14789f09brooks// Copyright 2011 Google Inc.
24789f09brooks// All rights reserved.
34789f09brooks//
44789f09brooks// Redistribution and use in source and binary forms, with or without
54789f09brooks// modification, are permitted provided that the following conditions are
64789f09brooks// met:
74789f09brooks//
84789f09brooks// * Redistributions of source code must retain the above copyright
94789f09brooks//   notice, this list of conditions and the following disclaimer.
104789f09brooks// * Redistributions in binary form must reproduce the above copyright
114789f09brooks//   notice, this list of conditions and the following disclaimer in the
124789f09brooks//   documentation and/or other materials provided with the distribution.
134789f09brooks// * Neither the name of Google Inc. nor the names of its contributors
144789f09brooks//   may be used to endorse or promote products derived from this software
154789f09brooks//   without specific prior written permission.
164789f09brooks//
174789f09brooks// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
184789f09brooks// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
194789f09brooks// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
204789f09brooks// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
214789f09brooks// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
224789f09brooks// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
234789f09brooks// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
244789f09brooks// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
254789f09brooks// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
264789f09brooks// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
274789f09brooks// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
284789f09brooks
294789f09brooks#include <cassert>
304789f09brooks
314789f09brooks#include <lua.hpp>
324789f09brooks
334789f09brooks#include "exceptions.hpp"
344789f09brooks#include "operations.hpp"
354789f09brooks#include "stack_cleaner.hpp"
364789f09brooks#include "state.hpp"
374789f09brooks
384789f09brooks
394789f09brooks/// Creates a module: i.e. a table with a set of methods in it.
404789f09brooks///
414789f09brooks/// \param s The Lua state.
424789f09brooks/// \param name The name of the module to create.
434789f09brooks/// \param members The list of member functions to add to the module.
444789f09brooksvoid
454789f09brookslutok::create_module(state& s, const std::string& name,
464789f09brooks                     const std::map< std::string, cxx_function >& members)
474789f09brooks{
484789f09brooks    stack_cleaner cleaner(s);
494789f09brooks    s.new_table();
504789f09brooks    for (std::map< std::string, cxx_function >::const_iterator
514789f09brooks         iter = members.begin(); iter != members.end(); iter++) {
524789f09brooks        s.push_string((*iter).first);
534789f09brooks        s.push_cxx_function((*iter).second);
544789f09brooks        s.set_table(-3);
554789f09brooks    }
564789f09brooks    s.set_global(name);
574789f09brooks}
584789f09brooks
594789f09brooks
604789f09brooks/// Loads and processes a Lua file.
614789f09brooks///
624789f09brooks/// This is a replacement for luaL_dofile but with proper error reporting
634789f09brooks/// and stack control.
644789f09brooks///
654789f09brooks/// \param s The Lua state.
664789f09brooks/// \param file The file to load.
674789f09brooks/// \param nargs The number of arguments on the stack to pass to the file.
684789f09brooks/// \param nresults The number of results to expect; -1 for any.
694789f09brooks/// \param errfunc If not 0, index of a function in the stack to act as an
704789f09brooks///     error handler.
714789f09brooks///
724789f09brooks/// \return The number of results left on the stack.
734789f09brooks///
744789f09brooks/// \throw error If there is a problem processing the file.
754789f09brooksunsigned int
764789f09brookslutok::do_file(state& s, const std::string& file, const int nargs,
774789f09brooks               const int nresults, const int errfunc)
784789f09brooks{
794789f09brooks    assert(nresults >= -1);
804789f09brooks    const int height = s.get_top() - nargs;
814789f09brooks
824789f09brooks    try {
834789f09brooks        s.load_file(file);
844789f09brooks        if (nargs > 0)
854789f09brooks            s.insert(-nargs - 1);
864789f09brooks        s.pcall(nargs, nresults == -1 ? LUA_MULTRET : nresults,
874789f09brooks                errfunc == 0 ? 0 : errfunc - 1);
884789f09brooks    } catch (const lutok::api_error& e) {
894789f09brooks        throw lutok::error("Failed to load Lua file '" + file + "': " +
904789f09brooks                           e.what());
914789f09brooks    }
924789f09brooks
934789f09brooks    const int actual_results = s.get_top() - height;
944789f09brooks    assert(nresults == -1 || actual_results == nresults);
954789f09brooks    assert(actual_results >= 0);
964789f09brooks    return static_cast< unsigned int >(actual_results);
974789f09brooks}
984789f09brooks
994789f09brooks
1004789f09brooks/// Processes a Lua script.
1014789f09brooks///
1024789f09brooks/// This is a replacement for luaL_dostring but with proper error reporting
1034789f09brooks/// and stack control.
1044789f09brooks///
1054789f09brooks/// \param s The Lua state.
1064789f09brooks/// \param str The string to process.
1074789f09brooks/// \param nargs The number of arguments on the stack to pass to the chunk.
1084789f09brooks/// \param nresults The number of results to expect; -1 for any.
1094789f09brooks/// \param errfunc If not 0, index of a function in the stack to act as an
1104789f09brooks///     error handler.
1114789f09brooks///
1124789f09brooks/// \return The number of results left on the stack.
1134789f09brooks///
1144789f09brooks/// \throw error If there is a problem processing the string.
1154789f09brooksunsigned int
1164789f09brookslutok::do_string(state& s, const std::string& str, const int nargs,
1174789f09brooks                 const int nresults, const int errfunc)
1184789f09brooks{
1194789f09brooks    assert(nresults >= -1);
1204789f09brooks    const int height = s.get_top() - nargs;
1214789f09brooks
1224789f09brooks    try {
1234789f09brooks        s.load_string(str);
1244789f09brooks        if (nargs > 0)
1254789f09brooks            s.insert(-nargs - 1);
1264789f09brooks        s.pcall(nargs, nresults == -1 ? LUA_MULTRET : nresults,
1274789f09brooks                errfunc == 0 ? 0 : errfunc - 1);
1284789f09brooks    } catch (const lutok::api_error& e) {
1294789f09brooks        throw lutok::error("Failed to process Lua string '" + str + "': " +
1304789f09brooks                           e.what());
1314789f09brooks    }
1324789f09brooks
1334789f09brooks    const int actual_results = s.get_top() - height;
1344789f09brooks    assert(nresults == -1 || actual_results == nresults);
1354789f09brooks    assert(actual_results >= 0);
1364789f09brooks    return static_cast< unsigned int >(actual_results);
1374789f09brooks}
1384789f09brooks
1394789f09brooks
1404789f09brooks/// Convenience function to evaluate a Lua expression.
1414789f09brooks///
1424789f09brooks/// \param s The Lua state.
1434789f09brooks/// \param expression The textual expression to evaluate.
1444789f09brooks/// \param nresults The number of results to leave on the stack.  Must be
1454789f09brooks///     positive.
1464789f09brooks///
1474789f09brooks/// \throw api_error If there is a problem evaluating the expression.
1484789f09brooksvoid
1494789f09brookslutok::eval(state& s, const std::string& expression, const int nresults)
1504789f09brooks{
1514789f09brooks    assert(nresults > 0);
1524789f09brooks    do_string(s, "return " + expression, 0, nresults, 0);
1534789f09brooks}
154