From f5e7bfcc486ad87cb95a51b1bb011c994410924a Mon Sep 17 00:00:00 2001 From: Iampete1 Date: Thu, 23 May 2024 22:00:45 +0100 Subject: [PATCH] AP_Scripting: remove support for REPL --- libraries/AP_Scripting/AP_Scripting.cpp | 42 +--- libraries/AP_Scripting/AP_Scripting.h | 9 - libraries/AP_Scripting/lua_common_defs.h | 16 -- libraries/AP_Scripting/lua_repl.cpp | 264 ----------------------- libraries/AP_Scripting/lua_scripts.cpp | 26 +-- libraries/AP_Scripting/lua_scripts.h | 17 +- 6 files changed, 6 insertions(+), 368 deletions(-) delete mode 100644 libraries/AP_Scripting/lua_repl.cpp diff --git a/libraries/AP_Scripting/AP_Scripting.cpp b/libraries/AP_Scripting/AP_Scripting.cpp index b54b890dce..8dc40aad59 100644 --- a/libraries/AP_Scripting/AP_Scripting.cpp +++ b/libraries/AP_Scripting/AP_Scripting.cpp @@ -224,10 +224,9 @@ void AP_Scripting::init(void) { MAV_RESULT AP_Scripting::handle_command_int_packet(const mavlink_command_int_t &packet) { switch ((SCRIPTING_CMD)packet.param1) { case SCRIPTING_CMD_REPL_START: - return repl_start() ? MAV_RESULT_ACCEPTED : MAV_RESULT_FAILED; case SCRIPTING_CMD_REPL_STOP: - repl_stop(); - return MAV_RESULT_ACCEPTED; + return MAV_RESULT_DENIED; + case SCRIPTING_CMD_STOP: _restart = false; _stop = true; @@ -244,41 +243,6 @@ MAV_RESULT AP_Scripting::handle_command_int_packet(const mavlink_command_int_t & } #endif -bool AP_Scripting::repl_start(void) { - if (terminal.session) { // it's already running, this is fine - return true; - } - - // nuke the old folder and all contents - struct stat st; - if ((AP::FS().stat(REPL_DIRECTORY, &st) == -1) && - (AP::FS().unlink(REPL_DIRECTORY) == -1) && - (errno != EEXIST)) { - GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Scripting: Unable to delete old REPL %s", strerror(errno)); - } - - // create a new folder - AP::FS().mkdir(REPL_DIRECTORY); - // delete old files in case we couldn't - AP::FS().unlink(REPL_DIRECTORY "/in"); - AP::FS().unlink(REPL_DIRECTORY "/out"); - - // make the output pointer - terminal.output_fd = AP::FS().open(REPL_OUT, O_WRONLY|O_CREAT|O_TRUNC); - if (terminal.output_fd == -1) { - GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Scripting: %s", "Unable to make new REPL"); - return false; - } - - terminal.session = true; - return true; -} - -void AP_Scripting::repl_stop(void) { - terminal.session = false; - // can't do any more cleanup here, closing the open FD's is the REPL's responsibility -} - /* avoid optimisation of the thread function. This avoids nasty traps where setjmp/longjmp does not properly handle save/restore of @@ -295,7 +259,7 @@ void AP_Scripting::thread(void) { _restart = false; _init_failed = false; - lua_scripts *lua = new lua_scripts(_script_vm_exec_count, _script_heap_size, _debug_options, terminal); + lua_scripts *lua = new lua_scripts(_script_vm_exec_count, _script_heap_size, _debug_options); if (lua == nullptr || !lua->heap_allocated()) { GCS_SEND_TEXT(MAV_SEVERITY_CRITICAL, "Scripting: %s", "Unable to allocate memory"); _init_failed = true; diff --git a/libraries/AP_Scripting/AP_Scripting.h b/libraries/AP_Scripting/AP_Scripting.h index f7139775c0..a2b22e45de 100644 --- a/libraries/AP_Scripting/AP_Scripting.h +++ b/libraries/AP_Scripting/AP_Scripting.h @@ -78,12 +78,6 @@ public: // User parameters for inputs into scripts AP_Float _user[6]; - struct terminal_s { - int output_fd; - off_t input_offset; - bool session; - } terminal; - enum class SCR_DIR { ROMFS = 1 << 0, SCRIPTS = 1 << 1, @@ -146,9 +140,6 @@ public: private: - bool repl_start(void); - void repl_stop(void); - void thread(void); // main script execution thread // Check if DEBUG_OPTS bit has been set to save current checksum values to params diff --git a/libraries/AP_Scripting/lua_common_defs.h b/libraries/AP_Scripting/lua_common_defs.h index 9776e687a8..595665a1e8 100644 --- a/libraries/AP_Scripting/lua_common_defs.h +++ b/libraries/AP_Scripting/lua_common_defs.h @@ -2,14 +2,6 @@ #include -#ifndef REPL_DIRECTORY - #if HAL_OS_FATFS_IO - #define REPL_DIRECTORY "/APM/repl" - #else - #define REPL_DIRECTORY "./repl" - #endif //HAL_OS_FATFS_IO -#endif // REPL_DIRECTORY - #ifndef SCRIPTING_DIRECTORY #if HAL_OS_FATFS_IO #define SCRIPTING_DIRECTORY "/APM/scripts" @@ -18,14 +10,6 @@ #endif //HAL_OS_FATFS_IO #endif // SCRIPTING_DIRECTORY -#ifndef REPL_IN - #define REPL_IN REPL_DIRECTORY "/in" -#endif // REPL_IN - -#ifndef REPL_OUT - #define REPL_OUT REPL_DIRECTORY "/out" -#endif // REPL_OUT - int lua_get_current_ref(); const char* lua_get_modules_path(); void lua_abort(void) __attribute__((noreturn)); diff --git a/libraries/AP_Scripting/lua_repl.cpp b/libraries/AP_Scripting/lua_repl.cpp deleted file mode 100644 index c20bb4f320..0000000000 --- a/libraries/AP_Scripting/lua_repl.cpp +++ /dev/null @@ -1,264 +0,0 @@ -// this implements a Lua REPL, and is based off of a cut down version of -// lua/src/lua.c. It overall modified the functions to the minimum amount -// required, with the exception of fixing whitespace/indentation on if's - -#include "AP_Scripting_config.h" - -#if AP_SCRIPTING_ENABLED - -#include "lua_scripts.h" -#include - -#include "lua/src/lua.h" -#include "lua/src/lauxlib.h" -#include "lua/src/lualib.h" - -#include - -#if !defined(LUA_MAXINPUT) -#define LUA_MAXINPUT 256 -#endif - -#if !defined(LUA_PROMPT) -#define LUA_PROMPT "> " -#define LUA_PROMPT2 ">> " -#endif - -extern const AP_HAL::HAL& hal; - -/* -** Message handler used to run all chunks -*/ -static int msghandler(lua_State *L) { - const char *msg = lua_tostring(L, 1); - if (msg == NULL) { /* is error object not a string? */ - if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ - lua_type(L, -1) == LUA_TSTRING) { /* that produces a string? */ - return 1; /* that is the message */ - } else { - msg = lua_pushfstring(L, "(error object is a %s value)", - luaL_typename(L, 1)); - } - } - luaL_traceback(L, L, msg, 1); /* append a standard traceback */ - return 1; /* return the traceback */ -} - - -/* -** Interface to 'lua_pcall', which sets appropriate message function -** and C-signal handler. Used to run all chunks. -*/ -int lua_scripts::docall(lua_State *L, int narg, int nres) const { - int status; - int base = lua_gettop(L) - narg; /* function index */ - lua_rawgeti(L, LUA_REGISTRYINDEX, sandbox_ref); - lua_setupvalue(L, -2, 1); - lua_pushcfunction(L, msghandler); /* push message handler */ - lua_insert(L, base); /* put it under function and args */ - status = lua_pcall(L, narg, nres, base); - lua_remove(L, base); /* remove message handler from the stack */ - return status; -} - - -/* -** Returns the string to be used as a prompt by the interpreter. -*/ -const char * lua_scripts::get_prompt(lua_State *L, int firstline) { - const char *p; - lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); - p = lua_tostring(L, -1); - if (p == NULL) { - p = (firstline ? LUA_PROMPT : LUA_PROMPT2); - } - return p; -} - -/* mark in error messages for incomplete statements */ -#define EOFMARK "" -#define marklen (sizeof(EOFMARK)/sizeof(char) - 1) - - -/* -** Check whether 'status' signals a syntax error and the error -** message at the top of the stack ends with the above mark for -** incomplete statements. -*/ -int lua_scripts::incomplete(lua_State *L, int status) { - if (status == LUA_ERRSYNTAX) { - size_t lmsg; - const char *msg = lua_tolstring(L, -1, &lmsg); - if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) { - lua_pop(L, 1); - return 1; - } - } - return 0; /* else... */ -} - - -/* -** Prompt the user, read a line, and push it into the Lua stack. -*/ -int lua_scripts::pushline(lua_State *L, int firstline) { - char buffer[LUA_MAXINPUT + 1] = {}; - size_t l = 0; - - // send prompt to the user - terminal_print(get_prompt(L, firstline)); - - while (terminal.session) { - // reseek to where we need input from, as invalid reads could have done weird stuff, and we want to start from the last valid input - int input_fd = AP::FS().open(REPL_IN, O_RDONLY); - if (input_fd != -1) { - AP::FS().lseek(input_fd, terminal.input_offset, SEEK_SET); - ssize_t read_bytes = AP::FS().read(input_fd, buffer, ARRAY_SIZE(buffer) - 1); - AP::FS().close(input_fd); - if (read_bytes > 0) { - // locate the first newline - char * newline_chr = strchr(buffer, '\n'); - if (newline_chr != NULL) { - newline_chr[0] = '\0'; - // only advance to the newline - l = strlen(buffer); - terminal.input_offset += l + 1; - break; - } - } - } - // wait for any input - hal.scheduler->delay(100); - } - - lua_pop(L, 1); /* remove prompt */ - lua_pushlstring(L, buffer, l); - return 1; -} - - -/* -** Try to compile line on the stack as 'return ;'; on return, stack -** has either compiled chunk or original line (if compilation failed). -*/ -int lua_scripts::addreturn(lua_State *L) { - const char *line = lua_tostring(L, -1); /* original line */ - const char *retline = lua_pushfstring(L, "return %s;", line); - int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin"); - if (status == LUA_OK) { - lua_remove(L, -2); /* remove modified line */ - } else { - lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */ - } - return status; -} - - -/* -** Read multiple lines until a complete Lua statement -*/ -int lua_scripts::multiline (lua_State *L) { - for (;;) { /* repeat until gets a complete statement */ - size_t len; - const char *line = lua_tolstring(L, 1, &len); /* get what it has */ - int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ - if (!incomplete(L, status) || !pushline(L, 0)) { - return status; /* cannot or should not try to add continuation line */ - } - lua_pushliteral(L, "\n"); /* add newline... */ - lua_insert(L, -2); /* ...between the two lines */ - lua_concat(L, 3); /* join them */ - } -} - - -/* -** Read a line and try to load (compile) it first as an expression (by -** adding "return " in front of it) and second as a statement. Return -** the final status of load/call with the resulting function (if any) -** in the top of the stack. -*/ -int lua_scripts::loadline(lua_State *L) { - int status; - lua_settop(L, 0); - if (!pushline(L, 1)) { - return -1; /* no input */ - } - if ((status = addreturn(L)) != LUA_OK) { /* 'return ...' did not work? */ - status = multiline(L); /* try as command, maybe with continuation lines */ - } else { - } - lua_remove(L, 1); /* remove line from the stack */ - lua_assert(lua_gettop(L) == 1); - return status; -} - -// push the tring into the terminal, blocks until it's queued -void lua_scripts::terminal_print(const char *str) { - if ((AP::FS().write(terminal.output_fd, str, strlen(str)) == -1) || - (AP::FS().fsync(terminal.output_fd) != 0)) { - terminal.session = false; - } -} - -/* -** Prints (calling the Lua 'print' function) any values on the stack -*/ -void lua_scripts::l_print(lua_State *L) { - int n = lua_gettop(L); - if (n > 0) { /* any result to be printed? */ - luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); - // grab all the internal functions via the sandbox - lua_rawgeti(L, LUA_REGISTRYINDEX, sandbox_ref); - lua_getfield(L, -1, "string"); - lua_getfield(L, -1, "format"); - lua_insert(L, 1); - lua_remove(L, -2); - lua_getfield(L, -1, "rep"); - lua_remove(L, -2); - lua_pushliteral(L, "%s"); - lua_pushinteger(L, n); - lua_pushliteral(L, "\t"); - if (lua_pcall(L, 3, 1, 0) != LUA_OK) { - // should never happen - lua_error(L); - } - lua_insert(L, 2); - if (lua_pcall(L, n + 1, 1, 0) != LUA_OK) { - terminal_print(lua_pushfstring(L, "error calling 'print' (%s)\n", lua_tostring(L, -1))); - } else { - terminal_print(lua_pushfstring(L, "%s\n", lua_tostring(L, -1))); - } - } -} - -/* -** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and -** print any results. -*/ -void lua_scripts::doREPL(lua_State *L) { - int status; - // clear out any old script results - reset_loop_overtime(L); - // prep the sandbox - create_sandbox(L); - sandbox_ref = luaL_ref(L, LUA_REGISTRYINDEX); - terminal.input_offset = 0; - while (((status = loadline(L)) != -1) && terminal.session) { - if (status == LUA_OK) { - status = docall(L, 0, LUA_MULTRET); - } - if (status == LUA_OK) { - l_print(L); - } else { - terminal_print(lua_pushfstring(L, "%s\n", lua_tostring(L, -1))); - } - reset_loop_overtime(L); - } - lua_settop(L, 0); /* clear stack */ - luaL_unref(L, LUA_REGISTRYINDEX, sandbox_ref); - repl_cleanup(); -} - - -#endif // AP_SCRIPTING_ENABLED diff --git a/libraries/AP_Scripting/lua_scripts.cpp b/libraries/AP_Scripting/lua_scripts.cpp index 98960a11ce..5a55e302d2 100644 --- a/libraries/AP_Scripting/lua_scripts.cpp +++ b/libraries/AP_Scripting/lua_scripts.cpp @@ -40,10 +40,9 @@ uint32_t lua_scripts::loaded_checksum; uint32_t lua_scripts::running_checksum; HAL_Semaphore lua_scripts::crc_sem; -lua_scripts::lua_scripts(const AP_Int32 &vm_steps, const AP_Int32 &heap_size, const AP_Int8 &debug_options, struct AP_Scripting::terminal_s &_terminal) +lua_scripts::lua_scripts(const AP_Int32 &vm_steps, const AP_Int32 &heap_size, const AP_Int8 &debug_options) : _vm_steps(vm_steps), - _debug_options(debug_options), - terminal(_terminal) + _debug_options(debug_options) { _heap.create(heap_size, 4); } @@ -458,19 +457,6 @@ void *lua_scripts::alloc(void *ud, void *ptr, size_t osize, size_t nsize) { return _heap.change_size(ptr, osize, nsize); } -void lua_scripts::repl_cleanup (void) { - if (terminal.session) { - terminal.session = false; - if (terminal.output_fd != -1) { - AP::FS().close(terminal.output_fd); - terminal.output_fd = -1; - AP::FS().unlink(REPL_DIRECTORY "/in"); - AP::FS().unlink(REPL_DIRECTORY "/out"); - AP::FS().unlink(REPL_DIRECTORY); - } - } -} - void lua_scripts::run(void) { bool succeeded_initial_load = false; @@ -493,8 +479,6 @@ void lua_scripts::run(void) { } scripts = nullptr; overtime = false; - // end any open REPL sessions - repl_cleanup(); } lua_state = lua_newstate(alloc, NULL); @@ -539,12 +523,6 @@ void lua_scripts::run(void) { #endif // __clang_analyzer__ while (AP_Scripting::get_singleton()->should_run()) { - // handle terminal data if we have any - if (terminal.session) { - doREPL(L); - continue; - } - #if defined(AP_SCRIPTING_CHECKS) && AP_SCRIPTING_CHECKS >= 1 if (lua_gettop(L) != 0) { AP_HAL::panic("Lua: Stack should be empty before running scripts"); diff --git a/libraries/AP_Scripting/lua_scripts.h b/libraries/AP_Scripting/lua_scripts.h index 04001f39bf..3f7129172e 100644 --- a/libraries/AP_Scripting/lua_scripts.h +++ b/libraries/AP_Scripting/lua_scripts.h @@ -34,7 +34,7 @@ class lua_scripts { public: - lua_scripts(const AP_Int32 &vm_steps, const AP_Int32 &heap_size, const AP_Int8 &debug_options, struct AP_Scripting::terminal_s &_terminal); + lua_scripts(const AP_Int32 &vm_steps, const AP_Int32 &heap_size, const AP_Int8 &debug_options); ~lua_scripts(); @@ -60,7 +60,6 @@ public: private: void create_sandbox(lua_State *L); - void repl_cleanup(void); typedef struct script_info { int lua_ref; // reference to the loaded script object @@ -83,20 +82,6 @@ private: // reschedule the script for execution. It is assumed the script is not in the list already void reschedule_script(script_info *script); - // REPL stuff - struct AP_Scripting::terminal_s &terminal; - void doREPL(lua_State *L); - void l_print(lua_State *L); - void terminal_print(const char *str); - int loadline(lua_State *L); - int multiline(lua_State *L); - int addreturn(lua_State *L); - int pushline(lua_State *L, int firstline); - int incomplete(lua_State *L, int status); - const char * get_prompt(lua_State *L, int firstline); - int docall(lua_State *L, int narg, int nres) const; - int sandbox_ref; - script_info *scripts; // linked list of scripts to be run, sorted by next run time (soonest first) // hook will be run when CPU time for a script is exceeded