From 9d6afeba223c22163928557c69a102877223d3bd Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Wed, 15 Feb 2017 22:13:01 +0100 Subject: Everything need to make luaL_newstate work, lua_pushnil test --- src/lapi.js | 14 +++++++ src/lauxlib.js | 21 +++++++++++ src/ldo.js | 22 ++++++----- src/lstate.js | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++------- src/ltm.js | 10 ++++- src/lua.js | 15 +++++++- 6 files changed, 172 insertions(+), 25 deletions(-) create mode 100644 src/lauxlib.js (limited to 'src') diff --git a/src/lapi.js b/src/lapi.js index eecf1ab..9e20d7f 100644 --- a/src/lapi.js +++ b/src/lapi.js @@ -2,6 +2,7 @@ "use strict"; const assert = require('assert'); + const ldo = require('./ldo.js'); const lobject = require('./lobject.js'); const lfunc = require('./lfunc.js'); @@ -15,6 +16,17 @@ const l_isfalse = lobject.l_isfalse; const TValue = lobject.TValue; const CClosure = lobject.CClosure; +const lua_version = function(L) { + if (L === null) return lua.LUA_VERSION_NUM; + else return L.l_G.version; +}; + +const lua_atpanic = function(L, panicf) { + let old = L.l_G.panic; + L.l_G.panic = panicf; + return old; +}; + // Return real index on stack const index2addr = function(L, idx) { let ci = L.ci; @@ -212,3 +224,5 @@ module.exports.lua_pushnumber = lua_pushnumber; module.exports.lua_pushinteger = lua_pushinteger; module.exports.lua_pushlstring = lua_pushlstring; module.exports.lua_pushstring = lua_pushstring; +module.exports.lua_version = lua_version; +module.exports.lua_atpanic = lua_atpanic; \ No newline at end of file diff --git a/src/lauxlib.js b/src/lauxlib.js new file mode 100644 index 0000000..3ff346e --- /dev/null +++ b/src/lauxlib.js @@ -0,0 +1,21 @@ +/*jshint esversion: 6 */ +"use strict"; + +const assert = require('assert'); + +const lstate = require('./lstate.js'); +const lapi = require('./lapi.js'); + +const panic = function(L) { + console.log(`PANIC: unprotected error in call to Lua API (...)`); + return 0; +} + +const luaL_newstate = function() { + let L = lstate.lua_newstate(); + if (L) lapi.lua_atpanic(L, panic); + return L; +}; + + +module.exports.luaL_newstate = luaL_newstate; \ No newline at end of file diff --git a/src/ldo.js b/src/ldo.js index 79b92ca..86a06e6 100644 --- a/src/ldo.js +++ b/src/ldo.js @@ -182,6 +182,7 @@ const luaD_rawrunprotected = function(L, f, ud) { try { f(L, ud); } catch (e) { + console.log(e); if (lj.status == 0) lj.status = -1; } @@ -223,13 +224,14 @@ const luaD_callnoyield = function(L, off, nResults) { L.nny--; }; -module.exports.nil = nil; -module.exports.luaD_precall = luaD_precall; -module.exports.luaD_poscall = luaD_poscall; -module.exports.moveresults = moveresults; -module.exports.adjust_varargs = adjust_varargs; -module.exports.tryfuncTM = tryfuncTM; -module.exports.stackerror = stackerror; -module.exports.luaD_call = luaD_call; -module.exports.luaD_callnoyield = luaD_callnoyield; -module.exports.luaD_pcall = luaD_pcall; \ No newline at end of file +module.exports.nil = nil; +module.exports.luaD_precall = luaD_precall; +module.exports.luaD_poscall = luaD_poscall; +module.exports.moveresults = moveresults; +module.exports.adjust_varargs = adjust_varargs; +module.exports.tryfuncTM = tryfuncTM; +module.exports.stackerror = stackerror; +module.exports.luaD_call = luaD_call; +module.exports.luaD_callnoyield = luaD_callnoyield; +module.exports.luaD_pcall = luaD_pcall; +module.exports.luaD_rawrunprotected = luaD_rawrunprotected; \ No newline at end of file diff --git a/src/lstate.js b/src/lstate.js index 84aefc0..4d71be7 100644 --- a/src/lstate.js +++ b/src/lstate.js @@ -1,10 +1,19 @@ /*jshint esversion: 6 */ "use strict"; -const lua = require('./lua.js'); -const LUA_MULTRET = lua.LUA_MULTRET; -const TS = lua.thread_status; -const Table = require('./lobject.js').Table; +const lua = require('./lua.js'); +const Table = require('./lobject.js').Table; +const ldo = require('./ldo.js'); +const lapi = require('./lapi.js'); +const nil = ldo.nil; +const luaD_rawrunprotected = ldo.luaD_rawrunprotected; +const luaT_init = require('./ltm.js').luaT_init; +const CT = lua.constant_types; +const LUA_MULTRET = lua.LUA_MULTRET; +const TS = lua.thread_status; +const LUA_NUMTAGS = lua.LUA_NUMTAGS; + +const BASIC_STACK_SIZE = 2 * lua.LUA_MINSTACK; class CallInfo { @@ -35,20 +44,99 @@ class CallInfo { class lua_State { constructor(cl) { - this.top = 1; - this.ci = new CallInfo(0, cl, 1, 1, null, null); - this.ci.u.l.savedpc = cl.p.code; - this.ci.nresults = LUA_MULTRET; - this.ciOff = 0; - this.stack = [ - cl - ]; + if (cl) { // TODO: remove + this.top = 1; + this.ci = new CallInfo(0, cl, 1, 1, null, null); + this.ci.u.l.savedpc = cl.p.code; + this.ci.nresults = LUA_MULTRET; + this.ciOff = 0; + this.stack = [ + cl + ]; + } else { + this.base_ci = new CallInfo(); // Will be populated later + this.top = 0; + this.ci = null; + this.ciOff = null; + this.stack = []; + } this.openupval = []; this.status = TS.LUA_OK; + this.next = null; + this.tt = CT.LUA_TTHREAD; + this.twups = [this]; + this.errorJmp = null; + // TODO: hooks + this.nny = 1; + this.errfunc = 0; + } + +} + +class global_State { + + constructor(L) { + this.mainthread = L; + this.strt = null // TODO: string hash table + this.l_registry = nil; + this.panic = null; + this.version = null; + this.twups = []; + this.mt = new Array(LUA_NUMTAGS); } } + +const stack_init = function(L1, L) { + L1.stack = new Array(BASIC_STACK_SIZE); // TODO: for now we don't care about the stack size + L1.top = 0; + let ci = L1.base_ci; + ci.next = ci.previous = null; + ci.callstatus = 0; + ci.func = L1.stack[L1.top]; + ci.funcOff = L1.top; + L1.stack[L1.top++] = nil; + ci.top = L1.top + lua.LUA_MINSTACK; + L1.ci = ci; +}; + +/* +** Create registry table and its predefined values +*/ +const init_registry = function(L, g) { + let registry = new Table(); + g.l_registry = registry; + registry.value.array[lua.LUA_RIDX_MAINTHREAD] = L; + registry.value.array[lua.LUA_RIDX_GLOBALS] = new Table(); +}; + +/* +** open parts of the state that may cause memory-allocation errors. +** ('g->version' != NULL flags that the state was completely build) +*/ +const f_luaopen = function(L) { + let g = L.l_G; + stack_init(L, L); + init_registry(L, g); + // TODO: luaS_init(L); + luaT_init(L); + g.version = lapi.lua_version(null); +}; + +const lua_newstate = function() { + let L = new lua_State(); + let g = new global_State(L); + + L.l_G = g; + + if (luaD_rawrunprotected(L, f_luaopen, null) !== TS.LUA_OK) { + L = null; + } + + return L; +}; + module.exports.lua_State = lua_State; module.exports.CallInfo = CallInfo; module.exports.CIST_OAH = (1<<0); /* original value of 'allowhook' */ @@ -59,4 +147,5 @@ module.exports.CIST_YPCALL = (1<<4); /* call is a yieldable protected call * module.exports.CIST_TAIL = (1<<5); /* call was tail called */ module.exports.CIST_HOOKYIELD = (1<<6); /* last hook called yielded */ module.exports.CIST_LEQ = (1<<7); /* using __lt for __le */ -module.exports.CIST_FIN = (1<<8); /* call is running a finalizer */ \ No newline at end of file +module.exports.CIST_FIN = (1<<8); /* call is running a finalizer */ +module.exports.lua_newstate = lua_newstate; \ No newline at end of file diff --git a/src/ltm.js b/src/ltm.js index f5c34b0..8b4f4f5 100644 --- a/src/ltm.js +++ b/src/ltm.js @@ -40,6 +40,13 @@ const TMS = { TM_N: 26 }; +const luaT_init = function(L) { + L.l_G.tmname = []; + for (let event in TMS) { + L.l_G.tmname.push(new TValue(CT.LUA_TLNGSTR, TMS[event])); // Strings are already interned by JS + } +}; + const luaT_callTM = function(L, f, p1, p2, p3, hasres) { let result = p3; let func = L.top; @@ -104,4 +111,5 @@ module.exports.luaT_callTM = luaT_callTM; module.exports.luaT_callbinTM = luaT_callbinTM; module.exports.luaT_trybinTM = luaT_trybinTM; module.exports.luaT_callorderTM = luaT_callorderTM; -module.exports.luaT_gettmbyobj = luaT_gettmbyobj; \ No newline at end of file +module.exports.luaT_gettmbyobj = luaT_gettmbyobj; +module.exports.luaT_init = luaT_init; \ No newline at end of file diff --git a/src/lua.js b/src/lua.js index a336bb0..4534f78 100644 --- a/src/lua.js +++ b/src/lua.js @@ -61,6 +61,14 @@ constant_types.LUA_TLCL = constant_types.LUA_TFUNCTION | (0 << 4); /* Lua closu constant_types.LUA_TLCF = constant_types.LUA_TFUNCTION | (1 << 4); /* light C function */ constant_types.LUA_TCCL = constant_types.LUA_TFUNCTION | (2 << 4); /* C closure */ +const LUA_NUMTAGS = 9; +const LUA_MINSTACK = 20; + +/* predefined values in the registry */ +const LUA_RIDX_MAINTHREAD = 1; +const LUA_RIDX_GLOBALS = 2; +const LUA_RIDX_LAST = LUA_RIDX_GLOBALS; + const print_version = function() { console.log(FENGARI_COPYRIGHT); }; @@ -122,4 +130,9 @@ module.exports.FENGARI_RELEASE = FENGARI_RELEASE; module.exports.FENGARI_COPYRIGHT = FENGARI_COPYRIGHT; module.exports.FENGARI_AUTHORS = FENGARI_AUTHORS; module.exports.LUA_INIT_VAR = LUA_INIT_VAR; -module.exports.LUA_INITVARVERSION = LUA_INITVARVERSION; \ No newline at end of file +module.exports.LUA_INITVARVERSION = LUA_INITVARVERSION; +module.exports.LUA_NUMTAGS = LUA_NUMTAGS; +module.exports.LUA_MINSTACK = LUA_MINSTACK; +module.exports.LUA_RIDX_MAINTHREAD = LUA_RIDX_MAINTHREAD; +module.exports.LUA_RIDX_GLOBALS = LUA_RIDX_GLOBALS; +module.exports.LUA_RIDX_LAST = LUA_RIDX_LAST; \ No newline at end of file -- cgit v1.2.3-70-g09d2