aboutsummaryrefslogtreecommitdiff
path: root/src/lauxlib.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/lauxlib.js')
-rw-r--r--src/lauxlib.js142
1 files changed, 139 insertions, 3 deletions
diff --git a/src/lauxlib.js b/src/lauxlib.js
index 6cc3d3c..af09df7 100644
--- a/src/lauxlib.js
+++ b/src/lauxlib.js
@@ -5,6 +5,8 @@ const assert = require('assert');
const lstate = require('./lstate.js');
const lapi = require('./lapi.js');
+const lua = require('./lua.js');
+const CT = lua.constant_types;
const panic = function(L) {
console.log(`PANIC: unprotected error in call to Lua API (...)`);
@@ -20,8 +22,142 @@ const luaL_newstate = function() {
const luaL_typename = function(L, i) {
return lapi.lua_typename(L, lapi.lua_type(L, i));
-}
+};
+
+const luaL_checkany = function(L, arg) {
+ if (lapi.lua_type(L, arg) === CT.LUA_TNONE)
+ throw new Error("value expected"); // TODO: luaL_argerror(L, arg, "value expected");
+};
+
+const luaL_getmetafield = function(L, obj, event) {
+ if (!lapi.lua_getmetatable(L, obj))
+ return CT.LUA_TNIL;
+ else {
+ lapi.lua_pushstring(L, event);
+ let tt = lapi.lua_rawget(L, -2);
+ if (tt === CT.LUA_TNIL)
+ lapi.lua_pop(L, 2);
+ return tt;
+ }
+};
+
+const luaL_callmeta = function(L, obj, event) {
+ obj = lapi.lua_absindex(L, obj);
+ if (luaL_getmetafield(L, obj, event) === CT.LUA_TNIL)
+ return false;
+
+ lapi.lua_pushvalue(L, obj);
+ lapi.lua_call(L, 1, 1);
+
+ return true;
+};
+const luaL_tolstring = function(L, idx, len) {
+ if (luaL_callmeta(L, idx, "__tostring")) {
+ if (!lapi.lua_isstring(L, -1))
+ throw new Error("'__tostring' must return a string"); // TODO: luaL_error
+ } else {
+ switch(lapi.lua_type(L, idx)) {
+ case CT.LUA_TNUMBER:
+ case CT.LUA_TSTRING:
+ case CT.LUA_TBOOLEAN:
+ lapi.lua_pushstring(L, `${lapi.index2addr(L, idx).value}`);
+ break;
+ case CT.LUA_TNIL:
+ lapi.lua_pushstring(L, `nil`);
+ break;
+ default:
+ let tt = luaL_getmetafield(L, idx, "__name");
+ let kind = tt === CT.LUA_TSTRING ? lua_tostring(L, -1) : luaL_typename(L, idx);
+ lapi.lua_pushstring(L, `${kind}`); // We can't print memory address in JS
+ if (tt !== CT.LUA_TNIL)
+ lapi.lua_remove(L, -2);
+ break;
+ }
+ }
+
+ return lapi.lua_tolstring(L, -1, len);
+};
+
+/*
+** Stripped-down 'require': After checking "loaded" table, calls 'openf'
+** to open a module, registers the result in 'package.loaded' table and,
+** if 'glb' is true, also registers the result in the global table.
+** Leaves resulting module on the top.
+*/
+const luaL_requiref = function(L, modname, openf, glb) {
+ luaL_getsubtable(L, lua.LUA_REGISTRYINDEX, lua.LUA_LOADED_TABLE);
+ lapi.lua_getfield(L, -1, modname); /* LOADED[modname] */
+ if (!lapi.lua_toboolean(L, -1)) { /* package not already loaded? */
+ lapi.lua_pop(L, 1); /* remove field */
+ lapi.lua_pushcfunction(L, openf);
+ lapi.lua_pushstring(L, modname); /* argument to open function */
+ lapi.lua_call(L, 1, 1); /* call 'openf' to open module */
+ lapi.lua_pushvalue(L, -1); /* make copy of module (call result) */
+ lapi.lua_setfield(L, -3, modname); /* LOADED[modname] = module */
+ }
+ lapi.lua_remove(L, -2); /* remove LOADED table */
+ if (glb) {
+ lua_pushvalue(L, -1); /* copy of module */
+ lua_setglobal(L, modname); /* _G[modname] = module */
+ }
+};
+
+/*
+** ensure that stack[idx][fname] has a table and push that table
+** into the stack
+*/
+const luaL_getsubtable = function(L, idx, fname) {
+ if (lapi.lua_getfield(L, idx, fname) === CT.LUA_TTABLE)
+ return true; /* table already there */
+ else {
+ lapi.lua_pop(L, 1); /* remove previous result */
+ idx = lapi.lua_absindex(L, idx);
+ lapi.lua_newtable(L);
+ lapi.lua_pushvalue(L, -1); /* copy to be left at top */
+ lapi.lua_setfield(L, idx, fname); /* assign new table to field */
+ return false; /* false, because did not find table there */
+ }
+};
+
+/*
+** set functions from list 'l' into table at top - 'nup'; each
+** function gets the 'nup' elements at the top as upvalues.
+** Returns with only the table at the stack.
+*/
+const luaL_setfuncs = function(L, l, nup) {
+ luaL_checkstack(L, nup, "too many upvalues");
+ for (lib in l) { /* fill the table with given functions */
+ for (let i = 0; i < nup; i++) /* copy upvalues to the top */
+ lapi.lua_pushvalue(L, -nup);
+ lapi.lua_pushcclosure(L, l[lib], nup); /* closure with those upvalues */
+ lapi.lua_setfield(L, -(nup + 2), lib);
+ }
+ lapi.lua_pop(l, nup); /* remove upvalues */
+};
+
+/*
+** Ensures the stack has at least 'space' extra slots, raising an error
+** if it cannot fulfill the request. (The error handling needs a few
+** extra slots to format the error message. In case of an error without
+** this extra space, Lua will generate the same 'stack overflow' error,
+** but without 'msg'.)
+*/
+const luaL_checkstack = function(L, space, msg) {
+ if (!lapi.luaL_checkstack(L, space)) {
+ if (msg)
+ throw new Error(L, `stack overflow (${msg})`);
+ else
+ throw new Error(L, 'stack overflow'); // TODO: luaL_error
+ }
+};
-module.exports.luaL_newstate = luaL_newstate;
-module.exports.luaL_typename = luaL_typename; \ No newline at end of file
+module.exports.luaL_newstate = luaL_newstate;
+module.exports.luaL_typename = luaL_typename;
+module.exports.luaL_checkany = luaL_checkany;
+module.exports.luaL_callmeta = luaL_callmeta;
+module.exports.luaL_getmetafield = luaL_getmetafield;
+module.exports.luaL_requiref = luaL_requiref;
+module.exports.luaL_getsubtable = luaL_getsubtable;
+module.exports.luaL_setfuncs = luaL_setfuncs;
+module.exports.luaL_checkstack = luaL_checkstack; \ No newline at end of file