// Call load_string and protected call. Make them throw exceptions. // void lua_kernel_base::throwing_run(const char * prog, int nArgs) { cmd_log_ << "$ " << prog << "\n"; error_handler eh = std::bind(&lua_kernel_base::throw_exception, this, _1, _2 ); load_string(prog, eh); lua_insert(mState, -nArgs - 1); protected_call(nArgs, 0, eh); }
/** * Loads and executes a Lua file. * - Arg 1: string containing the file name. * - Ret *: values returned by executing the file body. */ int lua_kernel_base::intf_dofile(lua_State* L) { if (lua_fileops::load_file(L) != 1) return 0; //^ should end with the file contents loaded on the stack. actually it will call lua_error otherwise, the return 0 is redundant. error_handler eh = boost::bind(&lua_kernel_base::log_error, this, _1, _2 ); protected_call(0, LUA_MULTRET, eh); return lua_gettop(L); }
void lua_kernel_base::load_core() { lua_State* L = mState; lua_settop(L, 0); cmd_log_ << "Loading core...\n"; luaW_getglobal(L, "wesnoth", "require"); lua_pushstring(L, "lua/core.lua"); if(!protected_call(1, 1)) { cmd_log_ << "Error: Failed to load core.\n"; } lua_settop(L, 0); }
/** \brief Parse a sequence of commands. This method also perform error management. */ bool parser_imp::parse_commands() { bool done = false; while (!done) { protected_call([&]() { check_interrupted(); switch (curr()) { case scanner::token::CommandId: if (!parse_command()) done = true; break; case scanner::token::ScriptBlock: parse_script(); break; case scanner::token::Period: show_prompt(); next(); break; case scanner::token::Eof: done = true; break; default: throw parser_error("Command expected", pos()); } }, [&]() { sync_command(); }); } return !m_found_errors; }
// Tests if a program resolves to an expression, and pretty prints it if it is, otherwise it runs it normally. Throws exceptions. void lua_kernel_base::interactive_run(char const * prog) { std::string experiment = "ilua._pretty_print("; experiment += prog; experiment += ")"; error_handler eh = boost::bind(&lua_kernel_base::throw_exception, this, _1, _2 ); try { // Try to load the experiment without syntax errors load_string(experiment.c_str(), eh); } catch (game::lua_error &) { throwing_run(prog); // Since it failed, fall back to the usual throwing_run, on the original input. return; } // experiment succeeded, now run but log normally. cmd_log_ << "$ " << prog << "\n"; protected_call(0, 0, eh); }
parser_imp::parser_imp(environment const & env, io_state const & st, std::istream & in, char const * strm_name, script_state * S, bool use_exceptions, bool interactive): m_env(env), m_io_state(st), m_scanner(in, strm_name), m_strm_name(strm_name), m_elaborator(env), m_use_exceptions(use_exceptions), m_interactive(interactive), m_script_state(S), m_set_parser(m_script_state, this) { m_unary_nat = false; m_namespace_prefixes.push_back(name()); m_check_identifiers = true; updt_options(); m_found_errors = false; m_num_local_decls = 0; m_scanner.set_command_keywords(get_command_keywords()); if (m_script_state) { m_script_state->apply([&](lua_State * L) { m_expr_macros = &get_expr_macros(L); m_tactic_macros = &get_tactic_macros(L); m_cmd_macros = &get_cmd_macros(L); for (auto const & p : *m_cmd_macros) { m_scanner.add_command_keyword(p.first); } }); } else { m_expr_macros = nullptr; m_tactic_macros = nullptr; m_cmd_macros = nullptr; } // Initialize m_curr with some value. We need that because scan() // may fail, and m_curr will remain uninitialized. // In thi case, Valgrind would report unit var errors. m_curr = scanner::token::Id; protected_call([&]() { scan(); }, [&]() { sync_command(); }); }
/** * Loads and executes a Lua file, if there is no corresponding entry in wesnoth.package. * Stores the result of the script in wesnoth.package and returns it. * - Arg 1: string containing the file name. * - Ret 1: value returned by the script. */ int lua_kernel_base::intf_require(lua_State* L) { const char * m = luaL_checkstring(L, 1); if (!m) { luaL_argerror(L, 1, "found a null string argument to wesnoth require"); } // Check if there is already an entry. lua_getglobal(L, "wesnoth"); lua_pushstring(L, "package"); lua_rawget(L, -2); lua_pushvalue(L, 1); lua_rawget(L, -2); if (!lua_isnil(L, -1) && !game_config::debug_lua) return 1; lua_pop(L, 1); lua_pushvalue(L, 1); // stack is now [packagename] [wesnoth] [package] [packagename] if (lua_fileops::load_file(L) != 1) return 0; //^ should end with the file contents loaded on the stack. actually it will call lua_error otherwise, the return 0 is redundant. // stack is now [packagename] [wesnoth] [package] [chunk] DBG_LUA << "require: loaded a file, now calling it\n"; if (!protected_call(L, 0, 1, boost::bind(&lua_kernel_base::log_error, this, _1, _2))) return 0; //^ historically if wesnoth.require fails it just yields nil and some logging messages, not a lua error // stack is now [packagename] [wesnoth] [package] [results] lua_pushvalue(L, 1); lua_pushvalue(L, -2); // stack is now [packagename] [wesnoth] [package] [results] [packagename] [results] // Add the return value to the table. lua_settable(L, -4); // stack is now [packagename] [wesnoth] [package] [results] return 1; }
// Ctor, initialization lua_kernel_base::lua_kernel_base() : mState(luaL_newstate()) , cmd_log_() { get_lua_kernel_base_ptr(mState) = this; lua_State *L = mState; cmd_log_ << "Initializing " << my_name() << "...\n"; // Open safe libraries. // Debug and OS are not, but most of their functions will be disabled below. cmd_log_ << "Adding standard libs...\n"; static const luaL_Reg safe_libs[] { { "", luaopen_base }, { "table", luaopen_table }, { "string", luaopen_string }, { "math", luaopen_math }, { "coroutine", luaopen_coroutine }, { "debug", luaopen_debug }, { "os", luaopen_os }, { "utf8", luaopen_utf8 }, // added in Lua 5.3 { nullptr, nullptr } }; for (luaL_Reg const *lib = safe_libs; lib->func; ++lib) { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ } // Disable functions from os which we don't want. lua_getglobal(L, "os"); lua_pushnil(L); while(lua_next(L, -2) != 0) { lua_pop(L, 1); char const* function = lua_tostring(L, -1); if(strcmp(function, "clock") == 0 || strcmp(function, "date") == 0 || strcmp(function, "time") == 0 || strcmp(function, "difftime") == 0) continue; lua_pushnil(L); lua_setfield(L, -3, function); } lua_pop(L, 1); // Disable functions from debug which we don't want. lua_getglobal(L, "debug"); lua_pushnil(L); while(lua_next(L, -2) != 0) { lua_pop(L, 1); char const* function = lua_tostring(L, -1); if(strcmp(function, "traceback") == 0 || strcmp(function, "getinfo") == 0) continue; //traceback is needed for our error handler lua_pushnil(L); //getinfo is needed for ilua strict mode lua_setfield(L, -3, function); } lua_pop(L, 1); // Delete dofile and loadfile. lua_pushnil(L); lua_setglobal(L, "dofile"); lua_pushnil(L); lua_setglobal(L, "loadfile"); // Store the error handler. cmd_log_ << "Adding error handler...\n"; push_error_handler(L); // Create the gettext metatable. cmd_log_ << lua_common::register_gettext_metatable(L); // Create the tstring metatable. cmd_log_ << lua_common::register_tstring_metatable(L); lua_settop(L, 0); // Define the CPP_function metatable ( so we can override print to point to a C++ member function, add "show_dialog" for this kernel, etc. ) cmd_log_ << "Adding boost function proxy...\n"; lua_cpp::register_metatable(L); // Add some callback from the wesnoth lib cmd_log_ << "Registering basic wesnoth API...\n"; static luaL_Reg const callbacks[] { { "compare_versions", &intf_compare_versions }, { "debug", &intf_wml_tostring }, { "deprecated_message", &intf_deprecated_message }, { "have_file", &lua_fileops::intf_have_file }, { "read_file", &lua_fileops::intf_read_file }, { "textdomain", &lua_common::intf_textdomain }, { "tovconfig", &lua_common::intf_tovconfig }, { "get_dialog_value", &lua_gui2::intf_get_dialog_value }, { "set_dialog_tooltip", &lua_gui2::intf_set_dialog_tooltip }, { "set_dialog_active", &lua_gui2::intf_set_dialog_active }, { "set_dialog_visible", &lua_gui2::intf_set_dialog_visible }, { "add_dialog_tree_node", &lua_gui2::intf_add_dialog_tree_node }, { "add_widget_definition", &lua_gui2::intf_add_widget_definition }, { "set_dialog_callback", &lua_gui2::intf_set_dialog_callback }, { "set_dialog_canvas", &lua_gui2::intf_set_dialog_canvas }, { "set_dialog_focus", &lua_gui2::intf_set_dialog_focus }, { "set_dialog_markup", &lua_gui2::intf_set_dialog_markup }, { "set_dialog_value", &lua_gui2::intf_set_dialog_value }, { "remove_dialog_item", &lua_gui2::intf_remove_dialog_item }, { "dofile", &dispatch<&lua_kernel_base::intf_dofile> }, { "require", &dispatch<&lua_kernel_base::intf_require> }, { "kernel_type", &dispatch<&lua_kernel_base::intf_kernel_type> }, { "show_dialog", &lua_gui2::show_dialog }, { "show_menu", &lua_gui2::show_menu }, { "show_message_dialog", &lua_gui2::show_message_dialog }, { "show_popup_dialog", &lua_gui2::show_popup_dialog }, { "show_story", &lua_gui2::show_story }, { "show_message_box", &lua_gui2::show_message_box }, { "show_lua_console", &dispatch<&lua_kernel_base::intf_show_lua_console> }, { "compile_formula", &lua_formula_bridge::intf_compile_formula}, { "eval_formula", &lua_formula_bridge::intf_eval_formula}, { "name_generator", &intf_name_generator }, { "random", &intf_random }, { "wml_matches_filter", &intf_wml_matches_filter }, { "log", &intf_log }, { "get_image_size", &intf_get_image_size }, { "get_time_stamp", &intf_get_time_stamp }, { "format", &intf_format }, { "format_conjunct_list", &intf_format_list<true> }, { "format_disjunct_list", &intf_format_list<false> }, { "get_language", &intf_get_language }, { nullptr, nullptr } }; lua_getglobal(L, "wesnoth"); if (!lua_istable(L,-1)) { lua_newtable(L); } luaL_setfuncs(L, callbacks, 0); //lua_cpp::set_functions(L, cpp_callbacks, 0); lua_setglobal(L, "wesnoth"); static luaL_Reg const wml_callbacks[]= { { "load", &intf_load_wml}, { "parse", &intf_parse_wml}, { "clone", &intf_clone_wml}, { nullptr, nullptr }, }; lua_newtable(L); luaL_setfuncs(L, wml_callbacks, 0); lua_setglobal(L, "wml"); // Override the print function cmd_log_ << "Redirecting print function...\n"; lua_getglobal(L, "print"); lua_setglobal(L, "std_print"); //storing original impl as 'std_print' lua_settop(L, 0); //clear stack, just to be sure lua_pushcfunction(L, &dispatch<&lua_kernel_base::intf_print>); lua_setglobal(L, "print"); lua_pushcfunction(L, intf_load); lua_setglobal(L, "load"); lua_pushnil(L); lua_setglobal(L, "loadstring"); cmd_log_ << "Initializing package repository...\n"; // Create the package table. lua_getglobal(L, "wesnoth"); lua_newtable(L); lua_setfield(L, -2, "package"); lua_pop(L, 1); lua_settop(L, 0); lua_pushstring(L, "lua/package.lua"); int res = intf_require(L); if(res != 1) { cmd_log_ << "Error: Failed to initialize package repository. Falling back to less flexible C++ implementation.\n"; } // Get some callbacks for map locations cmd_log_ << "Adding map table...\n"; static luaL_Reg const map_callbacks[] { { "get_direction", &lua_map_location::intf_get_direction }, { "vector_sum", &lua_map_location::intf_vector_sum }, { "vector_diff", &lua_map_location::intf_vector_diff }, { "vector_negation", &lua_map_location::intf_vector_negation }, { "rotate_right_around_center", &lua_map_location::intf_rotate_right_around_center }, { "tiles_adjacent", &lua_map_location::intf_tiles_adjacent }, { "get_adjacent_tiles", &lua_map_location::intf_get_adjacent_tiles }, { "distance_between", &lua_map_location::intf_distance_between }, { "get_in_basis_N_NE", &lua_map_location::intf_get_in_basis_N_NE }, { "get_relative_dir", &lua_map_location::intf_get_relative_dir }, { nullptr, nullptr } }; // Create the map_location table. lua_getglobal(L, "wesnoth"); lua_newtable(L); luaL_setfuncs(L, map_callbacks, 0); lua_setfield(L, -2, "map"); lua_pop(L, 1); // Create the game_config variable with its metatable. cmd_log_ << "Adding game_config table...\n"; lua_getglobal(L, "wesnoth"); lua_newuserdata(L, 0); lua_createtable(L, 0, 3); lua_pushcfunction(L, &dispatch<&lua_kernel_base::impl_game_config_get>); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, &dispatch<&lua_kernel_base::impl_game_config_set>); lua_setfield(L, -2, "__newindex"); lua_pushstring(L, "game config"); lua_setfield(L, -2, "__metatable"); lua_setmetatable(L, -2); lua_setfield(L, -2, "game_config"); lua_pop(L, 1); // Add mersenne twister rng wrapper cmd_log_ << "Adding rng tables...\n"; lua_rng::load_tables(L); cmd_log_ << "Adding name generator metatable...\n"; luaL_newmetatable(L, Gen); static luaL_Reg const generator[] { { "__call", &impl_name_generator_call}, { "__gc", &impl_name_generator_collect}, { nullptr, nullptr} }; luaL_setfuncs(L, generator, 0); // Create formula bridge metatables cmd_log_ << lua_formula_bridge::register_metatables(L); // Loading ilua: cmd_log_ << "Loading ilua...\n"; lua_settop(L, 0); luaW_getglobal(L, "wesnoth", "require"); lua_pushstring(L, "lua/ilua.lua"); if(protected_call(1, 1)) { //run "ilua.set_strict()" lua_pushstring(L, "set_strict"); lua_gettable(L, -2); if (!this->protected_call(0,0, std::bind(&lua_kernel_base::log_error, this, _1, _2))) { cmd_log_ << "Failed to activate strict mode.\n"; } else { cmd_log_ << "Activated strict mode.\n"; } lua_setglobal(L, "ilua"); //save ilua table as a global } else { cmd_log_ << "Error: failed to load ilua.\n"; } lua_settop(L, 0); }
void mapgen_lua_kernel::run_generator(const char * prog, const config & generator) { load_string(prog, boost::bind(&lua_kernel_base::throw_exception, this, _1, _2)); luaW_pushconfig(mState, generator); protected_call(1, 1, boost::bind(&lua_kernel_base::throw_exception, this, _1, _2)); }
// Call load_string and protected call. Make them throw exceptions. // void lua_kernel_base::throwing_run(const char * prog) { cmd_log_ << "$ " << prog << "\n"; error_handler eh = boost::bind(&lua_kernel_base::throw_exception, this, _1, _2 ); load_string(prog, eh); protected_call(0, 0, eh); }
bool lua_kernel_base::protected_call(int nArgs, int nRets, error_handler e_h) { return protected_call(mState, nArgs, nRets, e_h); }
bool lua_kernel_base::protected_call(int nArgs, int nRets) { error_handler eh = boost::bind(&lua_kernel_base::log_error, this, _1, _2 ); return protected_call(nArgs, nRets, eh); }
lua_kernel_base::lua_kernel_base(CVideo * video) : mState(luaL_newstate()) , video_(video) , cmd_log_() { lua_State *L = mState; cmd_log_ << "Initializing " << my_name() << "...\n"; // Open safe libraries. // Debug and OS are not, but most of their functions will be disabled below. cmd_log_ << "Adding standard libs...\n"; static const luaL_Reg safe_libs[] = { { "", luaopen_base }, { "table", luaopen_table }, { "string", luaopen_string }, { "math", luaopen_math }, { "coroutine", luaopen_coroutine }, { "debug", luaopen_debug }, { "os", luaopen_os }, { NULL, NULL } }; for (luaL_Reg const *lib = safe_libs; lib->func; ++lib) { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ } // Disable functions from os which we don't want. lua_getglobal(L, "os"); lua_pushnil(L); while(lua_next(L, -2) != 0) { lua_pop(L, 1); char const* function = lua_tostring(L, -1); if(strcmp(function, "clock") == 0 || strcmp(function, "date") == 0 || strcmp(function, "time") == 0 || strcmp(function, "difftime") == 0) continue; lua_pushnil(L); lua_setfield(L, -3, function); } lua_pop(L, 1); // Disable functions from debug which we don't want. lua_getglobal(L, "debug"); lua_pushnil(L); while(lua_next(L, -2) != 0) { lua_pop(L, 1); char const* function = lua_tostring(L, -1); if(strcmp(function, "traceback") == 0 || strcmp(function, "getinfo") == 0) continue; //traceback is needed for our error handler lua_pushnil(L); //getinfo is needed for ilua strict mode lua_setfield(L, -3, function); } lua_pop(L, 1); // Delete dofile and loadfile. lua_pushnil(L); lua_setglobal(L, "dofile"); lua_pushnil(L); lua_setglobal(L, "loadfile"); // Store the error handler. cmd_log_ << "Adding error handler...\n"; lua_pushlightuserdata(L , executeKey); lua_getglobal(L, "debug"); lua_getfield(L, -1, "traceback"); lua_remove(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); lua_pop(L, 1); // Create the gettext metatable. cmd_log_ << lua_common::register_gettext_metatable(L); // Create the tstring metatable. cmd_log_ << lua_common::register_tstring_metatable(L); lua_settop(L, 0); // Define the CPP_function metatable ( so we can override print to point to a C++ member function, add "show_dialog" for this kernel, etc. ) cmd_log_ << "Adding boost function proxy...\n"; lua_cpp::register_metatable(L); // Add some callback from the wesnoth lib cmd_log_ << "Registering basic wesnoth API...\n"; static luaL_Reg const callbacks[] = { { "compare_versions", &intf_compare_versions }, { "have_file", &lua_fileops::intf_have_file }, { "textdomain", &lua_common::intf_textdomain }, { "tovconfig", &lua_common::intf_tovconfig }, { "get_dialog_value", &lua_gui2::intf_get_dialog_value }, { "set_dialog_active", &lua_gui2::intf_set_dialog_active }, { "set_dialog_callback", &lua_gui2::intf_set_dialog_callback }, { "set_dialog_canvas", &lua_gui2::intf_set_dialog_canvas }, { "set_dialog_markup", &lua_gui2::intf_set_dialog_markup }, { "set_dialog_value", &lua_gui2::intf_set_dialog_value }, { NULL, NULL } }; lua_cpp::Reg const cpp_callbacks[] = { { "dofile", boost::bind(&lua_kernel_base::intf_dofile, this, _1)}, { "require", boost::bind(&lua_kernel_base::intf_require, this, _1)}, { "show_dialog", boost::bind(&lua_kernel_base::intf_show_dialog, this, _1)}, { "show_lua_console", boost::bind(&lua_kernel_base::intf_show_lua_console, this, _1)}, { NULL, NULL } }; lua_getglobal(L, "wesnoth"); if (!lua_istable(L,-1)) { lua_newtable(L); } luaL_setfuncs(L, callbacks, 0); lua_cpp::set_functions(L, cpp_callbacks, 0); lua_setglobal(L, "wesnoth"); // Override the print function cmd_log_ << "Redirecting print function...\n"; lua_getglobal(L, "print"); lua_setglobal(L, "std_print"); //storing original impl as 'std_print' lua_settop(L, 0); //clear stack, just to be sure lua_cpp::lua_function my_print = boost::bind(&lua_kernel_base::intf_print, this, _1); lua_cpp::push_closure(L, my_print, 0); lua_setglobal(L, "print"); // Create the package table. lua_getglobal(L, "wesnoth"); lua_newtable(L); lua_setfield(L, -2, "package"); lua_pop(L, 1); // Get some callbacks for map locations cmd_log_ << "Adding map_location table...\n"; static luaL_Reg const map_callbacks[] = { { "get_direction", &lua_map_location::intf_get_direction }, { "vector_sum", &lua_map_location::intf_vector_sum }, { "vector_negation", &lua_map_location::intf_vector_negation }, { "zero", &lua_map_location::intf_vector_zero }, { "rotate_right_around_center", &lua_map_location::intf_rotate_right_around_center }, { "tiles_adjacent", &lua_map_location::intf_tiles_adjacent }, { "get_adjacent_tiles", &lua_map_location::intf_get_adjacent_tiles }, { "distance_between", &lua_map_location::intf_distance_between }, { "get_in_basis_N_NE", &lua_map_location::intf_get_in_basis_N_NE }, { "get_relative_dir", &lua_map_location::intf_get_relative_dir }, { "parse_direction", &lua_map_location::intf_parse_direction }, { "write_direction", &lua_map_location::intf_write_direction }, { NULL, NULL } }; // Create the map_location table. lua_getglobal(L, "wesnoth"); lua_newtable(L); luaL_setfuncs(L, map_callbacks, 0); lua_setfield(L, -2, "map_location"); lua_pop(L,1); // Add mersenne twister rng wrapper cmd_log_ << "Adding rng tables...\n"; lua_rng::load_tables(L); // Loading ilua: cmd_log_ << "Loading ilua...\n"; lua_pushstring(L, "lua/ilua.lua"); int result = intf_require(L); if (result == 1) { //run "ilua.set_strict()" lua_pushstring(L, "set_strict"); lua_gettable(L, -2); if (!protected_call(0,0, boost::bind(&lua_kernel_base::log_error, this, _1, _2))) { cmd_log_ << "Failed to activate strict mode.\n"; } else { cmd_log_ << "Activated strict mode.\n"; } lua_setglobal(L, "ilua"); //save ilua table as a global } else { cmd_log_ << "Error: failed to load ilua.\n"; } lua_settop(L, 0); }