summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lapi.js31
-rw-r--r--src/lauxlib.js35
-rw-r--r--src/lbaselib.js36
3 files changed, 94 insertions, 8 deletions
diff --git a/src/lapi.js b/src/lapi.js
index ece02e0..e1e548d 100644
--- a/src/lapi.js
+++ b/src/lapi.js
@@ -260,6 +260,33 @@ const lua_setglobal = function(L, name) {
auxsetstr(L, L.l_G.l_registry.value.array[lua.LUA_RIDX_GLOBALS - 1], name);
};
+const lua_setmetatable = function(L, objindex) {
+ assert(1 < L.top - L.ci.funcOff, "not enough elements in the stack");
+ let mt;
+ let obj = index2addr(L, objindex);
+ if (L.stack[L.top - 1].ttisnil())
+ mt = null;
+ else {
+ assert(L.stack[L.top - 1].ttistable(), "table expected");
+ mt = L.stack[L.top - 1];
+ }
+
+ switch (obj.ttnov()) {
+ case CT.LUA_TUSERDATA:
+ case CT.LUA_TTABLE: {
+ obj.metatable = mt;
+ break;
+ }
+ default: {
+ L.l_G.mt[obj.ttnov()] = mt;
+ break;
+ }
+ }
+
+ L.top--;
+ return true;
+};
+
const lua_settable = function(L, idx) {
assert(2 < L.top - L.ci.funcOff, "not enough elements in the stack");
@@ -562,4 +589,6 @@ module.exports.lua_pushglobaltable = lua_pushglobaltable;
module.exports.lua_setfield = lua_setfield;
module.exports.lua_getfield = lua_getfield;
module.exports.lua_getglobal = lua_getglobal;
-module.exports.lua_getmetatable = lua_getmetatable; \ No newline at end of file
+module.exports.lua_getmetatable = lua_getmetatable;
+module.exports.lua_setmetatable = lua_setmetatable;
+module.exports.lua_settop = lua_settop; \ No newline at end of file
diff --git a/src/lauxlib.js b/src/lauxlib.js
index 6db0aae..a1f9d64 100644
--- a/src/lauxlib.js
+++ b/src/lauxlib.js
@@ -13,7 +13,27 @@ const LUA_LOADED_TABLE = "_LOADED"
const panic = function(L) {
console.log(`PANIC: unprotected error in call to Lua API (...)`);
return 0;
-}
+};
+
+const typeerror = function(L, arg, tname) {
+ let typearg;
+ if (luaL_getmetafield(L, arg, "__name") === CT.LUA_TSTRING)
+ typearg = lapi.lua_tostring(L, -1);
+ else if (lapi.lua_type(L, arg) === CT.LUA_TLIGHTUSERDATA)
+ typearg = "light userdata";
+ else
+ typearg = luaL_typename(L, arg);
+
+ throw new Error(`${tname} expected, got ${typearg}`);
+
+ // TODO:
+ // let msg = lua_pushstring(L, `${tname} expected, got ${typearg}`);
+ // return luaL_argerror(L, arg, msg);
+};
+
+const tag_error = function(L, arg, tag) {
+ typeerror(L, arg, lapi.lua_typename(L, tag));
+};
const luaL_newstate = function() {
let L = lstate.lua_newstate();
@@ -26,11 +46,20 @@ const luaL_typename = function(L, i) {
return lapi.lua_typename(L, lapi.lua_type(L, i));
};
+const luaL_argcheck = function(L, cond, arg, extramsg) {
+ if (!cond) throw new Error("bad argument"); // TODO: luaL_argerror
+};
+
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_checktype = function(L, arg, t) {
+ if (lapi.lua_type(L, arg) !== t)
+ tag_error(L, arg, t);
+};
+
const luaL_getmetafield = function(L, obj, event) {
if (!lapi.lua_getmetatable(L, obj))
return CT.LUA_TNIL;
@@ -157,6 +186,7 @@ const luaL_checkstack = function(L, space, msg) {
module.exports.luaL_newstate = luaL_newstate;
module.exports.luaL_typename = luaL_typename;
module.exports.luaL_checkany = luaL_checkany;
+module.exports.luaL_checktype = luaL_checktype;
module.exports.luaL_callmeta = luaL_callmeta;
module.exports.luaL_getmetafield = luaL_getmetafield;
module.exports.luaL_requiref = luaL_requiref;
@@ -164,4 +194,5 @@ module.exports.luaL_getsubtable = luaL_getsubtable;
module.exports.luaL_setfuncs = luaL_setfuncs;
module.exports.luaL_checkstack = luaL_checkstack;
module.exports.LUA_LOADED_TABLE = LUA_LOADED_TABLE;
-module.exports.luaL_tolstring = luaL_tolstring; \ No newline at end of file
+module.exports.luaL_tolstring = luaL_tolstring;
+module.exports.luaL_argcheck = luaL_argcheck; \ No newline at end of file
diff --git a/src/lbaselib.js b/src/lbaselib.js
index b046f67..12c28fe 100644
--- a/src/lbaselib.js
+++ b/src/lbaselib.js
@@ -6,6 +6,7 @@ const assert = require('assert');
const lua = require('./lua.js');
const lapi = require('./lapi.js');
const lauxlib = require('./lauxlib.js');
+const CT = lua.constant_types;
const luaB_print = function(L) {
let n = lapi.lua_gettop(L); /* number of arguments */
@@ -35,9 +36,32 @@ const luaB_tostring = function(L) {
return true;
};
+const luaB_getmetatable = function(L) {
+ lauxlib.luaL_checkany(L, 1);
+ if (!lapi.lua_getmetatable(L, 1)) {
+ lapi.lua_pushnil(L);
+ return true; /* no metatable */
+ }
+ lauxlib.luaL_getmetafield(L, 1, "__metatable");
+ return true; /* returns either __metatable field (if present) or metatable */
+};
+
+const luaB_setmetatable = function(L) {
+ let t = lapi.lua_type(L, 2);
+ lauxlib.luaL_checktype(L, 1, CT.LUA_TTABLE);
+ lauxlib.luaL_argcheck(L, t === CT.LUA_TNIL || t === CT.LUA_TTABLE, 2, "nil or table expected");
+ if (lauxlib.luaL_getmetafield(L, 1, "__metatable") !== CT.LUA_TNIL)
+ throw new Error("cannot change a protected metatable");
+ lapi.lua_settop(L, 2);
+ lapi.lua_setmetatable(L, 1);
+ return true;
+};
+
const base_funcs = {
- "print": luaB_print,
- "tostring": luaB_tostring,
+ "print": luaB_print,
+ "tostring": luaB_tostring,
+ "getmetatable": luaB_getmetatable,
+ "setmetatable": luaB_setmetatable,
};
const luaopen_base = function(L) {
@@ -53,6 +77,8 @@ const luaopen_base = function(L) {
return true;
};
-module.exports.luaB_tostring = luaB_tostring;
-module.exports.luaB_print = luaB_print;
-module.exports.luaopen_base = luaopen_base;
+module.exports.luaB_tostring = luaB_tostring;
+module.exports.luaB_print = luaB_print;
+module.exports.luaB_getmetatable = luaB_getmetatable;
+module.exports.luaB_setmetatable = luaB_setmetatable;
+module.exports.luaopen_base = luaopen_base;