aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--src/lauxlib.js129
-rw-r--r--src/lbaselib.js30
-rw-r--r--src/ldebug.js2
-rw-r--r--src/lobject.js7
-rw-r--r--tests/load.js33
-rw-r--r--tests/loadfile-test.lua1
7 files changed, 193 insertions, 13 deletions
diff --git a/README.md b/README.md
index 791a885..0cc0b09 100644
--- a/README.md
+++ b/README.md
@@ -70,8 +70,6 @@
- [ ] luaL_fileresult
- [ ] luaL_getmetatable
- [ ] luaL_gsub
- - [ ] luaL_loadfile
- - [ ] luaL_loadfilex
- [ ] luaL_newlibtable
- [ ] luaL_newmetatable
- [ ] luaL_optnumber
@@ -87,8 +85,8 @@
- [ ] Base lib
- [x] ...
- [x] load
+ - [x] loadfile
- [ ] dofile
- - [ ] loadfile
- [x] Coroutine
- [x] Table
- [x] Math
diff --git a/src/lauxlib.js b/src/lauxlib.js
index ac7ab00..dbdb251 100644
--- a/src/lauxlib.js
+++ b/src/lauxlib.js
@@ -3,11 +3,12 @@
const assert = require('assert');
-const lstate = require('./lstate.js');
-const lapi = require('./lapi.js');
-const lua = require('./lua.js');
-const ldebug = require('./ldebug.js');
-const CT = lua.constant_types;
+const lstate = require('./lstate.js');
+const lapi = require('./lapi.js');
+const lua = require('./lua.js');
+const ldebug = require('./ldebug.js');
+const lobject = require('./lobject.js');
+const CT = lua.constant_types;
const LUA_LOADED_TABLE = "_LOADED";
@@ -399,6 +400,124 @@ const luaL_newlib = function(L, l) {
luaL_setfuncs(L, l, 0);
};
+// Only with Node
+if (typeof window === "undefined") {
+ const fs = require('fs');
+
+ class LoadF {
+ constructor() {
+ this.n = NaN; /* number of pre-read characters */
+ this.f = null; /* file being read */
+ this.buff = new Buffer(1024); /* area for reading file */
+ this.pos = 0; /* current position in file */
+ }
+ }
+
+ const getF = function(L, ud) {
+ let lf = ud;
+ let bytes = 0;
+ if (lf.n > 0) { /* are there pre-read characters to be read? */
+ lf.n = 0; /* no more pre-read characters */
+ } else { /* read a block from file */
+ lf.buff.fill(0);
+ bytes = fs.readSync(lf.f, lf.buff, 0, lf.buff.length, lf.pos); /* read block */
+ lf.pos += bytes;
+ }
+ return bytes > 0 ? new lobject.TValue(0, lf.buff).jsstring() : null; // TODO: Here reading utf8 only
+ };
+
+ const errfile = function(L, what, fnameindex, error) {
+ let serr = error.message;
+ let filename = lapi.lua_tostring(L, fnameindex).slice(1);
+ lapi.lua_pushstring(L, `cannot ${what} ${filename}: ${serr}`);
+ lapi.lua_remove(L, fnameindex);
+ return lua.thread_status.LUA_ERRFILE;
+ };
+
+ const getc = function(lf) {
+ let b = new Buffer(1);
+ let bytes = fs.readSync(lf.f, b, 0, 1, lf.pos);
+ lf.pos += bytes;
+ return bytes > 0 ? b.readUInt8() : null;
+ };
+
+ const skipBOM = function(lf) {
+ let p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
+ lf.n = 0;
+ let c;
+ do {
+ c = getc(lf);
+ if (c === null || c !== p.charCodeAt(0)) return c;
+ p = p.slice(1);
+ lf.buff[lf.n++] = c; /* to be read by the parser */
+ } while (p.length > 0);
+ lf.n = 0; /* prefix matched; discard it */
+ return getc(lf); /* return next character */
+ };
+
+ /*
+ ** reads the first character of file 'f' and skips an optional BOM mark
+ ** in its beginning plus its first line if it starts with '#'. Returns
+ ** true if it skipped the first line. In any case, '*cp' has the
+ ** first "valid" character of the file (after the optional BOM and
+ ** a first-line comment).
+ */
+ const skipcomment = function(lf) {
+ let c = skipBOM(lf);
+ if (c === '#'.charCodeAt(0)) { /* first line is a comment (Unix exec. file)? */
+ do { /* skip first line */
+ c = getc(lf);
+ } while (c && c !== '\n'.charCodeAt(0));
+ return getc(lf); /* skip end-of-line, if present */
+ } else {
+ lf.pos--;
+ return false;
+ }
+ };
+
+ const luaL_loadfilex = function(L, filename, mode) {
+ let lf = new LoadF();
+ let fnameindex = lapi.lua_gettop(L) + 1; /* index of filename on the stack */
+ if (filename === null) {
+ lapi.lua_pushliteral(L, "=stdin");
+ lf.f = process.stdin.fd;
+ } else {
+ lapi.lua_pushstring(L, `@${filename}`);
+ try {
+ lf.f = fs.openSync(filename, "r");
+ } catch (e) {
+ return errfile(L, "open", fnameindex, e);
+ }
+ }
+
+ try {
+ let c;
+ if ((c = skipcomment(lf))) /* read initial portion */
+ lf.buff[lf.n++] = '\n'.charCodeAt(0); /* add line to correct line numbers */
+
+ if (c === lua.LUA_SIGNATURE.charCodeAt(0) && filename) { /* binary file? */
+ // ...
+ }
+
+ let status = lapi.lua_load(L, getF, lf, lapi.lua_tostring(L, -1), mode);
+ if (filename) fs.closeSync(lf.f); /* close file (even in case of errors) */
+ lapi.lua_remove(L, fnameindex);
+ return status;
+ } catch (err) {
+ lapi.lua_settop(L, fnameindex); /* ignore results from 'lua_load' */
+ return errfile(L, "read", fnameindex);
+ }
+ };
+
+ const luaL_loadfile = function(L, filename) {
+ return luaL_loadfilex(L, filename, null);
+ };
+
+ module.exports.luaL_loadfilex = luaL_loadfilex;
+ module.exports.luaL_loadfile = luaL_loadfile;
+
+}
+
module.exports.LUA_LOADED_TABLE = LUA_LOADED_TABLE;
module.exports.luaL_Buffer = luaL_Buffer;
module.exports.luaL_addchar = luaL_addchar;
diff --git a/src/lbaselib.js b/src/lbaselib.js
index 0b5c2f7..604a005 100644
--- a/src/lbaselib.js
+++ b/src/lbaselib.js
@@ -332,6 +332,36 @@ const base_funcs = {
"xpcall": luaB_xpcall
};
+// Only with Node
+if (typeof window === "undefined") {
+
+ const load_aux = function(L, status, envidx) {
+ if (status === TS.LUA_OK) {
+ if (envidx !== 0) { /* 'env' parameter? */
+ lapi.lua_pushvalue(L, envidx); /* environment for loaded function */
+ if (!lapi.lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
+ lapi.lua_pop(L, 1); /* remove 'env' if not used by previous call */
+ }
+ return 1;
+ } else { /* error (message is on top of the stack) */
+ lapi.lua_pushnil(L);
+ lapi.lua_insert(L, -2); /* put before error message */
+ return 2; /* return nil plus error message */
+ }
+ };
+
+ const luaB_loadfile = function(L) {
+ let fname = lauxlib.luaL_optstring(L, 1, null);
+ let mode = lauxlib.luaL_optstring(L, 2, null);
+ let env = !lapi.lua_isnone(L, 3) ? 3 : 0; /* 'env' index or 0 if no 'env' */
+ let status = lauxlib.luaL_loadfilex(L, fname, mode);
+ return load_aux(L, status, env);
+ };
+
+ base_funcs.loadfile = luaB_loadfile;
+
+}
+
const luaopen_base = function(L) {
/* open lib into global table */
lapi.lua_pushglobaltable(L);
diff --git a/src/ldebug.js b/src/ldebug.js
index 2858267..529cb0c 100644
--- a/src/ldebug.js
+++ b/src/ldebug.js
@@ -431,7 +431,7 @@ const varinfo = function(L, o) {
kind = getobjname(ci.func.p, ci.pcOff, stkid - ci.u.l.base);
}
- return kind ? ` (${kind.funcname} '${kind.name}')` : ``;
+ return kind ? ` (${kind.funcname} '${kind.name.jsstring()}')` : ``;
};
const luaG_typeerror = function(L, o, op) {
diff --git a/src/lobject.js b/src/lobject.js
index dfe6337..8fc587d 100644
--- a/src/lobject.js
+++ b/src/lobject.js
@@ -119,7 +119,6 @@ class TValue {
}
jsstring() {
- //return this.ttisstring() ? String.fromCharCode(...this.value) : null;
let u0, u1, u2, u3, u4, u5;
let idx = 0;
@@ -273,17 +272,17 @@ const PRE = "[string \"";
const POS = "\"]";
const luaO_chunkid = function(source, bufflen) {
- source = source instanceof TValue ? source.value : source;
+ source = source instanceof TValue ? source.jsstring() : source;
bufflen = bufflen instanceof TValue ? bufflen.value : bufflen;
let l = source.length;
let out = "";
- if (source[0] === '=') { /* 'literal' source */
+ if (source.charAt(0) === '=') { /* 'literal' source */
if (l < bufflen) /* small enough? */
out = `${source.slice(1)}`;
else { /* truncate it */
out += `${source.slice(1, bufflen)}`;
}
- } else if (source[0] === '@') { /* file name */
+ } else if (source.charAt(0) === '@') { /* file name */
if (l <= bufflen) /* small enough? */
out = `${source.slice(1)}`;
else { /* add '...' before rest of name */
diff --git a/tests/load.js b/tests/load.js
index 86c3904..c7ea3f9 100644
--- a/tests/load.js
+++ b/tests/load.js
@@ -114,4 +114,37 @@ test('luaL_loadbuffer', function (t) {
"Correct element(s) on the stack"
);
+});
+
+// TODO: test stdin
+test('loadfile', function (t) {
+ let luaCode = `
+ local f = loadfile("tests/loadfile-test.lua")
+ return f()
+ `, L;
+
+ t.plan(3);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ linit.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, luaCode);
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lapi.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+ t.strictEqual(
+ lapi.lua_tostring(L, -1),
+ "hello world",
+ "Correct element(s) on the stack"
+ );
+
}); \ No newline at end of file
diff --git a/tests/loadfile-test.lua b/tests/loadfile-test.lua
new file mode 100644
index 0000000..838d20b
--- /dev/null
+++ b/tests/loadfile-test.lua
@@ -0,0 +1 @@
+return "hello world" \ No newline at end of file