diff --git a/luprex/core/Makefile b/luprex/core/Makefile index 87b2dd4a..b1f701f2 100644 --- a/luprex/core/Makefile +++ b/luprex/core/Makefile @@ -8,6 +8,7 @@ CPP_FILES=\ cpp/luastack.cpp\ cpp/traceback.cpp\ cpp/planemap.cpp\ + cpp/print.cpp\ cpp/luaconsole.cpp\ cpp/idalloc.cpp\ cpp/globaldb.cpp\ diff --git a/luprex/core/cpp/idalloc.hpp b/luprex/core/cpp/idalloc.hpp index eb449e50..456fe63f 100644 --- a/luprex/core/cpp/idalloc.hpp +++ b/luprex/core/cpp/idalloc.hpp @@ -191,7 +191,7 @@ private: IdGlobalPool *global_; int fifo_capacity_; std::deque ranges_; - friend int unittests_idalloc(lua_State *L); + friend int lfn_unittests_idalloc(lua_State *L); }; #endif // IDALLOC_HPP diff --git a/luprex/core/cpp/luastack.cpp b/luprex/core/cpp/luastack.cpp index 5bee3ce8..1ab1df49 100644 --- a/luprex/core/cpp/luastack.cpp +++ b/luprex/core/cpp/luastack.cpp @@ -323,13 +323,6 @@ int LuaStack::rawlen(LuaSlot obj) const { return lua_rawlen(L_, obj.index()); } -void LuaStack::check_nret(int xnret, int otop, int nret) const { - int ntop = lua_gettop(L_); - if ((nret != xnret)||(ntop != otop + xnret)) { - luaL_error(L_, "expected %d return values", xnret); - } -} - int LuaStack::gettabletype(LuaSlot tab) const { uint16_t bits = lua_getflagbits(L_, tab.index()); return LUA_TT_GENERAL + (bits & 0x000F); diff --git a/luprex/core/cpp/luastack.hpp b/luprex/core/cpp/luastack.hpp index dda9d91b..58da7010 100644 --- a/luprex/core/cpp/luastack.hpp +++ b/luprex/core/cpp/luastack.hpp @@ -319,38 +319,6 @@ private: void push_any_values() { } - // Call the CFunction, pushing and popping arguments appropriately. - template - void call_cfunction(int otop, LuaSlot s, T... args) { - call_cfunction(otop, args...); - pop_any_value(s); - } - template - void call_cfunction(int otop, lua_Integer &s, T... args) { - call_cfunction(otop, args...); - pop_any_value(s); - } - template - void call_cfunction(int otop, lua_Number &s, T... args) { - call_cfunction(otop, args...); - pop_any_value(s); - } - template - void call_cfunction(int otop, std::string &s, T... args) { - call_cfunction(otop, args...); - pop_any_value(s); - } - template - void call_cfunction(int otop, lua_CFunction fn, T... args) { - push_any_values(args...); - int nret = fn(L_); - check_nret(NRET, otop, nret); - } - - // Check number of return values: xpected number of return values, - // original stack top, and number of declared return values. - void check_nret(int xnret, int otop, int nret) const; - template static void delete_pointer(void *p) { delete (T*)p; } static void do_not_delete(void *p) { } @@ -477,14 +445,6 @@ public: lua_rawseti(L_, tab, key); } - // Call invokes any C function. It pushes the arguments on the stack, - // calls the cfunction, verifies that the number of return values is as - // expected, and pops the return values into LuaVars. - template - void call(T&... args) { - call_cfunction<0>(lua_gettop(L_), args...); - } - // Lua flagbits manipulation: Table types. int gettabletype(LuaSlot tab) const; void settabletype(LuaSlot tab, int t) const; @@ -521,9 +481,9 @@ public: #define LuaDefine(name, mode) \ - int name(lua_State *L); \ - LuaFunctionReg reg_##name(mode, #name, name); \ - int name(lua_State *L) + int lfn_##name(lua_State *L); \ + LuaFunctionReg reg_##name(mode, #name, lfn_##name); \ + int lfn_##name(lua_State *L) #define LuaStringify(x) #x diff --git a/luprex/core/cpp/planemap.hpp b/luprex/core/cpp/planemap.hpp index 069ea8f1..e361cbef 100644 --- a/luprex/core/cpp/planemap.hpp +++ b/luprex/core/cpp/planemap.hpp @@ -128,7 +128,7 @@ public: private: // unit testing stuff. - friend int unittests_planemap(lua_State *L); + friend int lfn_unittests_planemap(lua_State *L); EltVec get_cell(const std::string &plane, int64_t cell) const; int total_cells() const; void clear() { planes_.clear(); } diff --git a/luprex/core/cpp/print.cpp b/luprex/core/cpp/print.cpp new file mode 100644 index 00000000..c71f5173 --- /dev/null +++ b/luprex/core/cpp/print.cpp @@ -0,0 +1,32 @@ +#include "print.hpp" +#include "util.hpp" +#include +#include + +void luai_writestring(const char *s, size_t len) { + std::cout.write(s, len); +} + +void luai_writeline() { + std::cout << std::endl; + std::cout.flush(); +} + +LuaDefine(string_isidentifier, "c") { + LuaArg str; + LuaRet result; + LuaStack LS(L, str, result); + if (LS.isstring(str)) { + std::string s = LS.ckstring(str); + LS.set(result, util::is_identifier(s)); + } else { + LS.set(result, false); + } + return LS.result(); +} + + +void pprint(LuaStack &LS0, LuaSlot val, int indent, int maxlen, std::ostream *os) { + + +} diff --git a/luprex/core/cpp/print.hpp b/luprex/core/cpp/print.hpp new file mode 100644 index 00000000..a4a712a7 --- /dev/null +++ b/luprex/core/cpp/print.hpp @@ -0,0 +1,46 @@ +///////////////////////////////////////////////////////// +// +// Pretty-print routine. +// +// The pretty-printer can be called from C++ or Lua. +// +///////////////////////////////////////////////////////// + +#ifndef PRINT_HPP +#define PRINT_HPP + +#include "luastack.hpp" + +// This file provides these functions for lua. +// +// They direct all output to std::cout +// +extern "C" { +void luai_writestring(const char *s, size_t len); +void luai_writeline(); +} + +// Pretty print to a stream. +// +// If indent is >=0, the output is indented. If indent<0, then +// the output is emitted without newlines or indentation. +// +// Maxlen specifies the maximum number of characters output. If +// this is exceeded, then the printout is truncated. +// +void pprint(LuaStack &LS, LuaSlot val, int indent, int maxlen, std::ostream *os); + +// The following lua interfaces to this code are included: +// +// pprint(expr) +// +// - pretty print the specified expression to stdout. +// +// string.pprint(expr, indent, maxlen) +// +// - pretty print the specified expression, return the result as a string. +// +void pprint_pprint(lua_State *L); +void string_pprint(lua_State *L); + +#endif // PRINT_HPP \ No newline at end of file diff --git a/luprex/core/cpp/source.cpp b/luprex/core/cpp/source.cpp index 85978254..a4545a32 100644 --- a/luprex/core/cpp/source.cpp +++ b/luprex/core/cpp/source.cpp @@ -115,11 +115,10 @@ static void source_install_builtins(lua_State *L) { LS.setmetatable(nullstring, stringclass); } -static int source_updatefile(lua_State *L) { - LuaArg source, fn; - LuaRet info; +static void source_updatefile(LuaStack &LS0, LuaSlot source, LuaSlot fn, LuaSlot info) { + lua_State *L = LS0.state(); LuaVar fingerprint, null, loadresult; - LuaStack LS(L, source, fn, info, fingerprint, null, loadresult); + LuaStack LS(L, fingerprint, null, loadresult); // Get the existing info table from the source DB. if (LS.istable(source)) { @@ -158,7 +157,7 @@ static int source_updatefile(lua_State *L) { LS.rawset(info, "loadresult", loadresult); } } - return LS.result(); + LS.result(); } void SourceDB::update() { @@ -184,7 +183,7 @@ void SourceDB::update() { LS.set(fn, filenames[i]); // Call source_updatefile to get the updated info for one file. - LS.call(info, source_updatefile, sourcedb, fn); + source_updatefile(LS, sourcedb, fn, info); // Insert the sequence number and put finalized info into the new database. LS.set(seq, i + 1); @@ -209,7 +208,7 @@ static void source_clear_globals(lua_State *L) { LS.set(classname, LuaNil); while (LS.next(globtab, classname, classtab) != 0) { if (LS.istable(classtab)) { - LS.call(table_clear, classtab); + table_clear(LS, classtab); } else { LS.rawset(globtab, classname, LuaNil); } @@ -238,7 +237,7 @@ static void source_load_cfunctions(lua_State *L) { std::string mode = r->get_mode(); if (mode.find('c') != std::string::npos) { // Insert into class lua_pushlstring(L, classname.c_str(), classname.size()); - source_makeclass(L); + lfn_source_makeclass(L); lua_pushcfunction(L, func); lua_setfield(L, -2, funcname.c_str()); } diff --git a/luprex/core/cpp/source.hpp b/luprex/core/cpp/source.hpp index fcfb628e..23ba12e6 100644 --- a/luprex/core/cpp/source.hpp +++ b/luprex/core/cpp/source.hpp @@ -163,11 +163,11 @@ public: // If there's already a table with this name in the global environment, // leaves it there, and repairs the __class and __index fields. // -int source_makeclass(lua_State *L); +int lfn_source_makeclass(lua_State *L); // Return true if the specified table is a class created by 'makeclass' // -int source_isclass(lua_State *L); +int lfn_source_isclass(lua_State *L); #endif // SOURCE_HPP diff --git a/luprex/core/cpp/streambuffer.hpp b/luprex/core/cpp/streambuffer.hpp index 47899579..b564bdec 100644 --- a/luprex/core/cpp/streambuffer.hpp +++ b/luprex/core/cpp/streambuffer.hpp @@ -416,7 +416,7 @@ private: // This is for unit testing. bool layout_is(int64_t a, int64_t b, int64_t c); - friend int unittests_streambuffer(lua_State *L); + friend int lfn_unittests_streambuffer(lua_State *L); }; diff --git a/luprex/core/cpp/table.cpp b/luprex/core/cpp/table.cpp index 24453fdc..44091867 100644 --- a/luprex/core/cpp/table.cpp +++ b/luprex/core/cpp/table.cpp @@ -1,6 +1,50 @@ #include "table.hpp" #include "source.hpp" +void table_findtables_i(LuaStack &LS0, LuaSlot root, LuaSlot tabcount) { + lua_State *L = LS0.state(); + LuaVar key, val, tab, count; + LuaStack LS(L, key, val, tab, count); + + LS.newtable(tabcount); + int top = lua_gettop(L); + if (LS.istable(root)) { + lua_pushvalue(L, root.index()); + } + while (lua_gettop(L) > top) { + lua_checkstack(L, 10); + lua_replace(L, tab.index()); + LS.rawget(count, tabcount, tab); + if (LS.isnil(count)) { + LS.rawset(tabcount, tab, 1); + LS.set(key, LuaNil); + while (LS.next(tab, key, val)) { + if (LS.istable(key)) { + lua_pushvalue(L, key.index()); + } + if (LS.istable(val)) { + lua_pushvalue(L, val.index()); + } + } + LS.getmetatable(val, tab); + if (LS.istable(val)) { + lua_pushvalue(L, val.index()); + } + } else { + LS.rawset(tabcount, tab, LS.ckint(count) + 1); + } + } + LS.result(); +} + +LuaDefine(table_findtables, "c") { + LuaArg root; + LuaRet tabcount; + LuaStack LS(L, root, tabcount); + table_findtables_i(LS, root, tabcount); + return LS.result(); +} + LuaDefine(table_getregistry, "f") { LuaArg key; LuaRet result; @@ -9,10 +53,8 @@ LuaDefine(table_getregistry, "f") { return LS.result(); } -LuaDefine(table_equal, "c") { - LuaArg t1, t2; - LuaRet eql; - LuaStack LS(L, t1, t2, eql); +bool table_equal(LuaStack &LS, LuaSlot t1, LuaSlot t2) { + lua_State *L = LS.state(); LS.checktable(t1); LS.checktable(t2); lua_pushnil(L); @@ -21,8 +63,7 @@ LuaDefine(table_equal, "c") { lua_pushvalue(L, -2); // k v1 k lua_rawget(L, t2.index()); // k v1 v2 if (!lua_rawequal(L, -1, -2)) { - LS.set(eql, false); - return LS.result(); + return false; } lua_pop(L, 2); total1 += 1; @@ -33,7 +74,14 @@ LuaDefine(table_equal, "c") { lua_pop(L, 1); total2 += 1; } - LS.set(eql, total1 == total2); + return total1 == total2; +} + +LuaDefine(table_equal, "c") { + LuaArg t1, t2; + LuaRet eql; + LuaStack LS(L, t1, t2, eql); + LS.set(eql, table_equal(LS, t1, t2)); return LS.result(); } @@ -124,10 +172,14 @@ LuaDefine(table_count, "c") { return 1; } +void table_clear(LuaStack &LS0, LuaSlot table) { + LS0.cleartable(table); +} + LuaDefine(table_clear, "c") { LuaArg tab; LuaStack LS(L, tab); - LS.cleartable(tab); + table_clear(LS, tab); return LS.result(); } @@ -607,7 +659,7 @@ LuaDefine(table_sortedpairs, "c") { luaL_error(L, "Cannot iterate over a table with unsortable keys"); } lua_replace(L, rtab.index()); - LS.set(closure, table_nextsortedpair); + LS.set(closure, lfn_table_nextsortedpair); LS.set(key, LuaNil); return LS.result(); } diff --git a/luprex/core/cpp/table.hpp b/luprex/core/cpp/table.hpp index 52d1e557..f9a8f8eb 100644 --- a/luprex/core/cpp/table.hpp +++ b/luprex/core/cpp/table.hpp @@ -12,83 +12,91 @@ #include "luastack.hpp" +// Starting at the specified root, find tables recursively. +// +// Returns a table containing every table found, in tabcount. +// The value associated with the table is the number of times the +// table was found. +// +void table_findtables(LuaStack &LS0, LuaSlot root, LuaSlot tabcount); + +// table_clear +// +// Remove all key/value pairs from the table. Does not remove +// the metatable. +// +void table_clear(LuaStack &LS0, LuaSlot tab); + // table_equal // // True if two tables contain the same key/value pairs. // -int table_equal(lua_State *L); +bool table_equal(LuaStack &LS0, LuaSlot tab1, LuaSlot tab2); // table_findremove // // Given a vector and a value, remove the specified value from // the vector, and shift elements downward to fill the gaps. // -int table_findremove(lua_State *L); +int lfn_table_findremove(lua_State *L); // table_push // // Given a vector and a value, push the value onto the end. // -int table_push(lua_State *L); +int lfn_table_push(lua_State *L); // table_find // // Given a vector and a value, search for the first occurrence // of that value. Return the index. // -int table_find(lua_State *L); +int lfn_table_find(lua_State *L); // table_empty // // Return true if the table has no key/value pairs. // -int table_empty(lua_State *L); +int lfn_table_empty(lua_State *L); // table_count // // Return the number of key/value pairs in the table. // -int table_count(lua_State *L); - -// table_clear -// -// Remove all key/value pairs from the table. Does not -// remove the metatable. -// -int table_clear(lua_State *L); +int lfn_table_count(lua_State *L); // // Create and return an empty deque. Queues are implemented // as tables which are used as dynamically-expandable circular // buffers. // -int deque_create(lua_State *L); +int lfn_deque_create(lua_State *L); // // Given a deque and a value, pushes the value onto the // left or right end. // -int deque_pushl(lua_State *L); -int deque_pushr(lua_State *L); +int lfn_deque_pushl(lua_State *L); +int lfn_deque_pushr(lua_State *L); // // Given a deque, pop from the left or right end. Returns the // value and removes it from the deque. If the deque is // empty, returns nil. // -int deque_popl(lua_State *L); -int deque_popr(lua_State *L); +int lfn_deque_popl(lua_State *L); +int lfn_deque_popr(lua_State *L); // // Return the nth element from the left or right end of a deque. // -int deque_nthl(lua_State *L); -int deque_nthr(lua_State *L); +int lfn_deque_nthl(lua_State *L); +int lfn_deque_nthr(lua_State *L); // Set (overwrite) the nth element in a deque. // -int deque_setl(lua_State *L); -int deque_setr(lua_State *L); +int lfn_deque_setl(lua_State *L); +int lfn_deque_setr(lua_State *L); // // Search a deque for a value. @@ -96,13 +104,12 @@ int deque_setr(lua_State *L); // Search starts on the specified end and indices are relative // to specified end. // -int deque_findl(lua_State *L); -int deque_findr(lua_State *L); +int lfn_deque_findl(lua_State *L); +int lfn_deque_findr(lua_State *L); // // Return the number of values in the deque. // -int deque_size(lua_State *L); - +int lfn_deque_size(lua_State *L); #endif // TABLE_HPP diff --git a/luprex/core/cpp/util.cpp b/luprex/core/cpp/util.cpp index 6bf872c5..8c13803d 100644 --- a/luprex/core/cpp/util.cpp +++ b/luprex/core/cpp/util.cpp @@ -16,6 +16,25 @@ namespace util { +static bool ascii_isalpha(char c) { + return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); +} + +static bool ascii_isdigit(char c) { + return ((c >= '0') && (c <= '9')); +} + +bool is_identifier(const std::string &str) { + if (str.size() == 0) return false; + char c=str[0]; + if ((!ascii_isalpha(c)) && (c!='_')) return false; + for (int i = 1; i < int(str.size()); i++) { + char c = str[i]; + if ((!ascii_isalpha(c)) && (!ascii_isdigit(c)) && (c!='_')) return false; + } + return true; +} + IdVector id_vector_create(int64_t id1, int64_t id2, int64_t id3, int64_t id4) { IdVector result; if (id1 >= 0) result.push_back(id1); diff --git a/luprex/core/cpp/util.hpp b/luprex/core/cpp/util.hpp index 83b4ee80..9c20afd0 100644 --- a/luprex/core/cpp/util.hpp +++ b/luprex/core/cpp/util.hpp @@ -24,6 +24,9 @@ using StringVec = std::vector; using HashValue = std::pair; using IdVector = std::vector; +// Return true if the string is a valid lua identifier. +bool is_identifier(const std::string &str); + // ID vector quick create. IdVector id_vector_create(int64_t id1=-1, int64_t id2=-1, int64_t id3=-1, int64_t id4=-1); diff --git a/luprex/core/cpp/world-difftab.cpp b/luprex/core/cpp/world-difftab.cpp index ac8a2efa..762cf067 100644 --- a/luprex/core/cpp/world-difftab.cpp +++ b/luprex/core/cpp/world-difftab.cpp @@ -477,9 +477,9 @@ LuaDefine(table_diffapply, "c") { patch_table(MLS, tangibles, mntmap, mstab, &sb); - MLS.call(eql, table_equal, mstab, mtab); - bool e = MLS.ckboolean(eql); - if (e) { + bool eq = table_equal(MLS, mstab, mtab); + MLS.set(eql, eq); + if (eq) { MLS.set(eqlstr, "tables equal"); } else { MLS.set(eqlstr, "tables were supposed to be equal"); diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index 92b684a3..4f249017 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -396,9 +396,9 @@ private: Redirects redirects_; friend class Tangible; - friend int tangible_animate(lua_State *L); - friend int tangible_build(lua_State *L); - friend int tangible_redirect(lua_State *L); + friend int lfn_tangible_animate(lua_State *L); + friend int lfn_tangible_build(lua_State *L); + friend int lfn_tangible_redirect(lua_State *L); }; #endif // WORLD_HPP