aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md18
-rw-r--r--src/ltable.js2
-rw-r--r--src/lvm.js2
-rwxr-xr-x[-rw-r--r--]tests/manual-tests/debug-cli.js5
-rwxr-xr-xtests/manual-tests/lua-cli.js305
-rw-r--r--tests/test-suite/inprogress/attrib.js6
-rw-r--r--tests/test-suite/inprogress/bitwise.js6
-rw-r--r--tests/test-suite/inprogress/coroutine.js6
-rw-r--r--tests/test-suite/inprogress/errors.js1323
-rw-r--r--tests/test-suite/inprogress/goto.js6
-rw-r--r--tests/test-suite/inprogress/math.js6
-rw-r--r--tests/test-suite/inprogress/pm.js6
-rw-r--r--tests/test-suite/inprogress/sort.js6
-rw-r--r--tests/test-suite/inprogress/tpack.js6
-rw-r--r--tests/test-suite/inprogress/utf8.js6
15 files changed, 1365 insertions, 344 deletions
diff --git a/README.md b/README.md
index 4a4cb78..29f432e 100644
--- a/README.md
+++ b/README.md
@@ -54,28 +54,28 @@ IRC: #fengari on freenode
- [x] Auxiliary library
- [ ] Run [Lua test suite](https://github.com/lua/tests)
- [x] `calls.lua` (32/32)
+ - [x] `closure.lua` (16/16)
- [x] `constructs.lua` (`_soft`) (10/10)
- - [x] `coroutine.lua` (32/32)
- [x] `events.lua` (26/26)
- [x] `literals.lua` (30/30)
- [x] `locals.lua` (10/10)
+ - [x] `nextvar.lua` (44/44)
- [x] `strings.lua` (34/34)
- [x] `vararg.lua` (8/8)
- - [ ] `api.lua`
- - [ ] `attrib.lua`
- - [ ] `big.lua`
- [ ] `bitwise.lua` (9/16)
- - [ ] `closure.lua` (14/16)
- - [ ] `code.lua`
- - [ ] `db.lua`
- - [ ] `errors.lua`
+ - [ ] `coroutine.lua` (32/40)
+ - [ ] `errors.lua` (46/64)
- [ ] `goto.lua` (16/18)
- [ ] `math.lua` (44/68)
- - [ ] `nextvar.lua` (42/44)
- [ ] `pm.lua` (27/38)
- [ ] `sort.lua` (21/24)
- [ ] `tpack.lua` (20/32)
- [ ] `utf8.lua` (14/20)
+ - [ ] `api.lua`
+ - [ ] `attrib.lua`
+ - [ ] `big.lua`
+ - [ ] `code.lua`
+ - [ ] `db.lua`
- [ ] `verybig.lua`
- [ ] DOM API binding: [https://github.com/fengari-lua/fengari-interop](https://github.com/fengari-lua/fengari-interop)
diff --git a/src/ltable.js b/src/ltable.js
index a06e5d8..e4d21e2 100644
--- a/src/ltable.js
+++ b/src/ltable.js
@@ -187,7 +187,7 @@ const luaH_next = function(L, table, keyI) {
return false;
} else {
/* Try dead keys */
- entry = table.dead_weak.get(hash) || table.dead_strong.get(hash);
+ entry = (table.dead_weak && table.dead_weak.get(hash)) || table.dead_strong.get(hash);
if (!entry)
/* item not in table */
return ldebug.luaG_runerror(L, defs.to_luastring("invalid key to 'next'"));
diff --git a/src/lvm.js b/src/lvm.js
index df4f62f..6857b1d 100644
--- a/src/lvm.js
+++ b/src/lvm.js
@@ -835,7 +835,7 @@ const LTnum = function(l, r) {
if (r.ttisinteger())
return l.value < r.value ? 1 : 0;
else
- return LTintfloat(r.value, l.value);
+ return LTintfloat(l.value, r.value);
} else {
if (r.ttisfloat())
return l.value < r.value ? 1 : 0;
diff --git a/tests/manual-tests/debug-cli.js b/tests/manual-tests/debug-cli.js
index 0bedf50..5fba8e5 100644..100755
--- a/tests/manual-tests/debug-cli.js
+++ b/tests/manual-tests/debug-cli.js
@@ -1,5 +1,8 @@
+#!/usr/bin/env node
"use strict";
+global.WEB = false;
+
const lua = require('../../src/lua.js');
const lauxlib = require('../../src/lauxlib.js');
const lualib = require('../../src/lualib.js');
@@ -15,4 +18,4 @@ lualib.luaL_openlibs(L);
lauxlib.luaL_loadstring(L, lua.to_luastring(luaCode));
-lua.lua_call(L, 0, -1);
+lua.lua_call(L, 0, 0);
diff --git a/tests/manual-tests/lua-cli.js b/tests/manual-tests/lua-cli.js
deleted file mode 100755
index deadee7..0000000
--- a/tests/manual-tests/lua-cli.js
+++ /dev/null
@@ -1,305 +0,0 @@
-#!/usr/bin/env node
-"use strict";
-
-global.WEB = false;
-
-const lua = require('../../src/lua.js');
-const lauxlib = require('../../src/lauxlib.js');
-const lualib = require('../../src/lualib.js');
-
-const readlineSync = require('readline-sync');
-
-const stdin = lua.to_luastring("=stdin");
-const _PROMPT = lua.to_luastring("_PROMPT");
-const _PROMPT2 = lua.to_luastring("_PROMPT2");
-
-const report = function(L, status) {
- if (status !== lua.LUA_OK) {
- lauxlib.lua_writestringerror(`${lua.lua_tojsstring(L, -1)}\n`);
- lua.lua_pop(L, 1);
- }
- return status;
-};
-
-const msghandler = function(L) {
- let msg = lua.lua_tostring(L, 1);
- if (msg === null) { /* is error object not a string? */
- if (lauxlib.luaL_callmeta(L, 1, lua.to_luastring("__tostring")) && /* does it have a metamethod */
- lua.lua_type(L, -1) == lua.LUA_TSTRING) /* that produces a string? */
- return 1; /* that is the message */
- else
- msg = lua.lua_pushstring(L, lua.to_luastring(`(error object is a ${lua.to_jsstring(lauxlib.luaL_typename(L, 1))} value)`));
- }
- lauxlib.luaL_traceback(L, L, msg, 1); /* append a standard traceback */
- return 1; /* return the traceback */
-};
-
-const docall = function(L, narg, nres) {
- let base = lua.lua_gettop(L) - narg;
- lua.lua_pushcfunction(L, msghandler);
- lua.lua_insert(L, base);
- let status = lua.lua_pcall(L, narg, nres, base);
- lua.lua_remove(L, base);
- return status;
-};
-
-const dochunk = function(L, status) {
- if (status === lua.LUA_OK) {
- status = docall(L, 0, 0);
- }
- return report(L, status);
-};
-
-const dofile = function(L, name) {
- return dochunk(L, lauxlib.luaL_loadfile(L, lua.to_luastring(name)));
-};
-
-const dostring = function(L, s, name) {
- let buffer = lua.to_luastring(s);
- return dochunk(L, lauxlib.luaL_loadbuffer(L, buffer, buffer.length, lua.to_luastring(name)));
-};
-
-const dolibrary = function(L, name) {
- lua.lua_getglobal(L, lua.to_luastring("require"));
- lua.lua_pushliteral(L, name);
- let status = docall(L, 1, 1); /* call 'require(name)' */
- if (status === lua.LUA_OK)
- lua.lua_setglobal(L, lua.to_luastring(name)); /* global[name] = require return */
- return report(L, status);
-};
-
-let progname = process.argv[1];
-
-const print_usage = function(badoption) {
- lauxlib.lua_writestringerror(`${progname}: `);
- if (badoption[1] === "e" || badoption[1] === "l")
- lauxlib.lua_writestringerror(`'${badoption}' needs argument\n`);
- else
- lauxlib.lua_writestringerror(`'unrecognized option '${badoption}'\n`);
- lauxlib.lua_writestringerror(
- `usage: ${progname} [options] [script [args]]\n` +
- "Available options are:\n" +
- " -e stat execute string 'stat'\n" +
- " -i enter interactive mode after executing 'script'\n" +
- " -l name require library 'name'\n" +
- " -v show version information\n" +
- " -E ignore environment variables\n" +
- " -- stop handling options\n" +
- " - stop handling options and execute stdin\n"
- );
-};
-
-const L = lauxlib.luaL_newstate();
-
-let script = 2; // Where to start args from
-let has_E = false;
-let has_i = false;
-let has_v = false;
-let has_e = false;
-
-(function() {
- let i;
- for (i = 2; i<process.argv.length; i++) {
- script = i;
- if (process.argv[i][0] != "-") {
- return;
- }
- switch(process.argv[i][1]) {
- case '-':
- if (process.argv[i][2]) {
- print_usage(process.argv[script]);
- return process.exit(1);
- }
- script = i + 1;
- return;
- case void 0: /* script name is '-' */
- return;
- case 'E':
- has_E = true;
- break;
- case 'i':
- has_i = true;
- /* (-i implies -v) */
- /* falls through */
- case 'v':
- if (process.argv[i].length > 2) {
- /* invalid option */
- print_usage(process.argv[script]);
- return process.exit(1);
- }
- has_v = true;
- break;
- case 'e':
- has_e = true;
- /* falls through */
- case 'l': /* both options need an argument */
- if (process.argv[i].length < 3) { /* no concatenated argument? */
- i++; /* try next 'process.argv' */
- if (process.argv.length <= i || process.argv[i][0] === '-') {
- /* no next argument or it is another option */
- print_usage(process.argv[script]);
- return process.exit(1);
- }
- }
- break;
- default: /* invalid option */
- print_usage(process.argv[script]);
- return process.exit(1);
- }
- }
- script = i;
-})();
-
-if (has_v)
- console.log(lua.FENGARI_COPYRIGHT);
-
-if (has_E) {
- /* signal for libraries to ignore env. vars. */
- lua.lua_pushboolean(L, 1);
- lua.lua_setfield(L, lua.LUA_REGISTRYINDEX, lua.to_luastring("LUA_NOENV"));
-}
-
-/* open standard libraries */
-lualib.luaL_openlibs(L);
-
-/* create table 'arg' */
-lua.lua_createtable(L, process.argv.length - (script + 1), script + 1);
-for (let i = 0; i < process.argv.length; i++) {
- lua.lua_pushliteral(L, process.argv[i]);
- lua.lua_seti(L, -2, i - script); /* TODO: rawseti */
-}
-lua.lua_setglobal(L, lua.to_luastring("arg"));
-
-if (!has_E) {
- /* run LUA_INIT */
- let name = "LUA_INIT"+lua.LUA_VERSUFFIX;
- let init = process.env[name];
- if (!init) {
- name = "LUA_INIT";
- init = process.env[name];
- }
- if (init) {
- let status;
- if (init[0] === '@') {
- status = dofile(L, init.substring(1));
- } else {
- status = dostring(L, init, name);
- }
- if (status !== lua.LUA_OK) {
- return process.exit(1);
- }
- }
-}
-
-/* execute arguments -e and -l */
-for (let i = 1; i < script; i++) {
- let option = process.argv[i][1];
- if (option == 'e' || option == 'l') {
- let extra = process.argv[i].substring(2); /* both options need an argument */
- if (extra.length === 0)
- extra = process.argv[++i];
- let status;
- if (option == 'e') {
- status = dostring(L, extra, "=(command line)");
- } else {
- status = dolibrary(L, extra);
- }
- if (status !== lua.LUA_OK) {
- return process.exit(1);
- }
- }
-}
-
-const pushargs = function(L) {
- if (lua.lua_getglobal(L, lua.to_luastring("arg")) !== lua.LUA_TTABLE)
- lauxlib.luaL_error(L, lua.to_luastring("'arg' is not a table"));
- let n = lauxlib.luaL_len(L, -1);
- lauxlib.luaL_checkstack(L, n+3, lua.to_luastring("too many arguments to script"));
- let i;
- for (i=1; i<=n; i++)
- lua.lua_rawgeti(L, -i, i);
- lua.lua_remove(L, -i);
- return n;
-};
-
-const handle_script = function(L, argv) {
- let fname = argv[0];
- let status;
- if (fname === "-" && argv[-1] !== "--")
- fname = null; /* stdin */
- else
- fname = lua.to_luastring(fname);
- status = lauxlib.luaL_loadfile(L, fname);
- if (status === lua.LUA_OK) {
- let n = pushargs(L); /* push arguments to script */
- status = docall(L, n, lua.LUA_MULTRET);
- }
- return report(L, status);
-};
-
-const doREPL = function(L) {
- for (;;) {
- lua.lua_getglobal(L, _PROMPT);
- let input = readlineSync.prompt({
- prompt: lua.lua_tojsstring(L, -1) || '> '
- });
- lua.lua_pop(L, 1);
-
- if (input.length === 0)
- continue;
-
- let status;
- {
- let buffer = lua.to_luastring("return " + input);
- status = lauxlib.luaL_loadbuffer(L, buffer, buffer.length, stdin);
- }
- if (status !== lua.LUA_OK) {
- lua.lua_pop(L, 1);
- let buffer = lua.to_luastring(input);
- if (lauxlib.luaL_loadbuffer(L, buffer, buffer.length, stdin) === lua.LUA_OK) {
- status = lua.LUA_OK;
- }
- }
- while (status === lua.LUA_ERRSYNTAX && lua.lua_tojsstring(L, -1).endsWith("<eof>")) {
- /* continuation */
- lua.lua_pop(L, 1);
- lua.lua_getglobal(L, _PROMPT2);
- input += "\n" + readlineSync.prompt({
- prompt: lua.lua_tojsstring(L, -1) || '>> '
- });
- lua.lua_pop(L, 1);
- let buffer = lua.to_luastring(input);
- status = lauxlib.luaL_loadbuffer(L, buffer, buffer.length, stdin);
- }
- if (status === lua.LUA_OK) {
- status = docall(L, 0, lua.LUA_MULTRET);
- }
- if (status === lua.LUA_OK) {
- let n = lua.lua_gettop(L);
- if (n > 0) { /* any result to be printed? */
- lua.lua_getglobal(L, lua.to_luastring("print"));
- lua.lua_insert(L, 1);
- if (lua.lua_pcall(L, n, 0, 0) != lua.LUA_OK) {
- lauxlib.lua_writestringerror(`error calling 'print' (${lua.lua_tojsstring(L, -1)})\n`);
- }
- }
- } else {
- report(L, status);
- }
- lua.lua_settop(L, 0); /* remove eventual returns */
- }
-};
-
-if (script < process.argv.length && /* execute main script (if there is one) */
- handle_script(L, process.argv.slice(script)) !== lua.LUA_OK) {
- /* success */
-} else if (has_i) {
- doREPL(L);
-} else if (script == process.argv.length && !has_e && !has_v) { /* no arguments? */
- if (process.stdin.isTTY) { /* running in interactive mode? */
- console.log(lua.FENGARI_COPYRIGHT);
- doREPL(L); /* do read-eval-print loop */
- } else {
- dofile(L, null);
- }
-}
diff --git a/tests/test-suite/inprogress/attrib.js b/tests/test-suite/inprogress/attrib.js
index ca23d26..b5926b7 100644
--- a/tests/test-suite/inprogress/attrib.js
+++ b/tests/test-suite/inprogress/attrib.js
@@ -4,9 +4,9 @@ const test = require('tape');
global.WEB = false;
-const lua = require('../../src/lua.js');
-const lauxlib = require('../../src/lauxlib.js');
-const lualib = require('../../src/lualib.js');
+const lua = require('../../../src/lua.js');
+const lauxlib = require('../../../src/lauxlib.js');
+const lualib = require('../../../src/lualib.js');
test("[test-suite] attrib: testing require", function (t) {
diff --git a/tests/test-suite/inprogress/bitwise.js b/tests/test-suite/inprogress/bitwise.js
index 3969bb0..b742b45 100644
--- a/tests/test-suite/inprogress/bitwise.js
+++ b/tests/test-suite/inprogress/bitwise.js
@@ -4,9 +4,9 @@ const test = require('tape');
global.WEB = false;
-const lua = require('../../src/lua.js');
-const lauxlib = require('../../src/lauxlib.js');
-const lualib = require('../../src/lualib.js');
+const lua = require('../../../src/lua.js');
+const lauxlib = require('../../../src/lauxlib.js');
+const lualib = require('../../../src/lualib.js');
const prefix = `
diff --git a/tests/test-suite/inprogress/coroutine.js b/tests/test-suite/inprogress/coroutine.js
index a66ae7b..1fe25a5 100644
--- a/tests/test-suite/inprogress/coroutine.js
+++ b/tests/test-suite/inprogress/coroutine.js
@@ -4,9 +4,9 @@ const test = require('tape');
global.WEB = false;
-const lua = require('../../src/lua.js');
-const lauxlib = require('../../src/lauxlib.js');
-const lualib = require('../../src/lualib.js');
+const lua = require('../../../src/lua.js');
+const lauxlib = require('../../../src/lauxlib.js');
+const lualib = require('../../../src/lualib.js');
test("[test-suite] coroutine: is main thread", function (t) {
diff --git a/tests/test-suite/inprogress/errors.js b/tests/test-suite/inprogress/errors.js
new file mode 100644
index 0000000..75c6f81
--- /dev/null
+++ b/tests/test-suite/inprogress/errors.js
@@ -0,0 +1,1323 @@
+"use strict";
+
+const test = require('tape');
+
+global.WEB = false;
+
+const lua = require('../../../src/lua.js');
+const lauxlib = require('../../../src/lauxlib.js');
+const lualib = require('../../../src/lualib.js');
+
+
+const prefix = `
+ -- avoid problems with 'strict' module (which may generate other error messages)
+ local mt = getmetatable(_G) or {}
+ local oldmm = mt.__index
+ mt.__index = nil
+
+ local function checkerr (msg, f, ...)
+ local st, err = pcall(f, ...)
+ assert(not st and string.find(err, msg))
+ end
+
+
+ local function doit (s)
+ local f, msg = load(s)
+ if f == nil then return msg end
+ local cond, msg = pcall(f)
+ return (not cond) and msg
+ end
+
+
+ local function checkmessage (prog, msg)
+ local m = doit(prog)
+ assert(string.find(m, msg, 1, true))
+ end
+
+ local function checksyntax (prog, extra, token, line)
+ local msg = doit(prog)
+ if not string.find(token, "^<%a") and not string.find(token, "^char%(")
+ then token = "'"..token.."'" end
+ token = string.gsub(token, "(%p)", "%%%1")
+ local pt = string.format([[^%%[string ".*"%%]:%d: .- near %s$]],
+ line, token)
+ assert(string.find(msg, pt))
+ assert(string.find(msg, msg, 1, true))
+ end
+`;
+
+test("[test-suite] errors: test error message with no extra info", function (t) {
+ let luaCode = `
+ assert(doit("error('hi', 0)") == 'hi')
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: test error message with no info", function (t) {
+ let luaCode = `
+ assert(doit("error()") == nil)
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: test common errors/errors that crashed in the past", function (t) {
+ let luaCode = `
+ assert(doit("table.unpack({}, 1, n=2^30)"))
+ assert(doit("a=math.sin()"))
+ assert(not doit("tostring(1)") and doit("tostring()"))
+ assert(doit"tonumber()")
+ assert(doit"repeat until 1; a")
+ assert(doit"return;;")
+ assert(doit"assert(false)")
+ assert(doit"assert(nil)")
+ assert(doit("function a (... , ...) end"))
+ assert(doit("function a (, ...) end"))
+ assert(doit("local t={}; t = t[#t] + 1"))
+
+ checksyntax([[
+ local a = {4
+
+ ]], "'}' expected (to close '{' at line 1)", "<eof>", 3)
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: tests for better error messages", function (t) {
+ let luaCode = `
+ checkmessage("a = {} + 1", "arithmetic")
+ checkmessage("a = {} | 1", "bitwise operation")
+ checkmessage("a = {} < 1", "attempt to compare")
+ checkmessage("a = {} <= 1", "attempt to compare")
+
+ checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'")
+ checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'")
+ checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
+ assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'"))
+ checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number")
+ checkmessage("a=(1)..{}", "a table value")
+
+ checkmessage("a = #print", "length of a function value")
+ checkmessage("a = #3", "length of a number value")
+
+ aaa = nil
+ checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
+ checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
+ checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
+ checkmessage("local a,b,c; (function () a = b+1 end)()", "upvalue 'b'")
+ assert(not doit"local aaa={bbb={ddd=next}}; aaa.bbb:ddd(nil)")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: upvalues being indexed do not go to the stack", function (t) {
+ let luaCode = `
+ checkmessage("local a,b,cc; (function () a = cc[1] end)()", "upvalue 'cc'")
+ checkmessage("local a,b,cc; (function () a.x = 1 end)()", "upvalue 'a'")
+
+ checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'")
+
+ checkmessage("b=1; local aaa='a'; x=aaa+b", "local 'aaa'")
+ checkmessage("aaa={}; x=3/aaa", "global 'aaa'")
+ checkmessage("aaa='2'; b=nil;x=aaa*b", "global 'b'")
+ checkmessage("aaa={}; x=-aaa", "global 'aaa'")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: short circuit", function (t) {
+ let luaCode = `
+ checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)",
+ "local 'bbbb'")
+ checkmessage("a=1; local a,bbbb=2,3; a = bbbb(1) or a(3)", "local 'bbbb'")
+ checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'")
+ checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value")
+ assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
+ assert(not string.find(doit"aaa={}; (aaa or aaa)()", "'aaa'"))
+
+ checkmessage("print(print < 10)", "function with number")
+ checkmessage("print(print < print)", "two function values")
+ checkmessage("print('10' < 10)", "string with number")
+ checkmessage("print(10 < '23')", "number with string")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: float->integer conversions", function (t) {
+ let luaCode = `
+ checkmessage("local a = 2.0^100; x = a << 2", "local a")
+ checkmessage("local a = 1 >> 2.0^100", "has no integer representation")
+ checkmessage("local a = '10' << 2.0^100", "has no integer representation")
+ checkmessage("local a = 2.0^100 & 1", "has no integer representation")
+ checkmessage("local a = 2.0^100 & '1'", "has no integer representation")
+ checkmessage("local a = 2.0 | 1e40", "has no integer representation")
+ checkmessage("local a = 2e100 ~ 1", "has no integer representation")
+ checkmessage("string.sub('a', 2.0^100)", "has no integer representation")
+ checkmessage("string.rep('a', 3.3)", "has no integer representation")
+ checkmessage("return 6e40 & 7", "has no integer representation")
+ checkmessage("return 34 << 7e30", "has no integer representation")
+ checkmessage("return ~-3e40", "has no integer representation")
+ checkmessage("return ~-3.009", "has no integer representation")
+ checkmessage("return 3.009 & 1", "has no integer representation")
+ checkmessage("return 34 >> {}", "table value")
+ checkmessage("a = 24 // 0", "divide by zero")
+ checkmessage("a = 1 % 0", "'n%0'")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: passing light userdata instead of full userdata", function (t) {
+ let luaCode = `
+ _G.D = debug
+ checkmessage([[
+ -- create light udata
+ local x = D.upvalueid(function () return debug end, 1)
+ D.setuservalue(x, {})
+ ]], "light userdata")
+ _G.D = nil
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: named objects (field '__name')", function (t) {
+ let luaCode = `
+ do
+ checkmessage("math.sin(io.input())", "(number expected, got FILE*)")
+ _G.XX = setmetatable({}, {__name = "My Type"})
+ assert(string.find(tostring(XX), "^My Type"))
+ checkmessage("io.input(XX)", "(FILE* expected, got My Type)")
+ checkmessage("return XX + 1", "on a My Type value")
+ checkmessage("return ~io.stdin", "on a FILE* value")
+ checkmessage("return XX < XX", "two My Type values")
+ checkmessage("return {} < XX", "table with My Type")
+ checkmessage("return XX < io.stdin", "My Type with FILE*")
+ _G.XX = nil
+ end
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: global functions", function (t) {
+ let luaCode = `
+ checkmessage("(io.write or print){}", "io.write")
+ checkmessage("(collectgarbage or print){}", "collectgarbage")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: errors in functions without debug info", function (t) {
+ let luaCode = `
+ do
+ local f = function (a) return a + 1 end
+ f = assert(load(string.dump(f, true)))
+ assert(f(3) == 4)
+ checkerr("^%?:%-1:", f, {})
+
+ -- code with a move to a local var ('OP_MOV A B' with A<B)
+ f = function () local a; a = {}; return a + 2 end
+ -- no debug info (so that 'a' is unknown)
+ f = assert(load(string.dump(f, true)))
+ -- symbolic execution should not get lost
+ checkerr("^%?:%-1:.*table value", f)
+ end
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: tests for field accesses after RK limit", function (t) {
+ let luaCode = `
+ local t = {}
+ for i = 1, 1000 do
+ t[i] = "a = x" .. i
+ end
+ local s = table.concat(t, "; ")
+ t = nil
+ checkmessage(s.."; a = bbb + 1", "global 'bbb'")
+ checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'")
+ checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'")
+ checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: global", function (t) {
+ let luaCode = `
+ checkmessage([[aaa=9
+ repeat until 3==3
+ local x=math.sin(math.cos(3))
+ if math.sin(1) == x then return math.sin(1) end -- tail call
+ local a,b = 1, {
+ {x='a'..'b'..'c', y='b', z=x},
+ {1,2,3,4,5} or 3+3<=3+3,
+ 3+1>3+1,
+ {d = x and aaa[x or y]}}
+ ]], "global 'aaa'")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: field", function (t) {
+ let luaCode = `
+ checkmessage([[
+ local x,y = {},1
+ if math.sin(1) == 0 then return 3 end -- return
+ x.a()]], "field 'a'")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: global insert", function (t) {
+ let luaCode = `
+ checkmessage([[
+ prefix = nil
+ insert = nil
+ while 1 do
+ local a
+ if nil then break end
+ insert(prefix, a)
+ end]], "global 'insert'")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: sin", function (t) {
+ let luaCode = `
+ checkmessage([[ -- tail call
+ return math.sin("a")
+ ]], "'sin'")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: concatenate", function (t) {
+ let luaCode = `
+ checkmessage([[x = print .. "a"]], "concatenate")
+ checkmessage([[x = "a" .. false]], "concatenate")
+ checkmessage([[x = {} .. 2]], "concatenate")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: unknown global", function (t) {
+ let luaCode = `
+ checkmessage([[
+ local Var
+ local function main()
+ NoSuchName (function() Var=0 end)
+ end
+ main()
+ ]], "global 'NoSuchName'")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: __index", function (t) {
+ let luaCode = `
+ a = {}; setmetatable(a, {__index = string})
+ checkmessage("a:sub()", "bad self")
+ checkmessage("string.sub('a', {})", "#2")
+ checkmessage("('a'):sub{}", "#1")
+
+ checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'")
+ checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: tests for errors in coroutines", function (t) {
+ let luaCode = `
+ local function f (n)
+ local c = coroutine.create(f)
+ local a,b = coroutine.resume(c)
+ return b
+ end
+ assert(string.find(f(), "JS stack overflow"))
+
+ checkmessage("coroutine.yield()", "outside a coroutine")
+
+ f = coroutine.wrap(function () table.sort({1,2,3}, coroutine.yield) end)
+ checkerr("yield across", f)
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: testing size of 'source' info", function (t) {
+ let luaCode = `
+ idsize = 60 - 1
+ local function checksize (source)
+ -- syntax error
+ local _, msg = load("x", source)
+ msg = string.match(msg, "^([^:]*):") -- get source (1st part before ':')
+ assert(msg:len() <= idsize)
+ end
+
+ for i = 60 - 10, 60 + 10 do -- check border cases around 60
+ checksize("@" .. string.rep("x", i)) -- file names
+ checksize(string.rep("x", i - 10)) -- string sources
+ checksize("=" .. string.rep("x", i)) -- exact sources
+ end
+
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: testing line error", function (t) {
+ let luaCode = `
+ local function lineerror (s, l)
+ local err,msg = pcall(load(s))
+ local line = string.match(msg, ":(%d+):")
+ assert((line and line+0) == l)
+ end
+
+ lineerror("local a\\n for i=1,'a' do \\n print(i) \\n end", 2)
+ lineerror("\\n local a \\n for k,v in 3 \\n do \\n print(k) \\n end", 3)
+ lineerror("\\n\\n for k,v in \\n 3 \\n do \\n print(k) \\n end", 4)
+ lineerror("function a.x.y ()\\na=a+1\\nend", 1)
+
+ lineerror("a = \\na\\n+\\n{}", 3)
+ lineerror("a = \\n3\\n+\\n(\\n4\\n/\\nprint)", 6)
+ lineerror("a = \\nprint\\n+\\n(\\n4\\n/\\n7)", 3)
+
+ lineerror("a\\n=\\n-\\n\\nprint\\n;", 3)
+
+ lineerror([[
+ a
+ (
+ 23)
+ ]], 1)
+
+ lineerror([[
+ local a = {x = 13}
+ a
+ .
+ x
+ (
+ 23
+ )
+ ]], 2)
+
+ lineerror([[
+ local a = {x = 13}
+ a
+ .
+ x
+ (
+ 23 + a
+ )
+ ]], 6)
+
+ local p = [[
+ function g() f() end
+ function f(x) error('a', X) end
+ g()
+ ]]
+ X=3;lineerror((p), 3)
+ X=0;lineerror((p), nil)
+ X=1;lineerror((p), 2)
+ X=2;lineerror((p), 1)
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: several tests that exhaust the Lua stack", { skip: true }, function (t) {
+ let luaCode = `
+ C = 0
+ local l = debug.getinfo(1, "l").currentline; function y () C=C+1; y() end
+
+ local function checkstackmessage (m)
+ return (string.find(m, "^.-:%d+: stack overflow"))
+ end
+ -- repeated stack overflows (to check stack recovery)
+ assert(checkstackmessage(doit('y()')))
+ print('+')
+ assert(checkstackmessage(doit('y()')))
+ print('+')
+ assert(checkstackmessage(doit('y()')))
+ print('+')
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: error lines in stack overflow", { skip: true }, function (t) {
+ let luaCode = `
+ C = 0
+ local l1
+ local function g(x)
+ l1 = debug.getinfo(x, "l").currentline; y()
+ end
+ local _, stackmsg = xpcall(g, debug.traceback, 1)
+ print('+')
+ local stack = {}
+ for line in string.gmatch(stackmsg, "[^\\n]*") do
+ local curr = string.match(line, ":(%d+):")
+ if curr then table.insert(stack, tonumber(curr)) end
+ end
+ local i=1
+ while stack[i] ~= l1 do
+ assert(stack[i] == l)
+ i = i+1
+ end
+ assert(i > 15)
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: error in error handling", function (t) {
+ let luaCode = `
+ local res, msg = xpcall(error, error)
+ assert(not res and type(msg) == 'string')
+ print('+')
+
+ local function f (x)
+ if x==0 then error('a\\n')
+ else
+ local aux = function () return f(x-1) end
+ local a,b = xpcall(aux, aux)
+ return a,b
+ end
+ end
+ f(3)
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: too many results", { skip: true }, function (t) {
+ let luaCode = `
+ local function loop (x,y,z) return 1 + loop(x, y, z) end
+
+ local res, msg = xpcall(loop, function (m)
+ assert(string.find(m, "stack overflow"))
+ checkerr("error handling", loop)
+ assert(math.sin(0) == 0)
+ return 15
+ end)
+ assert(msg == 15)
+
+ local f = function ()
+ for i = 999900, 1000000, 1 do table.unpack({}, 1, i) end
+ end
+ checkerr("too many results", f)
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: non string messages", function (t) {
+ let luaCode = `
+ do
+ -- non string messages
+ local t = {}
+ local res, msg = pcall(function () error(t) end)
+ assert(not res and msg == t)
+
+ res, msg = pcall(function () error(nil) end)
+ assert(not res and msg == nil)
+
+ local function f() error{msg='x'} end
+ res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end)
+ assert(msg.msg == 'xy')
+
+ -- 'assert' with extra arguments
+ res, msg = pcall(assert, false, "X", t)
+ assert(not res and msg == "X")
+
+ -- 'assert' with no message
+ res, msg = pcall(function () assert(false) end)
+ local line = string.match(msg, "%w+%.lua:(%d+): assertion failed!$")
+ assert(tonumber(line) == debug.getinfo(1, "l").currentline - 2)
+
+ -- 'assert' with non-string messages
+ res, msg = pcall(assert, false, t)
+ assert(not res and msg == t)
+
+ res, msg = pcall(assert, nil, nil)
+ assert(not res and msg == nil)
+
+ -- 'assert' without arguments
+ res, msg = pcall(assert)
+ assert(not res and string.find(msg, "value expected"))
+ end
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: xpcall with arguments", function (t) {
+ let luaCode = `
+ a, b, c = xpcall(string.find, error, "alo", "al")
+ assert(a and b == 1 and c == 2)
+ a, b, c = xpcall(string.find, function (x) return {} end, true, "al")
+ assert(not a and type(b) == "table" and c == nil)
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: testing tokens in error messages", function (t) {
+ let luaCode = `
+ checksyntax("syntax error", "", "error", 1)
+ checksyntax("1.000", "", "1.000", 1)
+ checksyntax("[[a]]", "", "[[a]]", 1)
+ checksyntax("'aa'", "", "'aa'", 1)
+ checksyntax("while << do end", "", "<<", 1)
+ checksyntax("for >> do end", "", ">>", 1)
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: test invalid non-printable char in a chunk", function (t) {
+ let luaCode = `
+ checksyntax("a\\1a = 1", "", "<\\\\1>", 1)
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: test 255 as first char in a chunk", function (t) {
+ let luaCode = `
+ checksyntax("\\255a = 1", "", "<\\\\255>", 1)
+
+ doit('I = load("a=9+"); a=3')
+ assert(a==3 and I == nil)
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: lots of errors", function (t) {
+ let luaCode = `
+ lim = 1000
+ if _soft then lim = 100 end
+ for i=1,lim do
+ doit('a = ')
+ doit('a = 4+nil')
+ end
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: testing syntax limits", function (t) {
+ let luaCode = `
+ local maxClevel = 200 -- LUAI_MAXCCALLS (in llimits.h)
+
+ local function testrep (init, rep, close, repc)
+ local s = init .. string.rep(rep, maxClevel - 10) .. close ..
+ string.rep(repc, maxClevel - 10)
+ assert(load(s)) -- 190 levels is OK
+ s = init .. string.rep(rep, maxClevel + 1)
+ checkmessage(s, "too many C levels")
+ end
+
+ testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment
+ testrep("local a; a=", "{", "0", "}")
+ testrep("local a; a=", "(", "2", ")")
+ testrep("local a; ", "a(", "2", ")")
+ testrep("", "do ", "", " end")
+ testrep("", "while a do ", "", " end")
+ testrep("local a; ", "if a then else ", "", " end")
+ testrep("", "function foo () ", "", " end")
+ testrep("local a; a=", "a..", "a", "")
+ testrep("local a; a=", "a^", "a", "")
+
+ checkmessage("a = f(x" .. string.rep(",x", 260) .. ")", "too many registers")
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: upvalues limit", function (t) {
+ let luaCode = `
+ local lim = 127
+ local s = "local function fooA ()\\n local "
+ for j = 1,lim do
+ s = s.."a"..j..", "
+ end
+ s = s.."b,c\\n"
+ s = s.."local function fooB ()\\n local "
+ for j = 1,lim do
+ s = s.."b"..j..", "
+ end
+ s = s.."b\\n"
+ s = s.."function fooC () return b+c"
+ local c = 1+2
+ for j = 1,lim do
+ s = s.."+a"..j.."+b"..j
+ c = c + 2
+ end
+ s = s.."\\nend end end"
+ local a,b = load(s)
+ assert(c > 255 and string.find(b, "too many upvalues") and
+ string.find(b, "line 5"))
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
+
+
+test("[test-suite] errors: local variables limit", function (t) {
+ let luaCode = `
+ s = "\\nfunction foo ()\\n local "
+ for j = 1,300 do
+ s = s.."a"..j..", "
+ end
+ s = s.."b\\n"
+ local a,b = load(s)
+ assert(string.find(b, "line 2") and string.find(b, "too many local variables"))
+ `, L;
+
+ t.plan(2);
+
+ t.doesNotThrow(function () {
+
+ L = lauxlib.luaL_newstate();
+
+ lualib.luaL_openlibs(L);
+
+ lauxlib.luaL_loadstring(L, lua.to_luastring(prefix + luaCode));
+
+ }, "Lua program loaded without error");
+
+ t.doesNotThrow(function () {
+
+ lua.lua_call(L, 0, -1);
+
+ }, "Lua program ran without error");
+
+});
diff --git a/tests/test-suite/inprogress/goto.js b/tests/test-suite/inprogress/goto.js
index 696ab16..d043d93 100644
--- a/tests/test-suite/inprogress/goto.js
+++ b/tests/test-suite/inprogress/goto.js
@@ -4,9 +4,9 @@ const test = require('tape');
global.WEB = false;
-const lua = require('../../src/lua.js');
-const lauxlib = require('../../src/lauxlib.js');
-const lualib = require('../../src/lualib.js');
+const lua = require('../../../src/lua.js');
+const lauxlib = require('../../../src/lauxlib.js');
+const lualib = require('../../../src/lualib.js');
test("[test-suite] goto: error messages", function (t) {
diff --git a/tests/test-suite/inprogress/math.js b/tests/test-suite/inprogress/math.js
index 463905f..776fa3c 100644
--- a/tests/test-suite/inprogress/math.js
+++ b/tests/test-suite/inprogress/math.js
@@ -4,9 +4,9 @@ const test = require('tape');
global.WEB = false;
-const lua = require('../../src/lua.js');
-const lauxlib = require('../../src/lauxlib.js');
-const lualib = require('../../src/lualib.js');
+const lua = require('../../../src/lua.js');
+const lauxlib = require('../../../src/lauxlib.js');
+const lualib = require('../../../src/lualib.js');
const prefix = `
diff --git a/tests/test-suite/inprogress/pm.js b/tests/test-suite/inprogress/pm.js
index 1a45752..e9510c5 100644
--- a/tests/test-suite/inprogress/pm.js
+++ b/tests/test-suite/inprogress/pm.js
@@ -4,9 +4,9 @@ const test = require('tape');
global.WEB = false;
-const lua = require('../../src/lua.js');
-const lauxlib = require('../../src/lauxlib.js');
-const lualib = require('../../src/lualib.js');
+const lua = require('../../../src/lua.js');
+const lauxlib = require('../../../src/lauxlib.js');
+const lualib = require('../../../src/lualib.js');
test("[test-suite] pm: pattern matching", function (t) {
diff --git a/tests/test-suite/inprogress/sort.js b/tests/test-suite/inprogress/sort.js
index 3c9b8d0..fc0762f 100644
--- a/tests/test-suite/inprogress/sort.js
+++ b/tests/test-suite/inprogress/sort.js
@@ -4,9 +4,9 @@ const test = require('tape');
global.WEB = false;
-const lua = require('../../src/lua.js');
-const lauxlib = require('../../src/lauxlib.js');
-const lualib = require('../../src/lualib.js');
+const lua = require('../../../src/lua.js');
+const lauxlib = require('../../../src/lauxlib.js');
+const lualib = require('../../../src/lualib.js');
const prefix = `
diff --git a/tests/test-suite/inprogress/tpack.js b/tests/test-suite/inprogress/tpack.js
index 530c421..bff5b4b 100644
--- a/tests/test-suite/inprogress/tpack.js
+++ b/tests/test-suite/inprogress/tpack.js
@@ -4,9 +4,9 @@ const test = require('tape');
global.WEB = false;
-const lua = require('../../src/lua.js');
-const lauxlib = require('../../src/lauxlib.js');
-const lualib = require('../../src/lualib.js');
+const lua = require('../../../src/lua.js');
+const lauxlib = require('../../../src/lauxlib.js');
+const lualib = require('../../../src/lualib.js');
const prefix = `
diff --git a/tests/test-suite/inprogress/utf8.js b/tests/test-suite/inprogress/utf8.js
index 3e32aec..252ac8b 100644
--- a/tests/test-suite/inprogress/utf8.js
+++ b/tests/test-suite/inprogress/utf8.js
@@ -4,9 +4,9 @@ const test = require('tape');
global.WEB = false;
-const lua = require('../../src/lua.js');
-const lauxlib = require('../../src/lauxlib.js');
-const lualib = require('../../src/lualib.js');
+const lua = require('../../../src/lua.js');
+const lauxlib = require('../../../src/lauxlib.js');
+const lualib = require('../../../src/lualib.js');
const prefix = `