?login_element?

Subversion Repositories NedoOS

Rev

Rev 539 | Blame | Compare with Previous | Last modification | View Log | Download

  1. /*
  2.  
  3.   SjASMPlus Z80 Cross Compiler - modified - lua scripting module
  4.  
  5.   Copyright (c) 2006 Sjoerd Mastijn (original SW)
  6.   Copyright (c) 2022 Peter Ped Helcmanovsky (lua scripting module)
  7.  
  8.   This software is provided 'as-is', without any express or implied warranty.
  9.   In no event will the authors be held liable for any damages arising from the
  10.   use of this software.
  11.  
  12.   Permission is granted to anyone to use this software for any purpose,
  13.   including commercial applications, and to alter it and redistribute it freely,
  14.   subject to the following restrictions:
  15.  
  16.   1. The origin of this software must not be misrepresented; you must not claim
  17.          that you wrote the original software. If you use this software in a product,
  18.          an acknowledgment in the product documentation would be appreciated but is
  19.          not required.
  20.  
  21.   2. Altered source versions must be plainly marked as such, and must not be
  22.          misrepresented as being the original software.
  23.  
  24.   3. This notice may not be removed or altered from any source distribution.
  25.  
  26. */
  27.  
  28. // lua_sjasm.cpp
  29.  
  30. #include "sjdefs.h"
  31.  
  32. #ifdef USE_LUA
  33.  
  34. #include "lua.hpp"
  35. #include "LuaBridge/LuaBridge.h"
  36.  
  37. static lua_State *LUA = nullptr;
  38.  
  39. static const char* lua_err_prefix = "[LUA] ";
  40.  
  41. // extra lua script inserting interface (sj.something) entry functions
  42. // for functions with optional arguments, like error and warning
  43. // (as LuaBridge2.6 doesn't offer that type of binding as far as I can tell)
  44. // Sidestepping LuaBridge write-protection by "rawset" the end point into it
  45. static const char* binding_script_name = "lua_sjasm.cpp";
  46. static constexpr int binding_script_line = __LINE__;
  47. static const std::string lua_impl_init_bindings_script = R"BINDING_LUA(
  48. rawset(sj,"error",function(m,v)sj.error_i(m or "no message",v)end)
  49. rawset(sj,"warning",function(m,v)sj.warning_i(m or "no message",v)end)
  50. rawset(sj,"insert_define",function(n,v)return sj.insert_define_i(n,v)end)
  51. rawset(sj,"exit",function(e)return sj.exit_i(e or 1)end)
  52. rawset(sj,"set_device",function(i,t)return sj.set_device_i(i or "NONE",t or 0)end)
  53. rawset(zx,"trdimage_create",function(n,l)return zx.trdimage_create_i(n,l)end)
  54. rawset(zx,"trdimage_add_file",function(t,f,s,l,a,r)return zx.trdimage_add_file_i(t,f,s,l,a or -1,r or false)end)
  55. )BINDING_LUA";
  56.  
  57. static void lua_impl_fatalError(lua_State *L) {
  58.         Error((char *)lua_tostring(L, -1), NULL, FATAL);
  59. }
  60.  
  61. static std::vector<TextFilePos> scripts_origin;
  62.  
  63. static char internal_script_name[LINEMAX];
  64.  
  65. static const char* lua_impl_get_script_name(const TextFilePos & srcPos) {
  66.         sprintf(internal_script_name, "script %u", uint32_t(scripts_origin.size()));
  67.         scripts_origin.push_back(srcPos);
  68.         return internal_script_name;
  69. }
  70.  
  71. static bool isInlinedScript(TextFilePos & errorPos, const char* script_name) {
  72.         // return false when the script is external (real file name)
  73.         if (script_name != strstr(script_name, "[string \"script ")) return false;
  74.         // inlined script, find it's origin and add line number to that
  75.         int scriptNumber = atoi(script_name + 16);
  76.         if (scriptNumber < 0 || int(scripts_origin.size()) <= scriptNumber) return false;
  77.         errorPos = scripts_origin.at(scriptNumber);
  78.         return true;
  79. }
  80.  
  81. // adds current source position in lua script + full stack depth onto sourcePosStack
  82. // = makes calls to Error/Warning API to display more precise error lines in lua scripts
  83. static int addLuaSourcePositions() {
  84.         // find all *known* inlined/standalone script names and line numbers on the lua stack
  85.         assert(LUA);
  86.         lua_Debug ar;
  87.         source_positions_t luaPosTemp;
  88.         luaPosTemp.reserve(16);
  89.         int level = 1;                  // level 0 is "C" space, ignore that always
  90.         while (lua_getstack(LUA, level, &ar)) {                 // as long lua stack level are available
  91.                 if (!lua_getinfo(LUA, "Sl", &ar)) break;        // not enough info about current level
  92.  
  93.                 //assert(level || !strcmp("[C]", ar.short_src));        //TODO: verify if ever upgrading to newer lua
  94.                 //if (!strcmp("[C]", ar.short_src)) { ++level; continue; }
  95.  
  96.                 TextFilePos levelErrorPos;
  97.                 if (isInlinedScript(levelErrorPos, ar.short_src)) {
  98.                         levelErrorPos.line += ar.currentline;
  99.                 } else {
  100.                         levelErrorPos.newFile(ArchiveFilename(ar.short_src));
  101.                         levelErrorPos.line = ar.currentline;
  102.                 }
  103.                 luaPosTemp.push_back(levelErrorPos);
  104.                 ++level;
  105.         }
  106.  
  107.         // add all lua positions in reversed order to sourcePosStack (hide binding script if anything else is available)
  108.         bool hide_binding = (2 <= luaPosTemp.size()) && !strcmp(binding_script_name, luaPosTemp[0].filename);
  109.         source_positions_t::iterator stop = hide_binding ? luaPosTemp.begin() + 1 : luaPosTemp.begin();
  110.         source_positions_t::iterator i = luaPosTemp.end();
  111.         while (i-- != stop) sourcePosStack.push_back(*i);
  112.  
  113.         return luaPosTemp.end() - stop;
  114. }
  115.  
  116. static void removeLuaSourcePositions(int to_remove) {
  117.         while (to_remove--) sourcePosStack.pop_back();  // restore sourcePosStack to original state
  118. }
  119.  
  120. // skips file+line_number info (but will adjust global LuaStartPos data for Error output)
  121. static TextFilePos lua_impl_splitLuaErrorMessage(const char*& LuaError) {
  122.         TextFilePos luaErrorPos("?");
  123.         if (!sourcePosStack.empty()) luaErrorPos = sourcePosStack.back();
  124.         if (nullptr == LuaError) return luaErrorPos;
  125.  
  126.         const char* colonPos = strchr(LuaError, ':');
  127.         const char* colon2Pos = nullptr != colonPos ? strchr(colonPos+1, ':') : nullptr;
  128.         if (nullptr == colonPos || nullptr == colon2Pos) return luaErrorPos;    // error, format not recognized
  129.  
  130.         int lineNumber = atoi(colonPos + 1);
  131.         if (isInlinedScript(luaErrorPos, LuaError)) {
  132.                 luaErrorPos.line += lineNumber;
  133.         } else {
  134.                 // standalone script, use file name and line number as is (if provided by lua error)
  135.                 STRNCPY(internal_script_name, LINEMAX, LuaError, colonPos - LuaError);
  136.                 luaErrorPos.newFile(ArchiveFilename(internal_script_name));
  137.                 luaErrorPos.line = lineNumber;
  138.         }
  139.  
  140.         // advance beyond filename and line in LuaError pointer
  141.         LuaError = colon2Pos + 1;
  142.         while (White(*LuaError)) ++LuaError;
  143.         return luaErrorPos;
  144. }
  145.  
  146. static void lua_impl_showLoadError(const EStatus type) {
  147.         const char *msgp = lua_tostring(LUA, -1);
  148.         sourcePosStack.push_back(lua_impl_splitLuaErrorMessage(msgp));
  149.         Error(msgp, nullptr, type);
  150.         sourcePosStack.pop_back();
  151.         lua_pop(LUA, 1);
  152. }
  153.  
  154. static aint lua_sj_calc(const char *str) {
  155.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  156.  
  157.         // substitute defines + macro_args in the `str` first (preserve original global variables)
  158.         char* const oldSubstitutedLine = substitutedLine;
  159.         const int oldComlin = comlin;
  160.         comlin = 0;
  161.         char* tmp = nullptr, * tmp2 = nullptr;
  162.         if (sline[0]) {
  163.                 tmp = STRDUP(sline);
  164.                 if (nullptr == tmp) ErrorOOM();
  165.         }
  166.         if (sline2[0]) {
  167.                 tmp2 = STRDUP(sline2);
  168.                 if (nullptr == tmp2) ErrorOOM();
  169.         }
  170.         // non-const copy of input string for ReplaceDefine argument
  171.         //TODO: v2.x, rewrite whole parser of sjasmplus to start with const input to avoid such copies
  172.         char* luaInput = STRDUP(str ? str : "");
  173.         char* substitutedStr = ReplaceDefine(luaInput);
  174.  
  175.         // evaluate the expression
  176.         aint val;
  177.         int parseResult = ParseExpression(substitutedStr, val);
  178.         free(luaInput);
  179.  
  180.         // restore any global values affected by substitution
  181.         sline[0] = 0;
  182.         if (tmp) {
  183.                 STRCPY(sline, LINEMAX2, tmp);
  184.                 free(tmp);
  185.         }
  186.         sline2[0] = 0;
  187.         if (tmp2) {
  188.                 STRCPY(sline2, LINEMAX2, tmp2);
  189.                 free(tmp2);
  190.         }
  191.         substitutedLine = oldSubstitutedLine;
  192.         comlin = oldComlin;
  193.  
  194.         removeLuaSourcePositions(positionsAdded);
  195.         return parseResult ? val : 0;
  196. }
  197.  
  198. static void parse_line(const char* str, bool parseLabels) {
  199.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  200.  
  201.         // preserve current actual line which will be parsed next
  202.         char *oldLine = STRDUP(line);
  203.         if (nullptr == oldLine) ErrorOOM();
  204.         char *oldEolComment = eolComment;
  205.  
  206.         // inject new line from Lua call and assemble it
  207.         STRCPY(line, LINEMAX, str ? str : "");
  208.         eolComment = nullptr;
  209.         ParseLineSafe(parseLabels);
  210.  
  211.         // restore the original line
  212.         STRCPY(line, LINEMAX, oldLine);
  213.         eolComment = oldEolComment;
  214.         free(oldLine);
  215.  
  216.         removeLuaSourcePositions(positionsAdded);
  217. }
  218.  
  219. static void lua_sj_parse_line(const char *str) {
  220.         parse_line(str, true);
  221. }
  222.  
  223. static void lua_sj_parse_code(const char *str) {
  224.         parse_line(str, false);
  225. }
  226.  
  227. static void lua_sj_error(const char* message, const char* value = nullptr) {
  228.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  229.         Error(message, value, ALL);
  230.         removeLuaSourcePositions(positionsAdded);
  231. }
  232.  
  233. static void lua_sj_warning(const char* message, const char* value = nullptr) {
  234.         int positionsAdded = addLuaSourcePositions();                   // add known script positions to sourcePosStack vector
  235.         Warning(message, value, W_ALL);
  236.         removeLuaSourcePositions(positionsAdded);
  237. }
  238.  
  239. static const char* lua_sj_get_define(const char* name, bool macro_args = false) {
  240.         const char* macro_res = (macro_args && macrolabp) ? MacroDefineTable.getverv(name) : nullptr;
  241.         return macro_res ? macro_res : DefineTable.Get(name);
  242. }
  243.  
  244. static bool lua_sj_insert_define(const char* name, const char* value) {
  245.         // wrapper to resolve member-function call (without std::function wrapping lambda, just to KISS)
  246.         char* lua_name = const_cast<char*>(name);               //TODO v2.x avoid const_cast like this
  247.         char* id = name ? GetID(lua_name) : nullptr;
  248.         if (nullptr == id) return false;
  249.         return DefineTable.Replace(id, value ? value : "");
  250. }
  251.  
  252. static int lua_sj_get_label(const char *name) {
  253.         if (nullptr == name) return -1;
  254.         aint val;
  255.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  256.         char* n = const_cast<char*>(name);      //TODO try to get rid of const_cast, LuaBridge requires const char* to understand it as lua string
  257.         if (!GetLabelValue(n, val)) val = -1;
  258.         removeLuaSourcePositions(positionsAdded);
  259.         return val;
  260. }
  261.  
  262. static bool lua_sj_insert_label(const char *name, int address) {
  263.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  264.         std::unique_ptr<char[]> fullName(ValidateLabel(name, false, false));
  265.         removeLuaSourcePositions(positionsAdded);
  266.         if (nullptr == fullName.get()) return false;
  267.         return LabelTable.Insert(name, address);
  268. }
  269.  
  270. static void lua_sj_shellexec(const char *command) {
  271.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  272.         LuaShellExec(command);
  273.         removeLuaSourcePositions(positionsAdded);
  274. }
  275.  
  276. static bool lua_sj_set_page(aint n) {
  277.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  278.         if (!DeviceID) Warning("sj.set_page: only allowed in real device emulation mode (See DEVICE)");
  279.         bool result = DeviceID && dirPageImpl("sj.set_page", n);
  280.         removeLuaSourcePositions(positionsAdded);
  281.         return result;
  282. }
  283.  
  284. static bool lua_sj_set_slot(aint n) {
  285.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  286.         bool result = false;
  287.         if (!DeviceID) {
  288.                 Warning("sj.set_slot: only allowed in real device emulation mode (See DEVICE)");
  289.         } else {
  290.                 n = Device->SlotNumberFromPreciseAddress(n);
  291.                 result = Device->SetSlot(n);
  292.                 if (!result) {
  293.                         char buf[LINEMAX];
  294.                         SPRINTF1(buf, LINEMAX, "sj.set_slot: Slot number must be in range 0..%u", Device->SlotsCount - 1);
  295.                         Error(buf);
  296.                 }
  297.         }
  298.         removeLuaSourcePositions(positionsAdded);
  299.         return result;
  300. }
  301.  
  302. static bool lua_sj_set_device(const char* id, const aint ramtop = 0) {
  303.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  304.         // refresh source position of first DEVICE directive (to make global-device detection work correctly)
  305.         if (1 == ++deviceDirectivesCount) {
  306.                 assert(!sourcePosStack.empty());
  307.                 globalDeviceSourcePos = sourcePosStack.back();
  308.         }
  309.         // check for nullptr id??
  310.         bool result = SetDevice(id, ramtop);
  311.         removeLuaSourcePositions(positionsAdded);
  312.         return result;
  313. }
  314.  
  315. static void lua_sj_add_byte(int byte) {
  316.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  317.         EmitByte(byte);
  318.         removeLuaSourcePositions(positionsAdded);
  319. }
  320.  
  321. static void lua_sj_add_word(int word) {
  322.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  323.         EmitWord(word);
  324.         removeLuaSourcePositions(positionsAdded);
  325. }
  326.  
  327. static unsigned char lua_sj_get_byte(unsigned int address) {
  328.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  329.         auto result = MemGetByte(address);
  330.         removeLuaSourcePositions(positionsAdded);
  331.         return result;
  332. }
  333.  
  334. static unsigned int lua_sj_get_word(unsigned int address) {
  335.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  336.         auto result = MemGetWord(address);
  337.         removeLuaSourcePositions(positionsAdded);
  338.         return result;
  339. }
  340.  
  341. static bool lua_zx_trdimage_create(const char* trdname, const char* label = nullptr) {
  342.         // setup label to truncated 8 char array padded with spaces
  343.         char l8[9] = "        ";
  344.         char* l8_ptr = l8;
  345.         while (label && *label && (l8_ptr - l8) < 8) *l8_ptr++ = *label++;
  346.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  347.         bool result = TRD_SaveEmpty(trdname, l8);
  348.         removeLuaSourcePositions(positionsAdded);
  349.         return result;
  350. }
  351.  
  352. bool lua_zx_trdimage_add_file(const char* trd, const char* file, int start, int length, int autostart = -1, bool replace = false) {
  353.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  354.         bool result = nullptr != trd && nullptr != file && TRD_AddFile(trd, file, start, length, autostart, replace, false);
  355.         removeLuaSourcePositions(positionsAdded);
  356.         return result;
  357. }
  358.  
  359. static bool lua_zx_save_snapshot_sna(const char* fname, word start) {
  360.         int positionsAdded = addLuaSourcePositions();   // add known script positions to sourcePosStack vector
  361.         bool result = SaveSNA_ZX(fname, start);
  362.         removeLuaSourcePositions(positionsAdded);
  363.         return result;
  364. }
  365.  
  366. static void lua_impl_init() {
  367.         assert(nullptr == LUA);
  368.  
  369.         scripts_origin.reserve(64);
  370.  
  371.         // initialise Lua (regular Lua, without sjasmplus bindings/extensions)
  372.         LUA = luaL_newstate();
  373.         lua_atpanic(LUA, (lua_CFunction)lua_impl_fatalError);
  374.  
  375.         // for manual testing of lua_atpanic handler
  376. //      { lua_error(LUA); }
  377. //      { lua_pushstring(LUA, "testing at panic handler"); lua_error(LUA); }
  378.  
  379.         luaL_openlibs(LUA);
  380.  
  381.         // initialise sjasmplus bindings/extensions
  382.         luabridge::getGlobalNamespace(LUA)
  383.                 .addFunction("_c", lua_sj_calc)
  384.                 .addFunction("_pl", lua_sj_parse_line)
  385.                 .addFunction("_pc", lua_sj_parse_code)
  386.                 .beginNamespace("sj")
  387.                         .addProperty("current_address", &CurAddress, false)     // read-only
  388.                         .addProperty("warning_count", &WarningCount, false)     // read-only
  389.                         .addProperty("error_count", &ErrorCount, false) // read-only
  390.                         // internal functions which are lua-wrapped to enable optional arguments
  391.                         .addFunction("error_i", lua_sj_error)
  392.                         .addFunction("warning_i", lua_sj_warning)
  393.                         .addFunction("insert_define_i", lua_sj_insert_define)
  394.                         .addFunction("exit_i", ExitASM)
  395.                         .addFunction("set_device_i", lua_sj_set_device)
  396.                         // remaining public functions with all arguments mandatory (boolean args seems to default to false?)
  397.                         .addFunction("get_define", lua_sj_get_define)
  398.                         .addFunction("get_label", lua_sj_get_label)
  399.                         .addFunction("insert_label", lua_sj_insert_label)
  400.                         .addFunction("shellexec", lua_sj_shellexec)
  401.                         .addFunction("calc", lua_sj_calc)
  402.                         .addFunction("parse_line", lua_sj_parse_line)
  403.                         .addFunction("parse_code", lua_sj_parse_code)
  404.                         .addFunction("add_byte", lua_sj_add_byte)
  405.                         .addFunction("add_word", lua_sj_add_word)
  406.                         .addFunction("get_byte", lua_sj_get_byte)
  407.                         .addFunction("get_word", lua_sj_get_word)
  408.                         .addFunction("get_device", GetDeviceName)               // no error/warning, can be called directly
  409.                         .addFunction("set_page", lua_sj_set_page)
  410.                         .addFunction("set_slot", lua_sj_set_slot)
  411.                         // MMU API will be not added, it is too dynamic, and _pc("MMU ...") works
  412.                         .addFunction("file_exists", FileExists)
  413.                 .endNamespace()
  414.                 .beginNamespace("zx")
  415.                         .addFunction("trdimage_create_i", lua_zx_trdimage_create)
  416.                         .addFunction("trdimage_add_file_i", lua_zx_trdimage_add_file)
  417.                         .addFunction("save_snapshot_sna", lua_zx_save_snapshot_sna)
  418.                 .endNamespace();
  419.  
  420.                 TextFilePos binding_script_pos(binding_script_name, binding_script_line);
  421.                 if (luaL_loadbuffer(LUA, lua_impl_init_bindings_script.c_str(), lua_impl_init_bindings_script.size(), lua_impl_get_script_name(binding_script_pos))
  422.                         || lua_pcall(LUA, 0, LUA_MULTRET, 0)) {
  423.                         lua_impl_showLoadError(FATAL);                          // unreachable (I hope) // manual testing: damage binding script
  424.                 }
  425. }
  426.  
  427. void dirENDLUA() {
  428.         Error("[ENDLUA] End of lua script without script");
  429. }
  430.  
  431. void dirLUA() {
  432.         // lazy init of Lua scripting upon first hit of LUA directive
  433.         if (nullptr == LUA) lua_impl_init();
  434.         assert(LUA);
  435.  
  436.         constexpr size_t luaBufferSize = 32768;
  437.         char* id, * buff = nullptr, * bp = nullptr;
  438.  
  439.         int passToExec = LASTPASS;
  440.         if ((id = GetID(lp)) && strlen(id) > 0) {
  441.                 if (cmphstr(id, "pass1")) {
  442.                         passToExec = 1;
  443.                 } else if (cmphstr(id, "pass2")) {
  444.                         passToExec = 2;
  445.                 } else if (cmphstr(id, "pass3")) {
  446.                         passToExec = LASTPASS;
  447.                 } else if (cmphstr(id, "allpass")) {
  448.                         passToExec = -1;
  449.                 } else {
  450.                         Error("[LUA] Syntax error", id);
  451.                 }
  452.         }
  453.  
  454.         const EStatus errorType = (1 == passToExec || 2 == passToExec) ? EARLY : PASS3;
  455.         const bool execute = (-1 == passToExec) || (passToExec == pass);
  456.         // remember warning suppression also from block start
  457.         bool showWarning = !suppressedById(W_LUA_MC_PASS);
  458.  
  459.         assert(!sourcePosStack.empty());
  460.         TextFilePos luaStartPos = sourcePosStack.back();        // position of LUA directive (not ENDLUA)
  461.         if (execute) {
  462.                 buff = new char[luaBufferSize];
  463.                 bp = buff;
  464.         }
  465.         ListFile();
  466.  
  467.         while (1) {
  468.                 if (!ReadLine(false)) {
  469.                         Error("[LUA] Unexpected end of lua script");
  470.                         break;
  471.                 }
  472.                 lp = line;
  473.                 SkipBlanks(lp);
  474.                 const int isEndLua = cmphstr(lp, "endlua");
  475.                 const size_t lineLen = isEndLua ? (lp - 6 - line) : strlen(line);
  476.                 if (execute) {
  477.                         if (luaBufferSize < (bp - buff) + lineLen + 4) {
  478.                                 ErrorInt("[LUA] Maximum byte-size of Lua script is", luaBufferSize-4, FATAL);
  479.                         }
  480.                         memcpy(bp, line, lineLen);
  481.                         bp += lineLen;
  482.                         *bp++ = '\n';
  483.                 }
  484.                 if (isEndLua) {         // eat also any trailing eol-type of comment
  485.                         skipEmitMessagePos = sourcePosStack.back();
  486.                         ++CompiledCurrentLine;
  487.                         lp = ReplaceDefine(lp);         // skip any empty substitutions and comments
  488.                         substitutedLine = line;         // override substituted listing for ENDLUA
  489.                         // take into account also warning suppression used at end of block
  490.                         showWarning = showWarning && !suppressedById(W_LUA_MC_PASS);
  491.                         break;
  492.                 }
  493.                 ListFile(true);
  494.         }
  495.  
  496.         if (execute) {
  497.                 extraErrorWarningPrefix = lua_err_prefix;
  498.                 *bp = 0;
  499.                 DidEmitByte();                  // reset the flag before running lua script
  500.                 if (luaL_loadbuffer(LUA, buff, bp-buff, lua_impl_get_script_name(luaStartPos)) || lua_pcall(LUA, 0, LUA_MULTRET, 0)) {
  501.                         lua_impl_showLoadError(errorType);
  502.                 }
  503.                 extraErrorWarningPrefix = nullptr;
  504.                 delete[] buff;
  505.                 if (DidEmitByte() && (-1 != passToExec) && showWarning) {
  506.                         const EWStatus warningType = (1 == passToExec || 2 == passToExec) ? W_EARLY : W_PASS3;
  507.                         WarningById(W_LUA_MC_PASS, nullptr, warningType);
  508.                 }
  509.         }
  510.  
  511.         ++CompiledCurrentLine;
  512.         substitutedLine = line;         // override substituted list line for ENDLUA
  513. }
  514.  
  515. void dirINCLUDELUA() {
  516.         // lazy init of Lua scripting upon first hit of INCLUDELUA directive
  517.         if (nullptr == LUA) lua_impl_init();
  518.         assert(LUA);
  519.  
  520.         if (1 != pass) {
  521.                 SkipToEol(lp);          // skip till EOL (colon), to avoid parsing file name
  522.                 return;
  523.         }
  524.         std::unique_ptr<char[]> fnaam(GetFileName(lp));
  525.         EDelimiterType dt = GetDelimiterOfLastFileName();
  526.         char* fullpath = GetPath(fnaam.get(), NULL, DT_ANGLE == dt);
  527.         if (!fullpath[0]) {
  528.                 Error("[INCLUDELUA] File doesn't exist", fnaam.get(), EARLY);
  529.         } else {
  530.                 extraErrorWarningPrefix = lua_err_prefix;
  531.                 fileNameFull = ArchiveFilename(fullpath);       // get const pointer into archive
  532.                 if (luaL_dofile(LUA, fileNameFull)) {
  533.                         lua_impl_showLoadError(EARLY);
  534.                 }
  535.                 extraErrorWarningPrefix = nullptr;
  536.         }
  537.         free(fullpath);
  538. }
  539.  
  540. #endif //USE_LUA
  541.  
  542. ////////////////////////////////////////////////////////////////////////////////////////////
  543. // close LUA engine and release everything related
  544. void lua_impl_close() {
  545.         #ifdef USE_LUA
  546.                 // if Lua was used and initialised, release everything
  547.                 if (LUA) lua_close(LUA);
  548.         #endif //USE_LUA
  549.  
  550.         // do nothing when Lua is compile-time disabled
  551. }
  552.  
  553. //eof lua_sjasm.cpp
  554.