Initial revision of lua 'doc' function

This commit is contained in:
2021-12-15 23:03:43 -05:00
parent e0001127c7
commit 1cfdb4fa09
22 changed files with 301 additions and 199 deletions

View File

@@ -576,7 +576,7 @@ static bool diff_works(const AnimQueue &master, AnimQueue &sync) {
return sync.size_and_steps_equal(master);
}
LuaDefine(unittests_animqueue, "c") {
LuaDefine(unittests_animqueue, "", "some unit tests") {
// Useful objects.
AnimStep stp;
AnimQueue aq(util::WORLD_TYPE_MASTER);

View File

@@ -2,14 +2,7 @@
#include "globaldb.hpp"
// Get a table from the global database.
//
// GLOBALNAME
// if globalname is already present, and is a table, return it.
// if globalname is already present, and not a table, error.
// if globalname is not present, create and initialize it.
//
LuaDefine(globaldb_global, "f") {
LuaDefine(global, "globalname", "get a table where global data can be stored") {
LuaArg globalname;
LuaRet globaltab;
LuaVar globaldb;

View File

@@ -52,7 +52,7 @@ std::string Gui::menu_debug_string() const {
return oss.str();
}
LuaDefine(gui_menu_item, "c") {
LuaDefine(gui_menu_item, "action,label", "add a menu item to the current gui") {
Gui *gui = Gui::fetch_global_pointer(L);
LuaArg laction, llabel;
LuaStack LS(L, laction, llabel);

View File

@@ -250,7 +250,7 @@ static int64_t nthbatch(int64_t n) {
return int64_t(0x0001000000000000) + n*256;
}
LuaDefine(unittests_idalloc, "c") {
LuaDefine(unittests_idalloc, "", "some unit tests") {
IdGlobalPool gp;
IdPlayerPool pp(&gp);
IdGlobalPool gpds;

View File

@@ -6,9 +6,10 @@ LuaSpecial LuaRegistry(LUA_REGISTRYINDEX);
LuaNilMarker LuaNil;
LuaNewTableMarker LuaNewTable;
LuaFunctionReg::LuaFunctionReg(const char *m, const char *n, lua_CFunction f) {
mode_ = m;
LuaFunctionReg::LuaFunctionReg(const char *n, const char *a, const char *d, lua_CFunction f) {
name_ = n;
args_ = a;
docs_ = d;
func_ = f;
next_ = LuaFunctionRegistry;
LuaFunctionRegistry = this;
@@ -22,6 +23,15 @@ LuaFunctionReg::List LuaFunctionReg::all() {
return result;
}
const LuaFunctionReg *LuaFunctionReg::lookup(lua_CFunction fn) {
for (const LuaFunctionReg *r = LuaFunctionRegistry; r != 0; r = r->next_) {
if (r->func_ == fn) {
return r;
}
}
return nullptr;
}
LuaFunctionReg *LuaFunctionReg::LuaFunctionRegistry;
bool LuaStack::issortablekey(LuaSlot s) const {
@@ -350,6 +360,31 @@ int LuaStack::rawlen(LuaSlot obj) const {
return lua_rawlen(L_, obj.index());
}
std::string LuaStack::get_function_name(LuaSlot fn) {
LuaVar globals, key, val, skey, sval;
LuaStack LS(L_, globals, key, val, skey, sval);
LS.getglobaltable(globals);
LS.set(key, LuaNil);
while (LS.next(globals, key, val)) {
if (LS.isstring(key)) {
if (LS.rawequal(val, fn)) {
return LS.ckstring(key);
}
if (LS.istable(val)) {
LS.set(skey, LuaNil);
while (LS.next(val, skey, sval)) {
if (LS.isstring(skey) && LS.rawequal(sval, fn)) {
std::string n1 = LS.ckstring(key);
std::string n2 = LS.ckstring(skey);
return n1 + "." + n2;
}
}
}
}
}
return "";
}
int LuaStack::gettabletype(LuaSlot tab) const {
uint16_t bits = lua_getflagbits(L_, tab.index());
return LUA_TT_GENERAL + (bits & 0x000F);

View File

@@ -126,7 +126,7 @@
// exposed to lua. It creates a global registry of functions
// created with LuaDefine. You use it like so:
//
// LuaDefine(function_name, "modebits") {
// LuaDefine(function_name, "arguments", "documentation") {
// ...
// }
//
@@ -450,6 +450,9 @@ public:
lua_rawseti(L_, tab, key);
}
// Get function name
std::string get_function_name(LuaSlot ls);
// Lua flagbits manipulation: Table types.
int gettabletype(LuaSlot tab) const;
void settabletype(LuaSlot tab, int t) const;
@@ -466,8 +469,9 @@ public:
class LuaFunctionReg {
private:
const char *mode_;
const char *name_;
const char *args_;
const char *docs_;
lua_CFunction func_;
LuaFunctionReg *next_;
@@ -476,18 +480,20 @@ private:
public:
using List = std::vector<const LuaFunctionReg *>;
LuaFunctionReg(const char *mode, const char *n, lua_CFunction f);
LuaFunctionReg(const char *name, const char *args, const char *docs, lua_CFunction f);
static List all();
static const LuaFunctionReg *lookup(lua_CFunction fn);
const char *get_mode() const { return mode_; }
const char *get_name() const { return name_; }
const char *get_args() const { return args_; }
const char *get_docs() const { return docs_; }
lua_CFunction get_func() const { return func_; }
};
#define LuaDefine(name, mode) \
#define LuaDefine(name, args, docs) \
int lfn_##name(lua_State *L); \
LuaFunctionReg reg_##name(mode, #name, lfn_##name); \
LuaFunctionReg reg_##name(#name, args, docs, lfn_##name); \
int lfn_##name(lua_State *L)

View File

@@ -201,7 +201,7 @@ PlaneMap::IdVector PlaneMap::scan_radius(const std::string &plane, float x, floa
return result;
}
LuaDefine(unittests_planemap, "c") {
LuaDefine(unittests_planemap, "", "some unit tests") {
float SC = CELL_SCALE;
float E = CELL_SCALE * 0.4;
int LO = -CELL_LIMIT;

View File

@@ -5,14 +5,19 @@
#include <iostream>
void atomic_print(LuaStack &LS, LuaSlot val, std::ostream *os) {
switch (LS.type(val)) {
void atomic_print(LuaStack &LS, LuaSlot val, bool quote, std::ostream *os) {
int tt = LS.type(val);
switch (tt) {
case LUA_TNIL:
(*os) << "nil";
return;
case LUA_TSTRING:
// TODO: this could be more efficient.
(*os) << LS.ckstring(val);
if (quote) {
util::quote_string(LS.ckstring(val), os);
} else {
// TODO: this could be more efficient.
(*os) << LS.ckstring(val);
}
return;
case LUA_TNUMBER: {
double value = LS.cknumber(val);
@@ -27,38 +32,18 @@ void atomic_print(LuaStack &LS, LuaSlot val, std::ostream *os) {
case LUA_TBOOLEAN:
(*os) << (LS.ckboolean(val) ? "true" : "false");
return;
case LUA_TTABLE:
(*os) << "table";
return;
default:
(*os) << "unknown";
return;
}
}
static bool string_quote(LuaStack &LS, LuaSlot val, std::ostream *os) {
switch (LS.type(val)) {
case LUA_TNIL:
(*os) << "nil";
return true;
case LUA_TSTRING:
util::quote_string(LS.ckstring(val), os);
return true;
case LUA_TNUMBER: {
double value = LS.cknumber(val);
int64_t ivalue = int64_t(value);
if (double(ivalue) == value) {
(*os) << ivalue;
case LUA_TFUNCTION: {
std::string name = LS.get_function_name(val);
if (name.empty()) {
(*os) << "<fn>";
} else {
(*os) << value;
(*os) << "<fn." << name << ">";
}
return true;
return;
}
case LUA_TBOOLEAN:
(*os) << (LS.ckboolean(val) ? "true" : "false");
return true;
default:
return false;
(*os) << "<" << lua_typename(LS.state(), tt) << ">";
return;
}
}
@@ -105,7 +90,7 @@ static void findtables(LuaStack &LS0, LuaSlot root, LuaSlot tabcount) {
LS.result();
}
LuaDefine(table_findtables, "c") {
LuaDefine(table_findtables, "root", "recursively find tables (debugging only)") {
LuaArg root;
LuaRet tabcount;
LuaStack LS(L, root, tabcount);
@@ -140,16 +125,9 @@ static void pprint_r(Inspector &insp, int level, LuaSlot root) {
LuaVar idv, pairs, key, val;
LuaStack LS(insp.L, idv, pairs, key, val);
// If it's a simple type, print it quoted.
if (string_quote(LS, root, insp.stream)) {
LS.result();
return;
}
// If it's not a table, just print the typename.
int t = LS.type(root);
if (t != LUA_TTABLE) {
(*insp.stream) << "<" << lua_typename(insp.L, t) << ">";
// If it's anything but a table, use 'atomic_print'.
if (!LS.istable(root)) {
atomic_print(LS, root, true, insp.stream);
LS.result();
return;
}
@@ -272,7 +250,7 @@ void pprint(LuaStack &LS0, LuaSlot root, bool indent, std::ostream *os) {
LS.result();
}
LuaDefine(string_isidentifier, "c") {
LuaDefine(string_isidentifier, "str", "return true if the string is a valid lua identifier") {
LuaArg str;
LuaRet result;
LuaStack LS(L, str, result);
@@ -285,17 +263,17 @@ LuaDefine(string_isidentifier, "c") {
return LS.result();
}
LuaDefine(string_print, "c") {
LuaDefine(string_print, "obj", "print the specified object into a string") {
LuaArg val;
LuaRet result;
LuaStack LS(L, val, result);
std::ostringstream oss;
atomic_print(LS, val, &oss);
atomic_print(LS, val, false, &oss);
LS.set(result, oss.str());
return LS.result();
}
LuaDefine(string_pprint, "c") {
LuaDefine(string_pprint, "obj,indent", "pretty-print the specified object into a string") {
LuaArg root, indent;
LuaRet result;
LuaStack LS(L, root, indent, result);
@@ -306,12 +284,12 @@ LuaDefine(string_pprint, "c") {
return LS.result();
}
LuaDefine(string_tostring, "f") {
LuaDefine(tostring, "obj", "print the specified object into a string") {
LuaArg val;
LuaRet result;
LuaStack LS(L, val, result);
std::ostringstream oss;
atomic_print(LS, val, &oss);
atomic_print(LS, val, false, &oss);
LS.set(result, oss.str());
return LS.result();
}

View File

@@ -24,19 +24,13 @@
// Atomic print to a stream.
//
// This prints an atomic value to a stream. If you give it a table,
// it just prints "table". This routine is the heart of the lua
// it just prints "<table>". This routine is the heart of the lua
// primitives 'print' and 'tostring'.
//
void atomic_print(LuaStack &LS, LuaSlot val, std::ostream *os);
void atomic_print(LuaStack &LS, LuaSlot val, bool quote, std::ostream *os);
// 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, bool indent, std::ostream *os);
#endif // PPRINT_HPP

View File

@@ -189,7 +189,7 @@ Invocation PrintChanneler::invocation(int64_t actor_id) {
return Invocation(Invocation::KIND_FLUSH_PRINTS, actor_id, actor_id, std::to_string(line_), InvocationData());
}
LuaDefine(unittests_printbuffer, "c") {
LuaDefine(unittests_printbuffer, "", "some unit tests") {
PrintBuffer pbm;
PrintBuffer pbs;
StreamBuffer sb;

View File

@@ -64,7 +64,7 @@ void Schedule::deserialize(StreamBuffer *sb) {
}
}
LuaDefine(unittests_scheduler, "c") {
LuaDefine(unittests_scheduler, "", "some unit tests") {
Schedule s, xs;
StreamBuffer sb;

View File

@@ -15,7 +15,7 @@
#include "source.hpp"
#include "luasnap.hpp"
LuaDefine(source_makeclass, "f") {
LuaDefine(makeclass, "classname", "create a class if it doesn't already exist") {
LuaArg classname;
LuaRet classtab;
LuaStack LS(L, classname, classtab);
@@ -23,7 +23,7 @@ LuaDefine(source_makeclass, "f") {
return LS.result();
}
LuaDefine(source_classname, "f") {
LuaDefine(classname, "classtable", "get the class name from a class table") {
LuaArg table;
LuaRet result;
LuaStack LS(L, table, result);
@@ -36,7 +36,7 @@ LuaDefine(source_classname, "f") {
return LS.result();
}
LuaDefine(source_maketangible, "f") {
LuaDefine(maketangible, "classname", "create a class if it doesn't already exist, and add tangible features") {
LuaArg classname;
LuaRet classtab;
LuaVar subtab;
@@ -46,6 +46,18 @@ LuaDefine(source_maketangible, "f") {
return LS.result();
}
static void get_reg_name(const LuaFunctionReg *reg, std::string &classname, std::string &funcname) {
std::string name = reg->get_name();
size_t upos = name.find('_');
if (upos == std::string::npos) {
funcname = name;
classname = "";
} else {
funcname = name.substr(upos + 1);
classname = name.substr(0, upos);
}
}
// the 'luaopen' function creates a new table.
//
@@ -299,25 +311,16 @@ static void source_load_cfunctions(lua_State *L) {
LuaStack LS(L, classobj);
auto regs = LuaFunctionReg::all();
for (const LuaFunctionReg *r : regs) {
const std::string &name = r->get_name();
size_t upos = name.find('_');
lua_CFunction func = r->get_func();
std::string classname;
std::string funcname;
if (upos == std::string::npos) {
continue;
} else {
funcname = name.substr(upos + 1);
classname = name.substr(0, upos);
}
lua_CFunction func = r->get_func();
std::string mode = r->get_mode();
if (mode.find('c') != std::string::npos) { // Insert into class
LS.makeclass(classobj, classname);
LS.rawset(classobj, funcname, func);
}
if (mode.find('f') != std::string::npos) { // Make global function
get_reg_name(r, classname, funcname);
if (classname.empty()) {
LS.getglobaltable(classobj);
LS.rawset(classobj, funcname, func);
} else {
LS.makeclass(classobj, classname);
LS.rawset(classobj, funcname, func);
}
}
LS.result();
@@ -465,8 +468,80 @@ void SourceDB::deserialize_source(util::LuaSourceVec *sv, StreamBuffer *sb) {
}
}
std::string SourceDB::function_docs(const LuaStack &LS0, LuaSlot fn) {
lua_State *L = LS0.state();
LuaVar sourcedb, fname, finfo, code;
LuaStack LS(L, sourcedb, fname, finfo, code);
if (LS.iscfunction(fn)) {
lua_CFunction cfn = lua_tocfunction(L, fn.index());
const LuaFunctionReg *reg = LuaFunctionReg::lookup(cfn);
if (reg == nullptr) {
return "";
}
std::string classname;
std::string funcname;
get_reg_name(reg, classname, funcname);
std::ostringstream oss;
util::StringVec docs = util::split_lines(reg->get_docs());
for (const std::string &line : docs) {
oss << "-- " << line << std::endl;
}
oss << "function ";
if (!classname.empty()) {
oss << classname << ".";
}
oss << funcname << "(" << reg->get_args() << ")";
return oss.str();
} else if (LS.isfunction(fn)) {
lua_Debug ar;
lua_pushvalue(L, fn.index());
int status = lua_getinfo(L, ">S", &ar);
if (status == 0) return "";
// Get the source database.
LS.rawget(sourcedb, LuaRegistry, "sourcedb");
if (!LS.istable(sourcedb)) {
return "";
}
// Get the finfo table from the source db.
LS.set(fname, std::string(ar.short_src));
LS.rawget(finfo, sourcedb, fname);
if (!LS.istable(finfo)) {
return "";
}
// Get the code from the finfo table.
LS.rawget(code, finfo, "code");
if (!LS.isstring(code)) {
return "";
}
// Split the code into lines.
util::StringVec lines = util::split_lines(LS.ckstring(code));
int linehi = ar.linedefined - 1;
if ((linehi < 0) || (linehi >= int(lines.size()))) {
return "";
}
// Incorporate the function comment.
int linelo = linehi;
while ((linelo > 0) && (util::is_lua_comment(lines[linelo-1]))) linelo -= 1;
// Output the docs.
std::ostringstream result;
for (int i = linelo; i <= linehi; i++) {
result << lines[i] << std::endl;
}
return result.str();
} else {
return "";
}
}
// These should go away eventually. They're for debugging.
LuaDefine(coroutine_setnextid, "c") {
LuaDefine(coroutine_setnextid, "thread,id", "set the next id of a thread (debugging only)") {
LuaArg co, lid;
LuaStack LS(L, co, lid);
lua_State *CO = LS.ckthread(co);
@@ -475,7 +550,7 @@ LuaDefine(coroutine_setnextid, "c") {
return LS.result();
}
LuaDefine(coroutine_getnextid, "c") {
LuaDefine(coroutine_getnextid, "thread", "get the next id of a thread (debugging only)") {
LuaArg co;
LuaRet lid;
LuaStack LS(L, co, lid);
@@ -484,7 +559,7 @@ LuaDefine(coroutine_getnextid, "c") {
return LS.result();
}
LuaDefine(unittests_sourcedb, "c") {
LuaDefine(unittests_sourcedb, "", "some unit tests") {
LuaSnap msnap;
LuaSnap ssnap;
SourceDB mdb;

View File

@@ -173,6 +173,9 @@ public:
void set(const std::string &fn, const std::string &code, int sequence);
std::string get(const std::string &fn);
// Get function documentation.
static std::string function_docs(const LuaStack &LS, LuaSlot slot);
// Serialize and unserialize a source vector.
//
static void serialize_source(const util::LuaSourceVec &sv, StreamBuffer *sb);

View File

@@ -521,7 +521,7 @@ static void write_ztbytes(StreamBuffer *sb, const char *bytes) {
sb->write_bytes(bytes, strlen(bytes));
}
LuaDefine(unittests_streambuffer, "c") {
LuaDefine(unittests_streambuffer, "", "some unit tests") {
// An 11-byte fixed-size stream buffer.
StreamBuffer sb11(11, true);

View File

@@ -1,13 +1,6 @@
#include "table.hpp"
#include "source.hpp"
LuaDefine(table_getregistry, "f") {
LuaArg key;
LuaRet result;
LuaStack LS(L, key, result);
LS.rawget(result, LuaRegistry, key);
return LS.result();
}
bool table_equal(LuaStack &LS, LuaSlot t1, LuaSlot t2) {
lua_State *L = LS.state();
@@ -33,7 +26,7 @@ bool table_equal(LuaStack &LS, LuaSlot t1, LuaSlot t2) {
return total1 == total2;
}
LuaDefine(table_equal, "c") {
LuaDefine(table_equal, "table1,table2", "return true if two tables contain the same keys and values") {
LuaArg t1, t2;
LuaRet eql;
LuaStack LS(L, t1, t2, eql);
@@ -41,7 +34,7 @@ LuaDefine(table_equal, "c") {
return LS.result();
}
LuaDefine(table_findremove, "c") {
LuaDefine(table_findremove, "vector,value", "remove all occurrences of value from vector") {
luaL_checktype(L, -2, LUA_TTABLE);
int src = 1;
int dst = 1;
@@ -78,7 +71,7 @@ LuaDefine(table_findremove, "c") {
}
LuaDefine(table_push, "c") {
LuaDefine(table_push, "vector,value", "push a value onto the end of a vector") {
luaL_checktype(L, -2, LUA_TTABLE);
int len = lua_rawlen(L, -2);
lua_pushinteger(L, len+1);
@@ -88,7 +81,7 @@ LuaDefine(table_push, "c") {
return 0;
}
LuaDefine(table_find, "c") {
LuaDefine(table_find, "vector,value", "find the first occurrence of value in vector") {
luaL_checktype(L, -2, LUA_TTABLE);
for (int i = 1; ; i++) {
lua_pushinteger(L, i);
@@ -107,28 +100,21 @@ LuaDefine(table_find, "c") {
}
}
LuaDefine(table_empty, "c") {
LuaDefine(table_empty, "table", "return true if the table is empty") {
luaL_checktype(L, -1, LUA_TTABLE);
lua_pushnil(L);
if (lua_next(L, -2) != 0) {
lua_pop(L, 3);
lua_pushboolean(L, 0);
return 1;
} else {
lua_pop(L, 1);
lua_pushboolean(L, 1);
return 1;
}
int total = lua_nkeys(L, -1);
lua_pushboolean(L, (total == 0)?1:0);
return 1;
}
LuaDefine(table_count, "c") {
LuaDefine(table_count, "table", "return the number of keys in table") {
luaL_checktype(L, -1, LUA_TTABLE);
int total = lua_nkeys(L, -1);
lua_pushinteger(L, total);
return 1;
}
LuaDefine(table_clear, "c") {
LuaDefine(table_clear, "table,metaflag", "clear all keys, and optionally the metatable") {
LuaArg tab, clearmeta;
LuaVar metatable, metafield;
LuaStack LS(L, tab, clearmeta, metatable, metafield);
@@ -148,7 +134,7 @@ LuaDefine(table_clear, "c") {
return LS.result();
}
LuaDefine(table_getflagbits, "c") {
LuaDefine(table_getflagbits, "table", "get the table's flag bits (debugging only)") {
LuaArg tab;
LuaRet bits;
LuaStack LS(L, tab, bits);
@@ -157,7 +143,7 @@ LuaDefine(table_getflagbits, "c") {
return LS.result();
}
LuaDefine(table_setflagbits, "c") {
LuaDefine(table_setflagbits, "table,bits", "set the table's flag bits (debugging only)") {
LuaArg tab, bits;
LuaStack LS(L, tab, bits);
uint16_t ubits = LS.ckinteger(bits);
@@ -238,7 +224,7 @@ int deque_make_room(lua_State *L, int deque, int left, int fill, int max) {
return max;
}
LuaDefine(deque_create, "c") {
LuaDefine(deque_create, "", "create a deque") {
LuaRet rdeque;
LuaVar classobj;
LuaStack LS(L, rdeque, classobj);
@@ -255,7 +241,7 @@ LuaDefine(deque_create, "c") {
return LS.result();
}
LuaDefine(deque_pushl, "c") {
LuaDefine(deque_pushl, "deque,value", "push onto the left end of a deque") {
LuaArg deque, elt;
LuaStack LS(L, deque, elt);
int left, fill, max;
@@ -269,7 +255,7 @@ LuaDefine(deque_pushl, "c") {
return LS.result();
}
LuaDefine(deque_pushr, "c") {
LuaDefine(deque_pushr, "deque,value", "push onto the right end of a deque") {
LuaArg deque, elt;
LuaStack LS(L, deque, elt);
int left, fill, max;
@@ -282,7 +268,7 @@ LuaDefine(deque_pushr, "c") {
return LS.result();
}
LuaDefine(deque_popl, "c") {
LuaDefine(deque_popl, "deque", "pop the left end of a deque") {
LuaArg deque;
LuaRet result;
LuaStack LS(L, deque, result);
@@ -300,7 +286,7 @@ LuaDefine(deque_popl, "c") {
return LS.result();
}
LuaDefine(deque_popr, "c") {
LuaDefine(deque_popr, "deque", "pop the right end of a deque") {
LuaArg deque;
LuaRet result;
LuaStack LS(L, deque, result);
@@ -318,7 +304,7 @@ LuaDefine(deque_popr, "c") {
return LS.result();
}
LuaDefine(deque_nthl, "c") {
LuaDefine(deque_nthl, "deque,n", "return the nth item from the left end of a deque") {
LuaArg deque, nn;
LuaRet result;
LuaStack LS(L, deque, nn, result);
@@ -334,7 +320,7 @@ LuaDefine(deque_nthl, "c") {
return LS.result();
}
LuaDefine(deque_nthr, "c") {
LuaDefine(deque_nthr, "deque,n", "return the nth item from the right end of a deque") {
LuaArg deque, nn;
LuaRet result;
LuaStack LS(L, deque, nn, result);
@@ -350,7 +336,7 @@ LuaDefine(deque_nthr, "c") {
return LS.result();
}
LuaDefine(deque_setl, "c") {
LuaDefine(deque_setl, "deque,n,value", "set the nth item from the left end of a deque") {
LuaArg deque, nn, val;
LuaStack LS(L, deque, nn, val);
int left, fill, max;
@@ -365,7 +351,7 @@ LuaDefine(deque_setl, "c") {
return LS.result();
}
LuaDefine(deque_setr, "c") {
LuaDefine(deque_setr, "deque,n,value", "set the nth item from the right end of a deque") {
LuaArg deque, nn, val;
LuaStack LS(L, deque, nn, val);
int left, fill, max;
@@ -380,7 +366,7 @@ LuaDefine(deque_setr, "c") {
return LS.result();
}
LuaDefine(deque_findl, "c") {
LuaDefine(deque_findl, "deque,value", "find the first occurence of value in deque, starting from left") {
LuaArg deque, val;
LuaRet pos;
LuaVar check;
@@ -399,7 +385,7 @@ LuaDefine(deque_findl, "c") {
return LS.result();
}
LuaDefine(deque_findr, "c") {
LuaDefine(deque_findr, "deque,value", "find the first occurrence of value in deque, starting from right") {
LuaArg deque, val;
LuaRet pos;
LuaVar check;
@@ -419,7 +405,7 @@ LuaDefine(deque_findr, "c") {
return LS.result();
}
LuaDefine(deque_size, "c") {
LuaDefine(deque_size, "deque", "return the number of items in the deque") {
LuaArg deque;
LuaRet size;
LuaStack LS(L, deque, size);
@@ -576,7 +562,7 @@ bool table_getpairs(LuaStack &LS0, LuaSlot tab, LuaSlot pairs, bool sort) {
//
/////////////////////////////////////////////////////////////
LuaDefine(table_nextsortedpair, "c") {
LuaDefine(table_nextsortedpair, "sortedpairs,dummy", "next function used by sortedpairs") {
if (lua_gettop(L) < 2) {
luaL_error(L, "Not enough arguments to nextpair");
}
@@ -595,20 +581,20 @@ LuaDefine(table_nextsortedpair, "c") {
}
}
LuaDefine(table_sortedpairs, "c") {
LuaDefine(table_sortedpairs, "table", "iterate over table, sorting all keys") {
LuaArg tab;
LuaRet closure, rtab, key;
LuaStack LS(L, tab, closure, rtab, key);
bool sorted = table_getpairs(LS, tab, rtab, true);
if (!sorted) {
luaL_error(L, "Cannot iterate over a table with unsortable keys");
luaL_error(L, "Cannot sort the table keys");
}
LS.set(closure, lfn_table_nextsortedpair);
LS.set(key, LuaNil);
return LS.result();
}
LuaDefine(table_semisortedpairs, "c") {
LuaDefine(table_semisortedpairs, "table", "iterate over table, sorting those keys that can be sorted") {
LuaArg tab;
LuaRet closure, rtab, key;
LuaStack LS(L, tab, closure, rtab, key);
@@ -618,7 +604,7 @@ LuaDefine(table_semisortedpairs, "c") {
return LS.result();
}
LuaDefine(table_genlt, "f") {
LuaDefine(genlt, "obj1,obj2", "return true if obj1 is less than obj2 in general ordering") {
LuaArg o1,o2;
LuaRet lt;
LuaStack LS(L, o1, o2, lt);

View File

@@ -142,6 +142,28 @@ StringVec split(const std::string &s, char sep) {
return result;
}
static std::string substr_nocr(const std::string &s, int start, int len) {
if ((len > 0) && (s[start + len - 1] == '\r')) {
len -= 1;
}
return s.substr(start, len);
}
StringVec split_lines(const std::string &s) {
StringVec result;
int start = 0;
for (int i = 0; i < int(s.size()); i++) {
if (s[i]=='\n') {
result.push_back(substr_nocr(s, start, i-start));
start = i + 1;
}
}
if (start < int(s.size())) {
result.push_back(substr_nocr(s, start, s.size()-start));
}
return result;
}
std::string join(const StringVec &strs, const std::string &sep) {
if (strs.empty()) return "";
std::ostringstream oss;
@@ -271,6 +293,12 @@ LuaSourcePtr make_lua_source(const std::string &code) {
return result;
}
bool is_lua_comment(const std::string &s) {
int start = 0;
while ((start < int(s.size())) && ((s[start]==' ') || (s[start]=='\t'))) start++;
return s.substr(start, 2) == "--";
}
static std::string get_file_contents(const std::string &fn) {
std::ifstream fs(fn);
std::stringstream buffer;
@@ -329,7 +357,7 @@ std::ostream &operator<<(std::ostream &oss, const util::hex8 &v) {
return oss;
}
LuaDefine(unittests_util, "c") {
LuaDefine(unittests_util, "", "some unit tests") {
// Test the unioning of ID vectors.
util::IdVector idv1,idv2;
idv1.push_back(1);
@@ -358,6 +386,15 @@ LuaDefine(unittests_util, "c") {
LuaAssert(L, sv2[2]=="");
LuaAssert(L, sv2[3]=="bar");
// Test the split_lines routine.
util::StringVec sv3 = util::split_lines("foo\n\nbar\r\nbaz\r\n\r\n");
LuaAssert(L, sv3.size() == 5);
LuaAssert(L, sv3[0] == "foo");
LuaAssert(L, sv3[1] == "");
LuaAssert(L, sv3[2] == "bar");
LuaAssert(L, sv3[3] == "baz");
LuaAssert(L, sv3[4] == "");
// Test the repeat string routine.
LuaAssertStrEq(L, util::repeat_string("abc", 3), "abcabcabc");

View File

@@ -64,6 +64,9 @@ std::string hash_to_hex(const HashValue &hash);
// Split a string into multiple strings
StringVec split(const std::string &s, char sep);
// Split a string into multiple strings using \r or \n
StringVec split_lines(const std::string &s);
// Join multiple strings into one string
std::string join(const StringVec &strs, std::string sep);
@@ -108,6 +111,9 @@ bool world_type_authoritative(util::WorldType wt);
// Make a LuaSourceVec with one element, for unit testing.
LuaSourcePtr make_lua_source(const std::string &code);
// Return true if the line of code is a lua comment.
bool is_lua_comment(const std::string &line);
// Remove nullptrs from a vector of unique pointers.
template<class T>
void remove_nullptrs(std::vector<std::unique_ptr<T>> &vec) {

View File

@@ -17,7 +17,7 @@ static void tangible_getall(LuaStack &LS0, LuaSlot list, const util::IdVector &i
LS.result();
}
LuaDefine(tangible_animstate, "c") {
LuaDefine(tangible_animstate, "tan", "get the final animation state of the tangible") {
LuaArg tanobj;
LuaRet graphic, plane, x, y, z, facing;
LuaStack LS(L, tanobj, graphic, plane, x, y, z, facing);
@@ -33,7 +33,7 @@ LuaDefine(tangible_animstate, "c") {
return LS.result();
}
LuaDefine(tangible_animate, "c") {
LuaDefine(tangible_animate, "tan,configtable", "add an animation step to the tangible") {
LuaArg tanobj, config;
LuaStack LS(L, tanobj, config);
World *w = World::fetch_global_pointer(L);
@@ -50,7 +50,7 @@ LuaDefine(tangible_animate, "c") {
return LS.result();
}
LuaDefine(tangible_setclass, "c") {
LuaDefine(tangible_setclass, "tan,classname", "set the class of the tangible") {
LuaArg tanobj, classname;
LuaVar classtab, mt;
LuaStack LS(L, tanobj, classname, classtab, mt);
@@ -66,7 +66,7 @@ LuaDefine(tangible_setclass, "c") {
return LS.result();
}
LuaDefine(tangible_getclass, "c") {
LuaDefine(tangible_getclass, "tan", "get the class of the tangible, if any") {
LuaArg tanobj;
LuaVar mt, classtab;
LuaRet classname;
@@ -84,7 +84,7 @@ LuaDefine(tangible_getclass, "c") {
return LS.result();
}
LuaDefine(tangible_delete, "c") {
LuaDefine(tangible_delete, "tan", "delete the specified tangible") {
LuaArg tanobj;
LuaStack LS(L, tanobj);
World *w = World::fetch_global_pointer(L);
@@ -98,7 +98,7 @@ LuaDefine(tangible_delete, "c") {
return LS.result();
}
LuaDefine(tangible_build, "c") {
LuaDefine(tangible_build, "configtable", "build a new tangible object") {
LuaArg config;
LuaVar classname, classtab, mt;
LuaRet database;
@@ -148,7 +148,7 @@ LuaDefine(tangible_build, "c") {
return LS.result();
}
LuaDefine(tangible_get, "c") {
LuaDefine(tangible_get, "id", "get the tangible with the specified id (debugging only)") {
LuaArg id;
LuaVar tangibles;
LuaRet database;
@@ -162,7 +162,7 @@ LuaDefine(tangible_get, "c") {
return LS.result();
}
LuaDefine(tangible_redirect, "c") {
LuaDefine(tangible_redirect, "tan1,tan2,bulldozetan1", "redirect is not working yet") {
LuaArg actor1, actor2, bldz;
LuaStack LS(L, actor1, actor2, bldz);
World *w = World::fetch_global_pointer(L);
@@ -184,7 +184,7 @@ LuaDefine(tangible_redirect, "c") {
return LS.result();
}
LuaDefine(tangible_id, "c") {
LuaDefine(tangible_id, "tan", "return the tangible's id number (debugging only)") {
LuaArg tanobj;
LuaRet id;
LuaStack LS(L, tanobj, id);
@@ -196,7 +196,7 @@ LuaDefine(tangible_id, "c") {
return LS.result();
}
LuaDefine(tangible_actor, "c") {
LuaDefine(tangible_actor, "", "return the current actor") {
LuaRet actor;
LuaVar tangibles;
LuaStack LS(L, tangibles, actor);
@@ -206,7 +206,7 @@ LuaDefine(tangible_actor, "c") {
return LS.result();
}
LuaDefine(tangible_place, "c") {
LuaDefine(tangible_place, "", "return the current place") {
LuaRet place;
LuaVar tangibles;
LuaStack LS(L, tangibles, place);
@@ -216,7 +216,7 @@ LuaDefine(tangible_place, "c") {
return LS.result();
}
LuaDefine(tangible_near, "c") {
LuaDefine(tangible_near, "tan,radius,omit_nowhere,omit_self", "scan near the specified tangible") {
LuaArg ltan, lradius, lomit_nowhere, lomit_self;
LuaRet list;
LuaStack LS(L, ltan, lradius, lomit_nowhere, lomit_self, list);
@@ -231,7 +231,7 @@ LuaDefine(tangible_near, "c") {
return LS.result();
}
LuaDefine(tangible_scan, "c") {
LuaDefine(tangible_scan, "plane,x,y,radius,omit_nowhere", "scan the specified plane") {
LuaArg lplane, lx, ly, lradius, lomit_nowhere;
LuaRet list;
LuaStack LS(L, lplane, lx, ly, lradius, lomit_nowhere, list);
@@ -246,14 +246,14 @@ LuaDefine(tangible_scan, "c") {
return LS.result();
}
LuaDefine(world_wait, "f") {
LuaDefine(wait, "nticks", "wait the specified number of ticks") {
if ((lua_gettop(L) != 1) || (lua_type(L, -1) != LUA_TNUMBER)) {
luaL_error(L, "Argument to wait must be a number.");
}
return lua_yield(L, 1);
}
LuaDefine(tangible_nopredict, "c") {
LuaDefine(tangible_nopredict, "", "stop predictive execution of this thread") {
if (lua_gettop(L) != 0) {
luaL_error(L, "tangible.nopredict takes no arguments");
}
@@ -265,35 +265,7 @@ LuaDefine(tangible_nopredict, "c") {
}
}
LuaDefine(world_getregistry, "f") {
lua_pushvalue(L, LUA_REGISTRYINDEX);
return 1;
}
LuaDefine(world_xtype, "f") {
LuaArg tab;
LuaRet rtype;
LuaStack LS(L, tab, rtype);
int xt = LS.xtype(tab);
LS.set(rtype, xt);
return LS.result();
}
LuaDefine(world_settabletype, "f") {
LuaArg tab, ttype;
LuaStack LS(L, tab, ttype);
if (!LS.istable(tab)) {
luaL_error(L, "Not a table");
}
int tt = LS.ckinteger(ttype);
if ((tt < LUA_TT_GENERAL) || (tt > LUA_TT_CLASS)) {
luaL_error(L, "table type out of range");
}
LS.settabletype(tab, tt);
return LS.result();
}
LuaDefine(world_pprint, "f") {
LuaDefine(pprint, "obj1,obj2,...", "pretty-print all the objects") {
World *w = World::fetch_global_pointer(L);
std::ostream *ostream = w->lthread_print_stream();
LuaStack LS(L);
@@ -305,14 +277,27 @@ LuaDefine(world_pprint, "f") {
return LS.result();
}
LuaDefine(world_print, "f") {
LuaDefine(print, "obj1,obj2,...", "print all the objects") {
World *w = World::fetch_global_pointer(L);
std::ostream *ostream = w->lthread_print_stream();
LuaStack LS(L);
for (int i = 1; i <= lua_gettop(L); i++) {
LuaSpecial root(i);
atomic_print(LS, root, ostream);
atomic_print(LS, root, false, ostream);
(*ostream) << std::endl;
}
return LS.result();
}
LuaDefine(doc, "function", "print documentation for specified function") {
World *w = World::fetch_global_pointer(L);
std::ostream *ostream = w->lthread_print_stream();
LuaArg func;
LuaStack LS(L, func);
std::string doc = SourceDB::function_docs(LS, func);
if (doc == "") {
(*ostream) << "no doc found" << std::endl;
}
(*ostream) << doc;
return LS.result();
}

View File

@@ -711,6 +711,7 @@ void World::run_scheduled_threads() {
if (LS.ckboolean(print)) {
for (int i = 1; i <= lua_gettop(CO); i++) {
pprint(LSCO, LuaSpecial(i), true, ostream);
(*ostream) << std::endl;
}
}
LS.rawset(threads, sched.thread_id(), LuaNil);

View File

@@ -438,8 +438,8 @@ void World::diff_tangible_databases(const IdVector &basis, lua_State *master, St
MLS.result();
}
LuaDefine(table_diffcompare, "c") {
LuaArg mtnmap, mtab, mstnmap, mstab, stnmap, stab;
LuaDefine(table_diffcompare, "mtnmap,mtab,stnmap,stab", "for unit testing only") {
LuaArg mtnmap, mtab, mstnmap, mstab;
LuaRet dbgstring;
LuaVar tthread;
LuaStack MLS(L, mtnmap, mtab, mstnmap, mstab, dbgstring, tthread);
@@ -456,6 +456,7 @@ LuaDefine(table_diffcompare, "c") {
lua_pushvalue(L, mstnmap.index());
lua_pushvalue(L, mstab.index());
lua_xmove(L, synch, 2);
LuaArg stnmap,stab;
LuaStack SLS(synch, stnmap, stab);
// Call tablecmp_diff.
@@ -467,8 +468,8 @@ LuaDefine(table_diffcompare, "c") {
return MLS.result();
}
LuaDefine(table_diffapply, "c") {
LuaArg mtnmap, mtab, mstab, stnmap, stab;
LuaDefine(table_diffapply, "mtnmap,mtab,mstab", "for unit testing only") {
LuaArg mtnmap, mtab, mstab;
LuaRet eql, eqlstr, rtab;
LuaVar tthread, tangibles, mntmap, key, val;
LuaStack MLS(L, mtnmap, mtab, mstab, eql, eqlstr, rtab, tthread, tangibles, mntmap, key, val);
@@ -494,6 +495,7 @@ LuaDefine(table_diffapply, "c") {
lua_pushvalue(L, mtnmap.index());
lua_pushvalue(L, mstab.index());
lua_xmove(L, synch, 2);
LuaArg stnmap, stab;
LuaStack SLS(synch, stnmap, stab);
// Call diff_tables and patch_tables

View File

@@ -240,7 +240,7 @@ static bool worlds_identical(const UniqueWorld &w1, const UniqueWorld &w2) {
return sbw1.contents_equal(&sbw2);
}
LuaDefine(unittests_world1animdiff, "c") {
LuaDefine(unittests_world1animdiff, "", "some unit tests") {
UniqueWorld m(new World(util::WORLD_TYPE_MASTER));
UniqueWorld ss(new World(util::WORLD_TYPE_S_SYNC));
UniqueWorld cs(new World(util::WORLD_TYPE_C_SYNC));
@@ -310,7 +310,7 @@ LuaDefine(unittests_world1animdiff, "c") {
return 0;
}
LuaDefine(unittests_world2pairtab, "c") {
LuaDefine(unittests_world2pairtab, "", "some unit tests") {
UniqueWorld m(new World(util::WORLD_TYPE_MASTER));
UniqueWorld ss(new World(util::WORLD_TYPE_S_SYNC));
StreamBuffer sb;
@@ -358,7 +358,7 @@ LuaDefine(unittests_world2pairtab, "c") {
return 0;
}
LuaDefine(unittests_world3diffluatab, "c") {
LuaDefine(unittests_world3diffluatab, "", "some unit tests") {
UniqueWorld m(new World(util::WORLD_TYPE_MASTER));
UniqueWorld ss(new World(util::WORLD_TYPE_S_SYNC));
UniqueWorld cs(new World(util::WORLD_TYPE_C_SYNC));
@@ -412,7 +412,7 @@ LuaDefine(unittests_world3diffluatab, "c") {
return 0;
}
LuaDefine(unittests_world4difftanclass, "c") {
LuaDefine(unittests_world4difftanclass, "", "some unit tests") {
UniqueWorld m(new World(util::WORLD_TYPE_MASTER));
UniqueWorld ss(new World(util::WORLD_TYPE_S_SYNC));
UniqueWorld cs(new World(util::WORLD_TYPE_C_SYNC));