From 2dbacc0031513a110c3ea62afb086020184150e7 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Thu, 13 Apr 2017 12:35:12 +1000 Subject: lua-cli: Fix missing settop() --- tests/manual-tests/lua-cli.js | 1 + 1 file changed, 1 insertion(+) (limited to 'tests') diff --git a/tests/manual-tests/lua-cli.js b/tests/manual-tests/lua-cli.js index de64359..a8f1928 100755 --- a/tests/manual-tests/lua-cli.js +++ b/tests/manual-tests/lua-cli.js @@ -40,6 +40,7 @@ for (;;) { } if (status !== lua.thread_status.LUA_OK) { lauxlib.lua_writestringerror(`${lapi.lua_tojsstring(L, -1)}\n`); + lapi.lua_settop(L, 0); continue; } if (lapi.lua_pcall(L, 0, lua.LUA_MULTRET, 0) !== lua.thread_status.LUA_OK) { -- cgit v1.2.3-70-g09d2 From 9aedb17371c7d77b4577c496654b9edf8f5bddb1 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Thu, 13 Apr 2017 12:41:30 +1000 Subject: lua-cli: Introduce support for multiline --- tests/manual-tests/lua-cli.js | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tests') diff --git a/tests/manual-tests/lua-cli.js b/tests/manual-tests/lua-cli.js index a8f1928..f93f306 100755 --- a/tests/manual-tests/lua-cli.js +++ b/tests/manual-tests/lua-cli.js @@ -38,6 +38,15 @@ for (;;) { status = lua.thread_status.LUA_OK; } } + while (status === lua.thread_status.LUA_ERRSYNTAX && lapi.lua_tojsstring(L, -1).endsWith("")) { + /* continuation */ + lapi.lua_pop(L, 1); + input += "\n" + readlineSync.prompt({ + prompt: '>> ' + }); + let buffer = lua.to_luastring(input); + status = lauxlib.luaL_loadbuffer(L, buffer, buffer.length, stdin); + } if (status !== lua.thread_status.LUA_OK) { lauxlib.lua_writestringerror(`${lapi.lua_tojsstring(L, -1)}\n`); lapi.lua_settop(L, 0); -- cgit v1.2.3-70-g09d2 From cfd6ac4b61f3d175725620895120b7480056bafd Mon Sep 17 00:00:00 2001 From: daurnimator Date: Thu, 13 Apr 2017 12:46:03 +1000 Subject: lua-cli: Add support for configurable prompts --- tests/manual-tests/lua-cli.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/tests/manual-tests/lua-cli.js b/tests/manual-tests/lua-cli.js index f93f306..0b5519b 100755 --- a/tests/manual-tests/lua-cli.js +++ b/tests/manual-tests/lua-cli.js @@ -8,11 +8,9 @@ const linit = require('../../src/linit.js'); const fs = require('fs'); const readlineSync = require('readline-sync'); -readlineSync.setDefaultOptions({ - prompt: '> ' -}); - const stdin = lua.to_luastring("=stdin"); +const _PROMPT = lua.to_luastring("_PROMPT"); +const _PROMPT2 = lua.to_luastring("_PROMPT2"); const L = lauxlib.luaL_newstate(); @@ -21,7 +19,11 @@ linit.luaL_openlibs(L); console.log(lua.FENGARI_COPYRIGHT); for (;;) { - let input = readlineSync.prompt(); + lapi.lua_getglobal(L, _PROMPT); + let input = readlineSync.prompt({ + prompt: lapi.lua_tojsstring(L, -1) || '> ' + }); + lapi.lua_pop(L, 1); if (input.length === 0) continue; @@ -41,9 +43,11 @@ for (;;) { while (status === lua.thread_status.LUA_ERRSYNTAX && lapi.lua_tojsstring(L, -1).endsWith("")) { /* continuation */ lapi.lua_pop(L, 1); + lapi.lua_getglobal(L, _PROMPT2); input += "\n" + readlineSync.prompt({ - prompt: '>> ' + prompt: lapi.lua_tojsstring(L, -1) || '>> ' }); + lapi.lua_pop(L, 1); let buffer = lua.to_luastring(input); status = lauxlib.luaL_loadbuffer(L, buffer, buffer.length, stdin); } -- cgit v1.2.3-70-g09d2 From d0b19d0a978b78d3fb4e6e5842af13736f58b316 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Thu, 13 Apr 2017 12:59:16 +1000 Subject: lua-cli: Run LUA_INIT if set --- tests/manual-tests/lua-cli.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'tests') diff --git a/tests/manual-tests/lua-cli.js b/tests/manual-tests/lua-cli.js index 0b5519b..e32067e 100755 --- a/tests/manual-tests/lua-cli.js +++ b/tests/manual-tests/lua-cli.js @@ -16,6 +16,24 @@ const L = lauxlib.luaL_newstate(); linit.luaL_openlibs(L); +let init = process.env["LUA_INIT"+lua.LUA_VERSUFFIX] || process.env["LUA_INIT"]; +if (init) { + let status; + if (init[0] === "@") { + status = lauxlib.luaL_loadfile(L, lua.to_luastring(init.substring(1))); + } else { + status = lauxlib.luaL_loadstring(L, lua.to_luastring(init)); + } + if (status === lua.thread_status.LUA_OK) { + status = lapi.lua_pcall(L, 0, 0, 0); + } + if (status !== lua.thread_status.LUA_OK) { + lauxlib.lua_writestringerror(`${lapi.lua_tojsstring(L, -1)}\n`); + lapi.lua_pop(L, 1); + return process.exit(1); + } +} + console.log(lua.FENGARI_COPYRIGHT); for (;;) { -- cgit v1.2.3-70-g09d2 From e03e55fb7d5dff8f2c7e64e9b35afb26c4665a0b Mon Sep 17 00:00:00 2001 From: daurnimator Date: Thu, 13 Apr 2017 14:19:31 +1000 Subject: lua-cli: Create 'arg' table --- tests/manual-tests/lua-cli.js | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tests') diff --git a/tests/manual-tests/lua-cli.js b/tests/manual-tests/lua-cli.js index e32067e..0b097f8 100755 --- a/tests/manual-tests/lua-cli.js +++ b/tests/manual-tests/lua-cli.js @@ -14,8 +14,18 @@ const _PROMPT2 = lua.to_luastring("_PROMPT2"); const L = lauxlib.luaL_newstate(); +let script = 2; // Where to start args from + linit.luaL_openlibs(L); +/* create 'arg' table */ +lapi.lua_createtable(L, process.argv.length - (script + 1), script + 1); +for (let i = 0; i < process.argv.length; i++) { + lapi.lua_pushliteral(L, process.argv[i]); + lapi.lua_seti(L, -2, i - script); /* TODO: rawseti */ +} +lapi.lua_setglobal(L, lua.to_luastring("arg")); + let init = process.env["LUA_INIT"+lua.LUA_VERSUFFIX] || process.env["LUA_INIT"]; if (init) { let status; -- cgit v1.2.3-70-g09d2 From a0f96081d3533d795c7a1575eb08837a3b0d26d7 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Thu, 13 Apr 2017 15:14:05 +1000 Subject: lua-cli: Factor out into same functions as lua.c --- tests/manual-tests/lua-cli.js | 88 ++++++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 31 deletions(-) (limited to 'tests') diff --git a/tests/manual-tests/lua-cli.js b/tests/manual-tests/lua-cli.js index 0b097f8..b71a576 100755 --- a/tests/manual-tests/lua-cli.js +++ b/tests/manual-tests/lua-cli.js @@ -12,6 +12,35 @@ 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.thread_status.LUA_OK) { + lauxlib.lua_writestringerror(`${lapi.lua_tojsstring(L, -1)}\n`); + lapi.lua_pop(L, 1); + } + return status; +}; + +const docall = function(L, narg, nres) { + let status = lapi.lua_pcall(L, narg, nres, 0); + return status; +}; + +const dochunk = function(L, status) { + if (status === lua.thread_status.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 L = lauxlib.luaL_newstate(); let script = 2; // Where to start args from @@ -26,21 +55,23 @@ for (let i = 0; i < process.argv.length; i++) { } lapi.lua_setglobal(L, lua.to_luastring("arg")); -let init = process.env["LUA_INIT"+lua.LUA_VERSUFFIX] || process.env["LUA_INIT"]; -if (init) { - let status; - if (init[0] === "@") { - status = lauxlib.luaL_loadfile(L, lua.to_luastring(init.substring(1))); - } else { - status = lauxlib.luaL_loadstring(L, lua.to_luastring(init)); - } - if (status === lua.thread_status.LUA_OK) { - status = lapi.lua_pcall(L, 0, 0, 0); +{ + let name = "LUA_INIT"+lua.LUA_VERSUFFIX; + let init = process.env[name]; + if (!init) { + name = "LUA_INIT"; + init = process.env[name]; } - if (status !== lua.thread_status.LUA_OK) { - lauxlib.lua_writestringerror(`${lapi.lua_tojsstring(L, -1)}\n`); - lapi.lua_pop(L, 1); - return process.exit(1); + if (init) { + let status; + if (init[0] === '@') { + status = dofile(L, init.substring(1)); + } else { + status = dostring(L, init, name); + } + if (status !== lua.thread_status.LUA_OK) { + return process.exit(1); + } } } @@ -79,25 +110,20 @@ for (;;) { let buffer = lua.to_luastring(input); status = lauxlib.luaL_loadbuffer(L, buffer, buffer.length, stdin); } - if (status !== lua.thread_status.LUA_OK) { - lauxlib.lua_writestringerror(`${lapi.lua_tojsstring(L, -1)}\n`); - lapi.lua_settop(L, 0); - continue; - } - if (lapi.lua_pcall(L, 0, lua.LUA_MULTRET, 0) !== lua.thread_status.LUA_OK) { - lauxlib.lua_writestringerror(`${lapi.lua_tojsstring(L, -1)}\n`); - lapi.lua_settop(L, 0); - continue; + if (status === lua.thread_status.LUA_OK) { + status = docall(L, 0, lua.LUA_MULTRET); } - let n = lapi.lua_gettop(L); - if (n > 0) { /* any result to be printed? */ - lapi.lua_getglobal(L, lua.to_luastring("print")); - lapi.lua_insert(L, 1); - if (lapi.lua_pcall(L, n, 0, 0) != lua.thread_status.LUA_OK) { - lauxlib.lua_writestringerror(`error calling 'print' (${lapi.lua_tojsstring(L, -1)})\n`); - lapi.lua_settop(L, 0); - continue; + if (status === lua.thread_status.LUA_OK) { + let n = lapi.lua_gettop(L); + if (n > 0) { /* any result to be printed? */ + lapi.lua_getglobal(L, lua.to_luastring("print")); + lapi.lua_insert(L, 1); + if (lapi.lua_pcall(L, n, 0, 0) != lua.thread_status.LUA_OK) { + lauxlib.lua_writestringerror(`error calling 'print' (${lapi.lua_tojsstring(L, -1)})\n`); + } } + } else { + report(L, status); } lapi.lua_settop(L, 0); /* remove eventual returns */ } -- cgit v1.2.3-70-g09d2 From 006badf9d13971010384340ff786c1cd62c268f6 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Thu, 13 Apr 2017 16:18:32 +1000 Subject: lua-cli: Add command line options --- tests/manual-tests/lua-cli.js | 242 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 199 insertions(+), 43 deletions(-) (limited to 'tests') diff --git a/tests/manual-tests/lua-cli.js b/tests/manual-tests/lua-cli.js index b71a576..5bbf5cd 100755 --- a/tests/manual-tests/lua-cli.js +++ b/tests/manual-tests/lua-cli.js @@ -41,13 +41,110 @@ const dostring = function(L, s, name) { return dochunk(L, lauxlib.luaL_loadbuffer(L, buffer, buffer.length, lua.to_luastring(name))); }; +const dolibrary = function(L, name) { + lapi.lua_getglobal(L, lua.to_luastring("require")); + lapi.lua_pushliteral(L, name); + let status = docall(L, 1, 1); /* call 'require(name)' */ + if (status === lua.thread_status.LUA_OK) + lapi.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 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. */ + lapi.lua_pushboolean(L, 1); + lapi.lua_setfield(L, lua.LUA_REGISTRYINDEX, lua.to_luastring("LUA_NOENV")); +} + +/* open standard libraries */ linit.luaL_openlibs(L); -/* create 'arg' table */ +/* create table 'arg' */ lapi.lua_createtable(L, process.argv.length - (script + 1), script + 1); for (let i = 0; i < process.argv.length; i++) { lapi.lua_pushliteral(L, process.argv[i]); @@ -55,7 +152,8 @@ for (let i = 0; i < process.argv.length; i++) { } lapi.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) { @@ -75,55 +173,113 @@ lapi.lua_setglobal(L, lua.to_luastring("arg")); } } -console.log(lua.FENGARI_COPYRIGHT); - -for (;;) { - lapi.lua_getglobal(L, _PROMPT); - let input = readlineSync.prompt({ - prompt: lapi.lua_tojsstring(L, -1) || '> ' - }); - lapi.lua_pop(L, 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.thread_status.LUA_OK) { + return process.exit(1); + } + } +} - if (input.length === 0) - continue; +const pushargs = function(L) { + if (lapi.lua_getglobal(L, lua.to_luastring("arg")) !== lua.constant_types.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++) + lapi.lua_rawgeti(L, -i, i); + lapi.lua_remove(L, -i); + return n; +}; +const handle_script = function(L, argv) { + let fname = argv[0]; let status; - { - let buffer = lua.to_luastring("return " + input); - status = lauxlib.luaL_loadbuffer(L, buffer, buffer.length, stdin); - } - if (status !== lua.thread_status.LUA_OK) { - lapi.lua_pop(L, 1); - let buffer = lua.to_luastring(input); - if (lauxlib.luaL_loadbuffer(L, buffer, buffer.length, stdin) === lua.thread_status.LUA_OK) { - status = lua.thread_status.LUA_OK; - } + if (fname === "-" && argv[-1] !== "--") + fname = void 0; /* stdin */ + status = lauxlib.luaL_loadfile(L, lua.to_luastring(fname)); + if (status === lua.thread_status.LUA_OK) { + let n = pushargs(L); /* push arguments to script */ + status = docall(L, n, lua.LUA_MULTRET); } - while (status === lua.thread_status.LUA_ERRSYNTAX && lapi.lua_tojsstring(L, -1).endsWith("")) { - /* continuation */ - lapi.lua_pop(L, 1); - lapi.lua_getglobal(L, _PROMPT2); - input += "\n" + readlineSync.prompt({ - prompt: lapi.lua_tojsstring(L, -1) || '>> ' + return report(L, status); +}; + +const doREPL = function(L) { + for (;;) { + lapi.lua_getglobal(L, _PROMPT); + let input = readlineSync.prompt({ + prompt: lapi.lua_tojsstring(L, -1) || '> ' }); lapi.lua_pop(L, 1); - let buffer = lua.to_luastring(input); - status = lauxlib.luaL_loadbuffer(L, buffer, buffer.length, stdin); - } - if (status === lua.thread_status.LUA_OK) { - status = docall(L, 0, lua.LUA_MULTRET); - } - if (status === lua.thread_status.LUA_OK) { - let n = lapi.lua_gettop(L); - if (n > 0) { /* any result to be printed? */ - lapi.lua_getglobal(L, lua.to_luastring("print")); - lapi.lua_insert(L, 1); - if (lapi.lua_pcall(L, n, 0, 0) != lua.thread_status.LUA_OK) { - lauxlib.lua_writestringerror(`error calling 'print' (${lapi.lua_tojsstring(L, -1)})\n`); + + 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.thread_status.LUA_OK) { + lapi.lua_pop(L, 1); + let buffer = lua.to_luastring(input); + if (lauxlib.luaL_loadbuffer(L, buffer, buffer.length, stdin) === lua.thread_status.LUA_OK) { + status = lua.thread_status.LUA_OK; } } + while (status === lua.thread_status.LUA_ERRSYNTAX && lapi.lua_tojsstring(L, -1).endsWith("")) { + /* continuation */ + lapi.lua_pop(L, 1); + lapi.lua_getglobal(L, _PROMPT2); + input += "\n" + readlineSync.prompt({ + prompt: lapi.lua_tojsstring(L, -1) || '>> ' + }); + lapi.lua_pop(L, 1); + let buffer = lua.to_luastring(input); + status = lauxlib.luaL_loadbuffer(L, buffer, buffer.length, stdin); + } + if (status === lua.thread_status.LUA_OK) { + status = docall(L, 0, lua.LUA_MULTRET); + } + if (status === lua.thread_status.LUA_OK) { + let n = lapi.lua_gettop(L); + if (n > 0) { /* any result to be printed? */ + lapi.lua_getglobal(L, lua.to_luastring("print")); + lapi.lua_insert(L, 1); + if (lapi.lua_pcall(L, n, 0, 0) != lua.thread_status.LUA_OK) { + lauxlib.lua_writestringerror(`error calling 'print' (${lapi.lua_tojsstring(L, -1)})\n`); + } + } + } else { + report(L, status); + } + lapi.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.thread_status.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 { - report(L, status); + dofile(L, null); } - lapi.lua_settop(L, 0); /* remove eventual returns */ } -- cgit v1.2.3-70-g09d2 From 4105fee42aa927c4da8ddd7b2e51b9f55202ddeb Mon Sep 17 00:00:00 2001 From: daurnimator Date: Wed, 19 Apr 2017 17:46:17 +1000 Subject: lua-cli: Pass null to luaL_loadfile for stdin --- tests/manual-tests/lua-cli.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tests') diff --git a/tests/manual-tests/lua-cli.js b/tests/manual-tests/lua-cli.js index 5bbf5cd..f11e833 100755 --- a/tests/manual-tests/lua-cli.js +++ b/tests/manual-tests/lua-cli.js @@ -208,8 +208,10 @@ const handle_script = function(L, argv) { let fname = argv[0]; let status; if (fname === "-" && argv[-1] !== "--") - fname = void 0; /* stdin */ - status = lauxlib.luaL_loadfile(L, lua.to_luastring(fname)); + fname = null; /* stdin */ + else + fname = lua.to_luastring(fname); + status = lauxlib.luaL_loadfile(L, fname); if (status === lua.thread_status.LUA_OK) { let n = pushargs(L); /* push arguments to script */ status = docall(L, n, lua.LUA_MULTRET); -- cgit v1.2.3-70-g09d2