Chi-Tech
chi_console_utilities.cc
Go to the documentation of this file.
2
3#include "chi_runtime.h"
4#include "chi_log.h"
5
6#include "chi_utils.h"
7
8#include "ChiObjectFactory.h"
9
11{
12int chiMakeObject(lua_State* L);
13}
14
15// #############################################################################
16// Execute file
17/** Executes the given file in the Lua engine.
18\author Jan*/
19int chi::Console::ExecuteFile(const std::string& fileName,
20 int argc,
21 char** argv) const
22{
23 lua_State* L = this->console_state_;
24 if (not fileName.empty())
25 {
26 if (argc > 0)
27 {
28 lua_newtable(L);
29 for (int i = 1; i <= argc; i++)
30 {
31 lua_pushnumber(L, i);
32 lua_pushstring(L, argv[i - 1]);
33 lua_settable(L, -3);
34 }
35 lua_setglobal(L, "chiArgs");
36 }
37 int error = luaL_dofile(this->console_state_, fileName.c_str());
38
39 if (error > 0)
40 {
42 << "LuaError: " << lua_tostring(this->console_state_, -1);
43 return EXIT_FAILURE;
44 }
45 }
46 return EXIT_SUCCESS;
47}
48
49// ###################################################################
50/**Pushes location id and number of processes to lua state.*/
51void chi::Console::PostMPIInfo(int location_id,
52 int number_of_processes) const
53{
54 lua_State* L = this->console_state_;
55
56 lua_pushinteger(L, location_id);
57 lua_setglobal(L, "chi_location_id");
58
59 lua_pushinteger(L, number_of_processes);
60 lua_setglobal(L, "chi_number_of_processes");
61}
62
63// ###################################################################
64/**Basic addition to registry. Used by the other public methods
65 * to registry a text-key to a lua function.*/
66void chi::Console::AddFunctionToRegistry(const std::string& name_in_lua,
67 lua_CFunction function_ptr)
68{
69 auto& console = GetInstance();
70
71 // Check if the function name is already there
72 if (console.lua_function_registry_.count(name_in_lua) > 0)
73 {
74 const auto& current_entry = console.lua_function_registry_.at(name_in_lua);
75
76 throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
77 ": Attempted "
78 "to register lua function \"" +
79 name_in_lua +
80 "\" but the function "
81 "is already taken by " +
82 current_entry.function_raw_name);
83 }
84
85 console.lua_function_registry_.insert(std::make_pair(
86 name_in_lua, LuaFunctionRegistryEntry{function_ptr, name_in_lua}));
87}
88
89// ###################################################################
90/**Adds a lua_CFunction to the registry. The registry of functions gets
91 * parsed into the lua console when `chi::Initialize` is called. This
92 * particular function will strip the namespace from the the parameter
93 * `raw_name_in_lua` and cause the function to be registered in the
94 * global namespace of the lua console.*/
96 const std::string& raw_name_in_lua, lua_CFunction function_ptr)
97{
98 // Filter out namespace from the raw name
99 const std::string name_in_lua =
100 chi::StringUpToFirstReverse(raw_name_in_lua, "::");
101
102 AddFunctionToRegistry(name_in_lua, function_ptr);
103
104 return 0;
105}
106
107// ###################################################################
108/**Adds a lua_CFunction to the registry. The registry of functions gets
109 * parsed into the lua console when `chi::Initialize` is called. The full
110 * path of the function will be derived from `namespace_name` + "::" +
111 * `function_name`.*/
113 lua_CFunction function_ptr,
114 const std::string& namespace_name,
115 const std::string& function_name)
116{
117 const std::string name_in_lua = namespace_name + "::" + function_name;
118
119 AddFunctionToRegistry(name_in_lua, function_ptr);
120
121 return 0;
122}
123
124// ###################################################################
125/**\brief Adds a constant to the lua state. Prepending the constant
126 * within a namespace is optional.*/
128 const std::string& namespace_name,
129 const std::string& constant_name,
130 const chi_data_types::Varying& value)
131{
132 const std::string name_in_lua = namespace_name + "::" + constant_name;
133
134 // Check if the constant name is already there
135 auto& console = Console::GetInstance();
136 if (console.lua_constants_registry_.count(name_in_lua) > 0)
137 {
138 throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
139 ": Attempted "
140 "to register lua const \"" +
141 name_in_lua +
142 "\" but the value "
143 "is already taken.");
144 }
145
146 console.lua_constants_registry_.insert(std::make_pair(name_in_lua, value));
147 return 0;
148}
149
150// ###################################################################
152{
153 return InputParameters();
154}
155
156// ###################################################################
157/**Wrapper functions operate with input and output parameters, essentially
158 * hiding the lua interface.*/
160 const std::string& namespace_name,
161 const std::string& name_in_lua,
162 WrapperGetInParamsFunc syntax_function,
163 WrapperCallFunc actual_function,
164 bool ignore_null_call_func /*=false*/)
165{
166 const std::string name = (namespace_name.empty())
167 ? name_in_lua
168 : namespace_name + "::" + name_in_lua;
169
170 auto& console = GetInstance();
171 auto& registry = console.function_wrapper_registry_;
172
174 registry.count(name) > 0,
175 std::string("Attempted to register lua-function wrapper \"") + name +
176 "\" but a wrapper with the same name already exists");
177
178 if (not syntax_function) syntax_function = DefaultGetInParamsFunc;
179
180 if (not ignore_null_call_func)
181 ChiLogicalErrorIf(not actual_function, "Problem with get_in_params_func");
182
183 LuaFuncWrapperRegEntry reg_entry;
184 reg_entry.get_in_params_func = syntax_function;
185 reg_entry.call_func = actual_function;
186
187 registry.insert(std::make_pair(name, reg_entry));
188
189 return 0;
190}
191
192// ###################################################################
193/**Sets/Forms a lua function in the state using a namespace structure.*/
195 const std::string& full_lua_name, lua_CFunction function_ptr)
196{
197 auto L = GetInstance().console_state_;
198 const auto lua_name_split = chi::StringSplit(full_lua_name, "::");
199
200 if (lua_name_split.size() == 1)
201 {
202 lua_pushcfunction(L, function_ptr);
203 lua_setglobal(L, lua_name_split.back().c_str());
204 return;
205 }
206
207 const std::vector<std::string> table_names(lua_name_split.begin(),
208 lua_name_split.end() - 1);
209
210 FleshOutLuaTableStructure(table_names);
211
212 lua_pushstring(L, lua_name_split.back().c_str());
213 lua_pushcfunction(L, function_ptr);
214 lua_settable(L, -3);
215
216 lua_pop(L, lua_gettop(L));
217}
218
219// ###################################################################
220/**Sets/Forms a table structure that mimics the namespace structure of
221 * a string. For example the string "sing::sob::nook::Tigger" will be
222 * assigned a table structure
223 * `sing.sob.nook.Tigger = "sing::sob::nook::Tigger"`. Then finally assigns
224 * lua call to this table.*/
226 const std::string& full_lua_name)
227{
228 auto L = GetInstance().console_state_;
229
230 /**Lambda for making a chunk*/
231 auto MakeChunk = [&L, &full_lua_name]()
232 {
233 std::string chunk_code = "local params = ...; ";
234 chunk_code +=
235 "return chi_console.LuaWrapperCall(\"" + full_lua_name + "\", ...)";
236
237 luaL_loadstring(L, chunk_code.c_str());
238 };
239
240 const auto table_names = chi::StringSplit(full_lua_name, "::");
241 std::vector<std::string> namespace_names;
242 for (const auto& table_name : table_names)
243 if (table_name != table_names.back()) namespace_names.push_back(table_name);
244
245 const auto& function_name = table_names.back();
246
247 if (not namespace_names.empty())
248 {
249 FleshOutLuaTableStructure(namespace_names);
250 lua_pushstring(L, function_name.c_str());
251 MakeChunk();
252 lua_settable(L, -3);
253 }
254 else
255 {
256 MakeChunk();
257 lua_setglobal(L, function_name.c_str());
258 }
259
260 lua_pop(L, lua_gettop(L));
261}
262
263// ###################################################################
264/**Sets/Forms a table structure that mimics the namespace structure of
265 * a string. For example the string "sing::sob::nook::Tigger" will be
266 * assigned a table structure
267 * `sing.sob.nook.Tigger = "sing::sob::nook::Tigger"`.*/
269 const std::string& full_lua_name)
270{
271 auto L = GetInstance().console_state_;
272
273 /**Lambda for registering object type and creation function.*/
274 auto RegisterObjectItems = [&L](const std::string& full_name)
275 {
276 lua_pushstring(L, "type");
277 lua_pushstring(L, full_name.c_str());
278 lua_settable(L, -3);
279
280 lua_pushstring(L, "Create");
281 std::string chunk_code = "local params = ...; ";
282 chunk_code += "return chiMakeObjectType(\"" + full_name + "\", ...)";
283
284 luaL_loadstring(L, chunk_code.c_str());
285 lua_settable(L, -3);
286 };
287
288 const auto table_names = chi::StringSplit(full_lua_name, "::");
289
290 FleshOutLuaTableStructure(table_names);
291
292 RegisterObjectItems(full_lua_name);
293
294 lua_pop(L, lua_gettop(L));
295}
296
297// ##################################################################
298/**Fleshes out a path in a table tree. For example, given
299 * "fee::foo::fah::koo, this routine will make sure that
300 * fee.foo.fah.koo is defined as a table tree structure. The routine will
301 * create a table structure where one is needed and leave existing ones alone.
302 *
303 * At the end of the routine the last table in the structure will be on top
304 * of the stack.*/
306 const std::vector<std::string>& table_names)
307{
308 auto L = GetInstance().console_state_;
309
310 for (const auto& table_name : table_names)
311 {
312 // The first entry needs to be in lua's global scope,
313 // so it looks a little different
314 if (table_name == table_names.front())
315 {
316 lua_getglobal(L, table_name.c_str());
317 if (not lua_istable(L, -1))
318 {
319 lua_pop(L, 1);
320 lua_newtable(L);
321 lua_setglobal(L, table_name.c_str());
322 lua_getglobal(L, table_name.c_str());
323 }
324 }
325 else
326 {
327 lua_getfield(L, -1, table_name.c_str());
328 if (not lua_istable(L, -1))
329 {
330 lua_pop(L, 1);
331 lua_pushstring(L, table_name.c_str());
332 lua_newtable(L);
333 lua_settable(L, -3);
334 lua_getfield(L, -1, table_name.c_str());
335 }
336 }
337 } // for table_key in table_keys
338}
339
340// ##################################################################
341/**Sets a lua constant in the lua state.*/
342void chi::Console::SetLuaConstant(const std::string& constant_name,
343 const chi_data_types::Varying& value)
344{
345 auto& console = GetInstance();
346 auto L = console.console_state_;
347 const auto path_names = chi::StringSplit(constant_name, "::");
348
349 auto PushVaryingValue = [&L](const chi_data_types::Varying& var_value)
350 {
351 if (var_value.Type() == chi_data_types::VaryingDataType::BOOL)
352 lua_pushboolean(L, var_value.BoolValue());
353 else if (var_value.Type() == chi_data_types::VaryingDataType::STRING)
354 lua_pushstring(L, var_value.StringValue().c_str());
355 else if (var_value.Type() == chi_data_types::VaryingDataType::INTEGER)
356 lua_pushinteger(L, static_cast<lua_Integer>(var_value.IntegerValue()));
357 else if (var_value.Type() == chi_data_types::VaryingDataType::FLOAT)
358 lua_pushnumber(L, var_value.FloatValue());
359 else
360 ChiInvalidArgument("Unsupported value type. Only bool, string, int and "
361 "double is supported");
362 };
363
364 if (path_names.size() == 1)
365 {
366 PushVaryingValue(value);
367 lua_setglobal(L, path_names.front().c_str());
368 }
369 else
370 {
371 std::vector<std::string> namespace_names;
372 for (const auto& table_name : path_names)
373 if (table_name != path_names.back())
374 {
375 namespace_names.push_back(table_name);
376 }
377
378 FleshOutLuaTableStructure(namespace_names);
379 lua_pushstring(L, path_names.back().c_str());
380 PushVaryingValue(value);
381 lua_settable(L, -3);
382 }
383
384 lua_pop(L, lua_gettop(L));
385}
386
387// ##################################################################
388/**Makes a formatted output, readible by the documentation scripts,
389 * of all the lua wrapper functions.*/
391{
392 Chi::log.Log() << "\n\n";
393 for (const auto& [key, entry] : function_wrapper_registry_)
394 {
395 if (Chi::log.GetVerbosity() == 0)
396 {
397 Chi::log.Log() << key;
398 continue;
399 }
400
401 Chi::log.Log() << "LUA_FUNCWRAPPER_BEGIN " << key;
402
403 if (not entry.call_func) Chi::log.Log() << "SYNTAX_BLOCK";
404
405 const auto in_params = entry.get_in_params_func();
406 in_params.DumpParameters();
407
408 Chi::log.Log() << "LUA_FUNCWRAPPER_END\n\n";
409 }
410 Chi::log.Log() << "\n\n";
411}
412
413// ##################################################################
414/**Given an old status, will update the bindings for only newly registered
415 * items.*/
417 const chi::RegistryStatuses& old_statuses)
418{
419 auto ListHasValue =
420 [](const std::vector<std::string>& list, const std::string& value)
421 { return std::find(list.begin(), list.end(), value) != list.end(); };
422
423 const auto& object_factory = ChiObjectFactory::GetInstance();
424 for (const auto& [key, _] : object_factory.Registry())
425 if (not ListHasValue(old_statuses.objfactory_keys_, key))
426 SetObjectNamespaceTableStructure(key);
427
428 for (const auto& [key, entry] : lua_function_registry_)
429 if (not ListHasValue(old_statuses.objfactory_keys_, key))
430 SetLuaFuncNamespaceTableStructure(key, entry.function_ptr);
431
432 for (const auto& [key, entry] : function_wrapper_registry_)
433 if (not ListHasValue(old_statuses.objfactory_keys_, key))
434 if (entry.call_func) SetLuaFuncWrapperNamespaceTableStructure(key);
435}
#define ChiLogicalErrorIf(condition, message)
#define ChiInvalidArgument(message)
static chi::ChiLog & log
Definition: chi_runtime.h:81
static ChiObjectFactory & GetInstance() noexcept
LogStream LogAllError()
Definition: chi_log.h:239
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
static void AddFunctionToRegistry(const std::string &name_in_lua, lua_CFunction function_ptr)
chi::ParameterBlock(*)(const chi::InputParameters &) WrapperCallFunc
Definition: chi_console.h:94
void UpdateConsoleBindings(const chi::RegistryStatuses &old_statuses)
static void SetLuaFuncWrapperNamespaceTableStructure(const std::string &full_lua_name)
Formats a namespace structure as a table, but the last entry is a function call.
int ExecuteFile(const std::string &fileName, int argc, char **argv) const
chi::InputParameters(*)() WrapperGetInParamsFunc
Definition: chi_console.h:93
static char AddLuaConstantToRegistry(const std::string &namespace_name, const std::string &constant_name, const chi_data_types::Varying &value)
Adds a constant to the lua state.
static char AddFunctionToRegistryInNamespaceWithName(lua_CFunction function_ptr, const std::string &namespace_name, const std::string &function_name)
Adds a lua_CFunction to the registry. With namespace-table analogy.
static void SetLuaConstant(const std::string &constant_name, const chi_data_types::Varying &value)
void PostMPIInfo(int location_id, int number_of_processes) const
static Console & GetInstance() noexcept
lua_State * console_state_
Pointer to lua console state.
Definition: chi_console.h:109
static void SetObjectNamespaceTableStructure(const std::string &full_lua_name)
Formats a namespace structure as a table, but the last entry contains a "Create" function and a type.
static InputParameters DefaultGetInParamsFunc()
A default function for returning empty input parameters.
void DumpRegister() const
Dumps the object registry to stdout.
static void FleshOutLuaTableStructure(const std::vector< std::string > &table_names)
Makes sure a table structure exists for the list of table names.
static char AddFunctionToRegistryGlobalNamespace(const std::string &raw_name_in_lua, lua_CFunction function_ptr)
Adds a lua_CFunction to the registry.
static char AddWrapperToRegistryInNamespaceWithName(const std::string &namespace_name, const std::string &name_in_lua, WrapperGetInParamsFunc syntax_function, WrapperCallFunc actual_function, bool ignore_null_call_func=false)
Adds a function wrapper to the lua registry.
static void SetLuaFuncNamespaceTableStructure(const std::string &full_lua_name, lua_CFunction function_ptr)
Formats a namespace structure as table.
int chiMakeObject(lua_State *L)
@ INTEGER
Datatype mapping to int64_t.
@ STRING
Datatype mapping to std::string.
@ BOOL
Datatype mapping to bool.
@ FLOAT
Datatype mapping to double.
std::string StringUpToFirstReverse(const std::string &input, const std::string &search_string)
std::vector< std::string > StringSplit(const std::string &input, const std::string &delim)
Definition: chi_console.h:103
WrapperGetInParamsFunc get_in_params_func
Definition: chi_console.h:104
WrapperCallFunc call_func
Definition: chi_console.h:105
Definition: chi_console.h:98
std::vector< std::string > objfactory_keys_
Definition: chi_runtime.h:63