1 /*
2    Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.com>
3    Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY.
11 
12    See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
17 #include <sstream>
18 #include <string>
19 #include <vector>
20 #include "utils/functional.hpp"
21 #include <cstdint>
22 
23 struct lua_State;
24 class config;
25 
26 class lua_kernel_base {
27 public:
28 	lua_kernel_base();
29 	virtual ~lua_kernel_base();
30 
31 	/** Runs a [lua] tag. Doesn't throw lua_error.*/
32 	void run_lua_tag(const config& cfg);
33 
34 	/** Runs a plain script. Doesn't throw lua_error.*/
35 	void run(char const *prog, int nArgs = 0);
36 
37 	/** Runs a plain script, but reports errors by throwing lua_error.*/
38 	void throwing_run(char const * prog, int nArgs);
39 
40 	/** Tests if a program resolves to an expression, and pretty prints it if it is, otherwise it runs it normally. Throws exceptions.*/
41 	void interactive_run(char const * prog);
42 
43 	/** Loads the `package` library into lua environment. Only in allow in `unsafe` modes. */
44 	void load_package();
45 	/** Loads the "core" library into the Lua environment. Without this, most Wesnoth Lua won't work.
46 	 * Cannot be called from the constructor because it needs to call virtual functions.
47 	 */
48 	void load_core();
49 
50 	/** Get tab completion strings */
51 	std::vector<std::string> get_global_var_names();
52 	std::vector<std::string> get_attribute_names(const std::string & var_path);
53 
54 	/** User-visible name of the lua kernel that they are talking to */
my_name()55 	virtual std::string my_name() { return "Basic Lua Kernel"; }
56 
57 	/** Access / manipulate logging of lua kernel activities */
get_log()58 	const std::stringstream & get_log() { cmd_log_.log_ << std::flush; return cmd_log_.log_; }
clear_log()59 	void clear_log() { cmd_log_.log_.str(""); cmd_log_.log_.clear(); }
60 
61 	using external_log_type = std::function<void(const std::string &)>;
set_external_log(external_log_type lg)62 	void set_external_log( external_log_type lg ) { cmd_log_.external_log_ = lg; }
63 
64 	/** Error reporting mechanisms, used by virtual methods protected_call and load_string*/
65 	virtual void log_error(char const* msg, char const* context = "Lua error");
66 	virtual void throw_exception(char const* msg, char const* context = "Lua error"); //throws game::lua_error
67 
68 	typedef std::function<void(char const*, char const*)> error_handler;
69 
70 	template<typename T>
get_lua_kernel(lua_State * L)71 	static T& get_lua_kernel(lua_State *L)
72 	{
73 		return *static_cast<T*>(get_lua_kernel_base_ptr(L));
74 	}
75 
76 	virtual uint32_t get_random_seed();
get_state()77 	lua_State * get_state() { return mState; }
add_widget_definition(const std::string & type,const std::string & id)78 	void add_widget_definition(const std::string& type, const std::string& id) { registered_widget_definitions_.emplace_back(type, id); }
79 protected:
80 	lua_State *mState;
81 
82 	/** Log implementation */
83 	struct command_log {
84 
85 		std::stringstream log_;
86 		external_log_type external_log_;
87 
command_loglua_kernel_base::command_log88 		command_log()
89 			: log_()
90 			, external_log_(nullptr)
91 		{}
92 
operator <<lua_kernel_base::command_log93 		inline command_log & operator<< (const std::string & str) {
94 			log_ << str;
95 			if (external_log_) {
96 				external_log_(str);
97 			}
98 			return *this;
99 		}
100 
operator <<lua_kernel_base::command_log101 		inline command_log & operator<< (char const* str) {
102 			if (str != nullptr) {
103 				log_ << str;
104 				if (external_log_) {
105 					external_log_(str);
106 				}
107 			}
108 			return *this;
109 		}
110 	};
111 
112 	command_log cmd_log_;
113 
114 	// Print text to the command log for this lua kernel. Used as a replacement impl for lua print.
115 	int intf_print(lua_State * L);
116 
117 	// Show the interactive lua console (for debugging purposes)
118 	int intf_show_lua_console(lua_State * L);
119 
120 	// Execute a protected call. Error handler is called in case of an error, using syntax for log_error and throw_exception above. Returns true if successful.
121 	bool protected_call(int nArgs, int nRets, error_handler);
122 	// Execute a protected call, taking a lua_State as argument. For functions pushed into the lua environment, this version should be used, or the function cannot be used by coroutines without segfaulting (since they have a different lua_State pointer). This version is called by the above version.
123 	static bool protected_call(lua_State * L, int nArgs, int nRets, error_handler);
124 	// Load a string onto the stack as a function. Returns true if successful, error handler is called if not.
125 	bool load_string(char const * prog, error_handler);
126 
127 	virtual bool protected_call(int nArgs, int nRets); 	// select default error handler polymorphically
128 	virtual bool load_string(char const * prog);		// select default error handler polymorphically
129 
130 	// dofile (using lua_fileops)
131 	int intf_dofile(lua_State * L);
132 
133 	// require (using lua_fileops, protected_call)
134 	int intf_require(lua_State * L);
135 
136 	int intf_kernel_type(lua_State* L);
137 
138 	virtual int impl_game_config_get(lua_State* L);
139 	virtual int impl_game_config_set(lua_State* L);
140 private:
141 	static lua_kernel_base*& get_lua_kernel_base_ptr(lua_State *L);
142 	std::vector<std::tuple<std::string, std::string>> registered_widget_definitions_;
143 };
144