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 --- README.md | 86 +++++++++++++++++++++++++++++++++--------- src/lapi.js | 14 +++++++ src/lauxlib.js | 21 +++++++++++ src/ldo.js | 22 ++++++----- src/lstate.js | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++------- src/ltm.js | 10 ++++- src/lua.js | 15 +++++++- tests/lapi.js | 11 +++--- 8 files changed, 245 insertions(+), 49 deletions(-) create mode 100644 src/lauxlib.js diff --git a/README.md b/README.md index 02f16fe..ee33ad4 100644 --- a/README.md +++ b/README.md @@ -21,21 +21,11 @@ - [ ] `__tostring` - [ ] `__pairs` - [ ] C API - - [ ] lua_Alloc - - [ ] lua_CFunction - - [ ] lua_Debug - - [ ] lua_Hook - - [ ] lua_Integer - - [ ] lua_KContext - - [ ] lua_KFunction - - [ ] lua_Number - - [ ] lua_Reader - - [ ] lua_State - - [ ] lua_Unsigned - - [ ] lua_Writer + - [x] lua_atpanic + - [x] lua_newstate + - [x] lua_pushnil - [ ] lua_absindex - [ ] lua_arith - - [ ] lua_atpanic - [ ] lua_call - [ ] lua_callk - [ ] lua_checkstack @@ -46,9 +36,9 @@ - [ ] lua_createtable - [ ] lua_dump - [ ] lua_error - - [ ] lua_gc - - [ ] lua_getallocf - - [ ] lua_getextraspace + - [x] lua_gc (unvailable) + - [x] lua_getallocf (unvailable) + - [x] lua_getextraspace (unvailable) - [ ] lua_getfield - [ ] lua_getglobal - [ ] lua_gethook @@ -80,7 +70,6 @@ - [ ] lua_isyieldable - [ ] lua_len - [ ] lua_load - - [ ] lua_newstate - [ ] lua_newtable - [ ] lua_newthread - [ ] lua_newuserdata @@ -98,7 +87,6 @@ - [ ] lua_pushlightuserdata - [ ] lua_pushliteral - [ ] lua_pushlstring - - [ ] lua_pushnil - [ ] lua_pushnumber - [ ] lua_pushstring - [ ] lua_pushthread @@ -151,6 +139,68 @@ - [ ] lua_yield - [ ] lua_yieldk - [ ] Auxiliary library + - [x] luaL_newstate + - [ ] luaL_Buffer + - [ ] luaL_Reg + - [ ] luaL_Stream + - [ ] luaL_addchar + - [ ] luaL_addlstring + - [ ] luaL_addsize + - [ ] luaL_addstring + - [ ] luaL_addvalue + - [ ] luaL_argcheck + - [ ] luaL_argerror + - [ ] luaL_buffinit + - [ ] luaL_buffinitsize + - [ ] luaL_callmeta + - [ ] luaL_checkany + - [ ] luaL_checkinteger + - [ ] luaL_checklstring + - [ ] luaL_checknumber + - [ ] luaL_checkoption + - [ ] luaL_checkstack + - [ ] luaL_checkstring + - [ ] luaL_checktype + - [ ] luaL_checkudata + - [ ] luaL_checkversion + - [ ] luaL_dofile + - [ ] luaL_dostring + - [ ] luaL_error + - [ ] luaL_execresult + - [ ] luaL_fileresult + - [ ] luaL_getmetafield + - [ ] luaL_getmetatable + - [ ] luaL_getsubtable + - [ ] luaL_gsub + - [ ] luaL_len + - [ ] luaL_loadbuffer + - [ ] luaL_loadbufferx + - [ ] luaL_loadfile + - [ ] luaL_loadfilex + - [ ] luaL_loadstring + - [ ] luaL_newlib + - [ ] luaL_newlibtable + - [ ] luaL_newmetatable + - [ ] luaL_openlibs + - [ ] luaL_opt + - [ ] luaL_optinteger + - [ ] luaL_optlstring + - [ ] luaL_optnumber + - [ ] luaL_optstring + - [ ] luaL_prepbuffer + - [ ] luaL_prepbuffsize + - [ ] luaL_pushresult + - [ ] luaL_pushresultsize + - [ ] luaL_ref + - [ ] luaL_requiref + - [ ] luaL_setfuncs + - [ ] luaL_setmetatable + - [ ] luaL_testudata + - [ ] luaL_tolstring + - [ ] luaL_traceback + - [ ] luaL_typename + - [ ] luaL_unref + - [ ] luaL_where - [ ] Standard library - [ ] Debug (errors) - [ ] DOM API binding 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 diff --git a/tests/lapi.js b/tests/lapi.js index 2f493c9..b79c519 100644 --- a/tests/lapi.js +++ b/tests/lapi.js @@ -9,20 +9,19 @@ const getState = require("./tests.js").getState; const VM = require("../src/lvm.js"); const ldo = require("../src/ldo.js"); const lapi = require("../src/lapi.js"); +const lauxlib = require("../src/lauxlib.js"); const CT = require('../src/lua.js').constant_types; -test('lua_pushnil', function (t) { +test('luaL_newstate, lua_pushnil', function (t) { let L; - t.plan(3); + t.plan(2); t.doesNotThrow(function () { - L = getState(`return "dummy"`); - }, "New Lua State initiliazed"); + L = lauxlib.luaL_newstate() - // t.doesNotThrow(function () { lapi.lua_pushnil(L); - // }, "Pushed nil on the stack"); + }, "JS Lua program ran without error"); t.strictEqual( L.stack[L.top - 1].type, -- cgit v1.2.3-70-g09d2