From 464658b16a1a539fd590e1696bfcfb572a77fe13 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Tue, 6 Mar 2018 17:30:17 -0300 Subject: [PATCH] better modularization of the code for the REPL --- lua.c | 401 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 203 insertions(+), 198 deletions(-) diff --git a/lua.c b/lua.c index b0e7e1b9..2e95c40b 100644 --- a/lua.c +++ b/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.232 2017/05/24 21:11:19 roberto Exp roberto $ +** $Id: lua.c,v 1.233 2018/02/06 15:32:36 roberto Exp roberto $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -21,20 +21,10 @@ #include "lualib.h" - -#if !defined(LUA_PROMPT) -#define LUA_PROMPT "> " -#define LUA_PROMPT2 ">> " -#endif - #if !defined(LUA_PROGNAME) #define LUA_PROGNAME "lua" #endif -#if !defined(LUA_MAXINPUT) -#define LUA_MAXINPUT 512 -#endif - #if !defined(LUA_INIT_VAR) #define LUA_INIT_VAR "LUA_INIT" #endif @@ -42,65 +32,6 @@ #define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX -/* -** lua_stdin_is_tty detects whether the standard input is a 'tty' (that -** is, whether we're running lua interactively). -*/ -#if !defined(lua_stdin_is_tty) /* { */ - -#if defined(LUA_USE_POSIX) /* { */ - -#include -#define lua_stdin_is_tty() isatty(0) - -#elif defined(LUA_USE_WINDOWS) /* }{ */ - -#include -#include - -#define lua_stdin_is_tty() _isatty(_fileno(stdin)) - -#else /* }{ */ - -/* ISO C definition */ -#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ - -#endif /* } */ - -#endif /* } */ - - -/* -** lua_readline defines how to show a prompt and then read a line from -** the standard input. -** lua_saveline defines how to "save" a read line in a "history". -** lua_freeline defines how to free a line read by lua_readline. -*/ -#if !defined(lua_readline) /* { */ - -#if defined(LUA_USE_READLINE) /* { */ - -#include -#include -#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) -#define lua_saveline(L,line) ((void)L, add_history(line)) -#define lua_freeline(L,b) ((void)L, free(b)) - -#else /* }{ */ - -#define lua_readline(L,b,p) \ - ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ - fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ -#define lua_saveline(L,line) { (void)L; (void)line; } -#define lua_freeline(L,b) { (void)L; (void)b; } - -#endif /* } */ - -#endif /* } */ - - - - static lua_State *globalL = NULL; static const char *progname = LUA_PROGNAME; @@ -268,6 +199,207 @@ static int dolibrary (lua_State *L, const char *name) { } +/* +** Push on the stack the contents of table 'arg' from 1 to #arg +*/ +static int pushargs (lua_State *L) { + int i, n; + if (lua_getglobal(L, "arg") != LUA_TTABLE) + luaL_error(L, "'arg' is not a table"); + n = (int)luaL_len(L, -1); + luaL_checkstack(L, n + 3, "too many arguments to script"); + for (i = 1; i <= n; i++) + lua_rawgeti(L, -i, i); + lua_remove(L, -i); /* remove table from the stack */ + return n; +} + + +static int handle_script (lua_State *L, char **argv) { + int status; + const char *fname = argv[0]; + if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0) + fname = NULL; /* stdin */ + status = luaL_loadfile(L, fname); + if (status == LUA_OK) { + int n = pushargs(L); /* push arguments to script */ + status = docall(L, n, LUA_MULTRET); + } + return report(L, status); +} + + +/* bits of various argument indicators in 'args' */ +#define has_error 1 /* bad option */ +#define has_i 2 /* -i */ +#define has_v 4 /* -v */ +#define has_e 8 /* -e */ +#define has_E 16 /* -E */ + + +/* +** Traverses all arguments from 'argv', returning a mask with those +** needed before running any Lua code (or an error code if it finds +** any invalid argument). 'first' returns the first not-handled argument +** (either the script name or a bad argument in case of error). +*/ +static int collectargs (char **argv, int *first) { + int args = 0; + int i; + for (i = 1; argv[i] != NULL; i++) { + *first = i; + if (argv[i][0] != '-') /* not an option? */ + return args; /* stop handling options */ + switch (argv[i][1]) { /* else check option */ + case '-': /* '--' */ + if (argv[i][2] != '\0') /* extra characters after '--'? */ + return has_error; /* invalid option */ + *first = i + 1; + return args; + case '\0': /* '-' */ + return args; /* script "name" is '-' */ + case 'E': + if (argv[i][2] != '\0') /* extra characters after 1st? */ + return has_error; /* invalid option */ + args |= has_E; + break; + case 'i': + args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */ + case 'v': + if (argv[i][2] != '\0') /* extra characters after 1st? */ + return has_error; /* invalid option */ + args |= has_v; + break; + case 'e': + args |= has_e; /* FALLTHROUGH */ + case 'l': /* both options need an argument */ + if (argv[i][2] == '\0') { /* no concatenated argument? */ + i++; /* try next 'argv' */ + if (argv[i] == NULL || argv[i][0] == '-') + return has_error; /* no next argument or it is another option */ + } + break; + default: /* invalid option */ + return has_error; + } + } + *first = i; /* no script name */ + return args; +} + + +/* +** Processes options 'e' and 'l', which involve running Lua code. +** Returns 0 if some code raises an error. +*/ +static int runargs (lua_State *L, char **argv, int n) { + int i; + for (i = 1; i < n; i++) { + int option = argv[i][1]; + lua_assert(argv[i][0] == '-'); /* already checked */ + if (option == 'e' || option == 'l') { + int status; + const char *extra = argv[i] + 2; /* both options need an argument */ + if (*extra == '\0') extra = argv[++i]; + lua_assert(extra != NULL); + status = (option == 'e') + ? dostring(L, extra, "=(command line)") + : dolibrary(L, extra); + if (status != LUA_OK) return 0; + } + } + return 1; +} + + +static int handle_luainit (lua_State *L) { + const char *name = "=" LUA_INITVARVERSION; + const char *init = getenv(name + 1); + if (init == NULL) { + name = "=" LUA_INIT_VAR; + init = getenv(name + 1); /* try alternative name */ + } + if (init == NULL) return LUA_OK; + else if (init[0] == '@') + return dofile(L, init+1); + else + return dostring(L, init, name); +} + + +/* +** {================================================================== +** Read-Eval-Print Loop (REPL) +** =================================================================== +*/ + +#if !defined(LUA_PROMPT) +#define LUA_PROMPT "> " +#define LUA_PROMPT2 ">> " +#endif + +#if !defined(LUA_MAXINPUT) +#define LUA_MAXINPUT 512 +#endif + + +/* +** lua_stdin_is_tty detects whether the standard input is a 'tty' (that +** is, whether we're running lua interactively). +*/ +#if !defined(lua_stdin_is_tty) /* { */ + +#if defined(LUA_USE_POSIX) /* { */ + +#include +#define lua_stdin_is_tty() isatty(0) + +#elif defined(LUA_USE_WINDOWS) /* }{ */ + +#include +#include + +#define lua_stdin_is_tty() _isatty(_fileno(stdin)) + +#else /* }{ */ + +/* ISO C definition */ +#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ + +#endif /* } */ + +#endif /* } */ + + +/* +** lua_readline defines how to show a prompt and then read a line from +** the standard input. +** lua_saveline defines how to "save" a read line in a "history". +** lua_freeline defines how to free a line read by lua_readline. +*/ +#if !defined(lua_readline) /* { */ + +#if defined(LUA_USE_READLINE) /* { */ + +#include +#include +#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_saveline(L,line) ((void)L, add_history(line)) +#define lua_freeline(L,b) ((void)L, free(b)) + +#else /* }{ */ + +#define lua_readline(L,b,p) \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ +#define lua_saveline(L,line) { (void)L; (void)line; } +#define lua_freeline(L,b) { (void)L; (void)b; } + +#endif /* } */ + +#endif /* } */ + + /* ** Returns the string to be used as a prompt by the interpreter. */ @@ -418,134 +550,7 @@ static void doREPL (lua_State *L) { progname = oldprogname; } - -/* -** Push on the stack the contents of table 'arg' from 1 to #arg -*/ -static int pushargs (lua_State *L) { - int i, n; - if (lua_getglobal(L, "arg") != LUA_TTABLE) - luaL_error(L, "'arg' is not a table"); - n = (int)luaL_len(L, -1); - luaL_checkstack(L, n + 3, "too many arguments to script"); - for (i = 1; i <= n; i++) - lua_rawgeti(L, -i, i); - lua_remove(L, -i); /* remove table from the stack */ - return n; -} - - -static int handle_script (lua_State *L, char **argv) { - int status; - const char *fname = argv[0]; - if (strcmp(fname, "-") == 0 && strcmp(argv[-1], "--") != 0) - fname = NULL; /* stdin */ - status = luaL_loadfile(L, fname); - if (status == LUA_OK) { - int n = pushargs(L); /* push arguments to script */ - status = docall(L, n, LUA_MULTRET); - } - return report(L, status); -} - - - -/* bits of various argument indicators in 'args' */ -#define has_error 1 /* bad option */ -#define has_i 2 /* -i */ -#define has_v 4 /* -v */ -#define has_e 8 /* -e */ -#define has_E 16 /* -E */ - -/* -** Traverses all arguments from 'argv', returning a mask with those -** needed before running any Lua code (or an error code if it finds -** any invalid argument). 'first' returns the first not-handled argument -** (either the script name or a bad argument in case of error). -*/ -static int collectargs (char **argv, int *first) { - int args = 0; - int i; - for (i = 1; argv[i] != NULL; i++) { - *first = i; - if (argv[i][0] != '-') /* not an option? */ - return args; /* stop handling options */ - switch (argv[i][1]) { /* else check option */ - case '-': /* '--' */ - if (argv[i][2] != '\0') /* extra characters after '--'? */ - return has_error; /* invalid option */ - *first = i + 1; - return args; - case '\0': /* '-' */ - return args; /* script "name" is '-' */ - case 'E': - if (argv[i][2] != '\0') /* extra characters after 1st? */ - return has_error; /* invalid option */ - args |= has_E; - break; - case 'i': - args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */ - case 'v': - if (argv[i][2] != '\0') /* extra characters after 1st? */ - return has_error; /* invalid option */ - args |= has_v; - break; - case 'e': - args |= has_e; /* FALLTHROUGH */ - case 'l': /* both options need an argument */ - if (argv[i][2] == '\0') { /* no concatenated argument? */ - i++; /* try next 'argv' */ - if (argv[i] == NULL || argv[i][0] == '-') - return has_error; /* no next argument or it is another option */ - } - break; - default: /* invalid option */ - return has_error; - } - } - *first = i; /* no script name */ - return args; -} - - -/* -** Processes options 'e' and 'l', which involve running Lua code. -** Returns 0 if some code raises an error. -*/ -static int runargs (lua_State *L, char **argv, int n) { - int i; - for (i = 1; i < n; i++) { - int option = argv[i][1]; - lua_assert(argv[i][0] == '-'); /* already checked */ - if (option == 'e' || option == 'l') { - int status; - const char *extra = argv[i] + 2; /* both options need an argument */ - if (*extra == '\0') extra = argv[++i]; - lua_assert(extra != NULL); - status = (option == 'e') - ? dostring(L, extra, "=(command line)") - : dolibrary(L, extra); - if (status != LUA_OK) return 0; - } - } - return 1; -} - - - -static int handle_luainit (lua_State *L) { - const char *name = "=" LUA_INITVARVERSION; - const char *init = getenv(name + 1); - if (init == NULL) { - name = "=" LUA_INIT_VAR; - init = getenv(name + 1); /* try alternative name */ - } - if (init == NULL) return LUA_OK; - else if (init[0] == '@') - return dofile(L, init+1); - else - return dostring(L, init, name); -} +/* }================================================================== */ /*