// Copyright 2011 Google Inc.1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are5// met:6//7// * Redistributions of source code must retain the above copyright8// notice, this list of conditions and the following disclaimer.9// * Redistributions in binary form must reproduce the above copyright10// notice, this list of conditions and the following disclaimer in the11// documentation and/or other materials provided with the distribution.12// * Neither the name of Google Inc. nor the names of its contributors13// may be used to endorse or promote products derived from this software14// without specific prior written permission.15//16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2728#include <cassert>2930#include <lua.hpp>3132#include "exceptions.hpp"33#include "operations.hpp"34#include "stack_cleaner.hpp"35#include "state.hpp"363738/// Creates a module: i.e. a table with a set of methods in it.39///40/// \param s The Lua state.41/// \param name The name of the module to create.42/// \param members The list of member functions to add to the module.43void44lutok::create_module(state& s, const std::string& name,45const std::map< std::string, cxx_function >& members)46{47stack_cleaner cleaner(s);48s.new_table();49for (std::map< std::string, cxx_function >::const_iterator50iter = members.begin(); iter != members.end(); iter++) {51s.push_string((*iter).first);52s.push_cxx_function((*iter).second);53s.set_table(-3);54}55s.set_global(name);56}575859/// Loads and processes a Lua file.60///61/// This is a replacement for luaL_dofile but with proper error reporting62/// and stack control.63///64/// \param s The Lua state.65/// \param file The file to load.66/// \param nargs The number of arguments on the stack to pass to the file.67/// \param nresults The number of results to expect; -1 for any.68/// \param errfunc If not 0, index of a function in the stack to act as an69/// error handler.70///71/// \return The number of results left on the stack.72///73/// \throw error If there is a problem processing the file.74unsigned int75lutok::do_file(state& s, const std::string& file, const int nargs,76const int nresults, const int errfunc)77{78assert(nresults >= -1);79const int height = s.get_top() - nargs;8081try {82s.load_file(file);83if (nargs > 0)84s.insert(-nargs - 1);85s.pcall(nargs, nresults == -1 ? LUA_MULTRET : nresults,86errfunc == 0 ? 0 : errfunc - 1);87} catch (const lutok::api_error& e) {88throw lutok::error("Failed to load Lua file '" + file + "': " +89e.what());90}9192const int actual_results = s.get_top() - height;93assert(nresults == -1 || actual_results == nresults);94assert(actual_results >= 0);95return static_cast< unsigned int >(actual_results);96}979899/// Processes a Lua script.100///101/// This is a replacement for luaL_dostring but with proper error reporting102/// and stack control.103///104/// \param s The Lua state.105/// \param str The string to process.106/// \param nargs The number of arguments on the stack to pass to the chunk.107/// \param nresults The number of results to expect; -1 for any.108/// \param errfunc If not 0, index of a function in the stack to act as an109/// error handler.110///111/// \return The number of results left on the stack.112///113/// \throw error If there is a problem processing the string.114unsigned int115lutok::do_string(state& s, const std::string& str, const int nargs,116const int nresults, const int errfunc)117{118assert(nresults >= -1);119const int height = s.get_top() - nargs;120121try {122s.load_string(str);123if (nargs > 0)124s.insert(-nargs - 1);125s.pcall(nargs, nresults == -1 ? LUA_MULTRET : nresults,126errfunc == 0 ? 0 : errfunc - 1);127} catch (const lutok::api_error& e) {128throw lutok::error("Failed to process Lua string '" + str + "': " +129e.what());130}131132const int actual_results = s.get_top() - height;133assert(nresults == -1 || actual_results == nresults);134assert(actual_results >= 0);135return static_cast< unsigned int >(actual_results);136}137138139/// Convenience function to evaluate a Lua expression.140///141/// \param s The Lua state.142/// \param expression The textual expression to evaluate.143/// \param nresults The number of results to leave on the stack. Must be144/// positive.145///146/// \throw api_error If there is a problem evaluating the expression.147void148lutok::eval(state& s, const std::string& expression, const int nresults)149{150assert(nresults > 0);151do_string(s, "return " + expression, 0, nresults, 0);152}153154155