aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md86
-rw-r--r--src/lapi.js14
-rw-r--r--src/lauxlib.js21
-rw-r--r--src/ldo.js22
-rw-r--r--src/lstate.js115
-rw-r--r--src/ltm.js10
-rw-r--r--src/lua.js15
-rw-r--r--tests/lapi.js11
8 files changed, 245 insertions, 49 deletions
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,