• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

z00m128 / sjasmplus / 1447

29 Dec 2024 11:09AM UTC coverage: 96.279% (+0.002%) from 96.277%
1447

push

cirrus-ci

ped7g
tests: sj.get_modules() adjusted slightly

9676 of 10050 relevant lines covered (96.28%)

168571.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.11
/sjasm/lua_sjasm.cpp
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) {
846✔
66
        sprintf(internal_script_name, "script %u", uint32_t(scripts_origin.size()));
846✔
67
        scripts_origin.push_back(srcPos);
846✔
68
        return internal_script_name;
846✔
69
}
70

71
static bool isInlinedScript(TextFilePos & errorPos, const char* script_name) {
203,881✔
72
        // return false when the script is external (real file name)
73
        if (script_name != strstr(script_name, "[string \"script ")) return false;
203,881✔
74
        // inlined script, find it's origin and add line number to that
75
        int scriptNumber = atoi(script_name + 16);
203,513✔
76
        if (scriptNumber < 0 || int(scripts_origin.size()) <= scriptNumber) return false;
203,513✔
77
        errorPos = scripts_origin.at(scriptNumber);
203,513✔
78
        return true;
203,513✔
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() {
203,258✔
84
        // find all *known* inlined/standalone script names and line numbers on the lua stack
85
        assert(LUA);
203,258✔
86
        lua_Debug ar;
87
        source_positions_t luaPosTemp;
203,258✔
88
        luaPosTemp.reserve(16);
203,258✔
89
        int level = 1;                        // level 0 is "C" space, ignore that always
203,258✔
90
        while (lua_getstack(LUA, level, &ar)) {                        // as long lua stack level are available
407,126✔
91
                if (!lua_getinfo(LUA, "Sl", &ar)) break;        // not enough info about current level
203,868✔
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;
203,868✔
97
                if (isInlinedScript(levelErrorPos, ar.short_src)) {
203,868✔
98
                        levelErrorPos.line += ar.currentline;
203,502✔
99
                } else {
100
                        levelErrorPos.newFile(ArchiveFilename(ar.short_src));
366✔
101
                        levelErrorPos.line = ar.currentline;
366✔
102
                }
103
                luaPosTemp.push_back(levelErrorPos);
203,868✔
104
                ++level;
203,868✔
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);
203,258✔
109
        source_positions_t::iterator stop = hide_binding ? luaPosTemp.begin() + 1 : luaPosTemp.begin();
203,258✔
110
        source_positions_t::iterator i = luaPosTemp.end();
203,258✔
111
        while (i-- != stop) sourcePosStack.push_back(*i);
407,034✔
112

113
        return luaPosTemp.end() - stop;
406,516✔
114
}
203,258✔
115

116
static void removeLuaSourcePositions(int to_remove) {
203,258✔
117
        while (to_remove--) sourcePosStack.pop_back();        // restore sourcePosStack to original state
407,034✔
118
}
203,258✔
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) {
16✔
122
        TextFilePos luaErrorPos("?");
16✔
123
        if (!sourcePosStack.empty()) luaErrorPos = sourcePosStack.back();
16✔
124
        if (nullptr == LuaError) return luaErrorPos;
16✔
125

126
        const char* colonPos = strchr(LuaError, ':');
16✔
127
        const char* colon2Pos = nullptr != colonPos ? strchr(colonPos+1, ':') : nullptr;
16✔
128
        if (nullptr == colonPos || nullptr == colon2Pos) return luaErrorPos;        // error, format not recognized
16✔
129

130
        int lineNumber = atoi(colonPos + 1);
13✔
131
        if (isInlinedScript(luaErrorPos, LuaError)) {
13✔
132
                luaErrorPos.line += lineNumber;
11✔
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);
2✔
136
                luaErrorPos.newFile(ArchiveFilename(internal_script_name));
2✔
137
                luaErrorPos.line = lineNumber;
2✔
138
        }
139

140
        // advance beyond filename and line in LuaError pointer
141
        LuaError = colon2Pos + 1;
13✔
142
        while (White(*LuaError)) ++LuaError;
26✔
143
        return luaErrorPos;
13✔
144
}
145

146
static void lua_impl_showLoadError(const EStatus type) {
16✔
147
        const char *msgp = lua_tostring(LUA, -1);
16✔
148
        sourcePosStack.push_back(lua_impl_splitLuaErrorMessage(msgp));
16✔
149
        Error(msgp, nullptr, type);
16✔
150
        sourcePosStack.pop_back();
16✔
151
        lua_pop(LUA, 1);
16✔
152
}
16✔
153

154
static aint lua_sj_calc(const char *str) {
387✔
155
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
387✔
156

157
        // substitute defines + macro_args in the `str` first (preserve original global variables)
158
        char* const oldSubstitutedLine = substitutedLine;
387✔
159
        const int oldComlin = comlin;
387✔
160
        comlin = 0;
387✔
161
        char* tmp = nullptr, * tmp2 = nullptr;
387✔
162
        if (sline[0]) {
387✔
163
                tmp = STRDUP(sline);
3✔
164
                if (nullptr == tmp) ErrorOOM();
3✔
165
        }
166
        if (sline2[0]) {
387✔
167
                tmp2 = STRDUP(sline2);
62✔
168
                if (nullptr == tmp2) ErrorOOM();
62✔
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 : "");
387✔
173
        char* substitutedStr = ReplaceDefine(luaInput);
387✔
174

175
        // evaluate the expression
176
        aint val;
177
        int parseResult = ParseExpression(substitutedStr, val);
387✔
178
        free(luaInput);
387✔
179

180
        // restore any global values affected by substitution
181
        sline[0] = 0;
387✔
182
        if (tmp) {
387✔
183
                STRCPY(sline, LINEMAX2, tmp);
3✔
184
                free(tmp);
3✔
185
        }
186
        sline2[0] = 0;
387✔
187
        if (tmp2) {
387✔
188
                STRCPY(sline2, LINEMAX2, tmp2);
62✔
189
                free(tmp2);
62✔
190
        }
191
        substitutedLine = oldSubstitutedLine;
387✔
192
        comlin = oldComlin;
387✔
193

194
        removeLuaSourcePositions(positionsAdded);
387✔
195
        return parseResult ? val : 0;
774✔
196
}
197

198
static void parse_line(const char* str, bool parseLabels) {
3,290✔
199
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
3,290✔
200

201
        // preserve current actual line which will be parsed next
202
        char *oldLine = STRDUP(line);
3,290✔
203
        if (nullptr == oldLine) ErrorOOM();
3,290✔
204
        char *oldEolComment = eolComment;
3,290✔
205

206
        // inject new line from Lua call and assemble it
207
        STRCPY(line, LINEMAX, str ? str : "");
3,290✔
208
        eolComment = nullptr;
3,290✔
209
        ParseLineSafe(parseLabels);
3,290✔
210

211
        // restore the original line
212
        STRCPY(line, LINEMAX, oldLine);
3,290✔
213
        eolComment = oldEolComment;
3,290✔
214
        free(oldLine);
3,290✔
215

216
        removeLuaSourcePositions(positionsAdded);
3,290✔
217
}
3,290✔
218

219
static void lua_sj_parse_line(const char *str) {
251✔
220
        parse_line(str, true);
251✔
221
}
251✔
222

223
static void lua_sj_parse_code(const char *str) {
3,039✔
224
        parse_line(str, false);
3,039✔
225
}
3,039✔
226

227
static void lua_sj_error(const char* message, const char* value = nullptr) {
20✔
228
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
20✔
229
        Error(message, value, ALL);
20✔
230
        removeLuaSourcePositions(positionsAdded);
20✔
231
}
20✔
232

233
static void lua_sj_warning(const char* message, const char* value = nullptr) {
39✔
234
        int positionsAdded = addLuaSourcePositions();                        // add known script positions to sourcePosStack vector
39✔
235
        Warning(message, value, W_ALL);
39✔
236
        removeLuaSourcePositions(positionsAdded);
39✔
237
}
39✔
238

239
static const char* lua_sj_get_define(const char* name, bool macro_args = false) {
207✔
240
        const char* macro_res = (macro_args && macrolabp) ? MacroDefineTable.getverv(name) : nullptr;
207✔
241
        return macro_res ? macro_res : DefineTable.Get(name);
207✔
242
}
243

244
static bool lua_sj_insert_define(const char* name, const char* value) {
26✔
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
26✔
247
        char* id = name ? GetID(lua_name) : nullptr;
26✔
248
        if (nullptr == id) return false;
26✔
249
        return DefineTable.Replace(id, value ? value : "");
14✔
250
}
251

252
static int lua_sj_get_label(const char *name) {
286✔
253
        if (nullptr == name) return -1;
286✔
254
        aint val;
255
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
284✔
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
284✔
257
        if (!GetLabelValue(n, val)) val = -1;
284✔
258
        removeLuaSourcePositions(positionsAdded);
284✔
259
        return val;
284✔
260
}
261

262
static bool lua_sj_insert_label(const char *name, int address) {
31✔
263
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
31✔
264
        std::unique_ptr<char[]> fullName(ValidateLabel(name, false, false));
31✔
265
        removeLuaSourcePositions(positionsAdded);
31✔
266
        if (nullptr == fullName.get()) return false;
31✔
267
        return LabelTable.Insert(name, address);
19✔
268
}
31✔
269

270
static void lua_sj_shellexec(const char *command) {
1✔
271
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
1✔
272
        LuaShellExec(command);
1✔
273
        removeLuaSourcePositions(positionsAdded);
1✔
274
}
1✔
275

276
static bool lua_sj_set_page(aint n) {
5✔
277
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
5✔
278
        if (!DeviceID) Warning("sj.set_page: only allowed in real device emulation mode (See DEVICE)");
5✔
279
        bool result = DeviceID && dirPageImpl("sj.set_page", n);
5✔
280
        removeLuaSourcePositions(positionsAdded);
5✔
281
        return result;
5✔
282
}
283

284
static bool lua_sj_set_slot(aint n) {
10✔
285
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
10✔
286
        bool result = false;
10✔
287
        if (!DeviceID) {
10✔
288
                Warning("sj.set_slot: only allowed in real device emulation mode (See DEVICE)");
1✔
289
        } else {
290
                n = Device->SlotNumberFromPreciseAddress(n);
9✔
291
                result = Device->SetSlot(n);
9✔
292
                if (!result) {
9✔
293
                        char buf[LINEMAX];
294
                        SPRINTF1(buf, LINEMAX, "sj.set_slot: Slot number must be in range 0..%u", Device->SlotsCount - 1);
2✔
295
                        Error(buf);
2✔
296
                }
297
        }
298
        removeLuaSourcePositions(positionsAdded);
10✔
299
        return result;
10✔
300
}
301

302
static bool lua_sj_set_device(const char* id, const aint ramtop = 0) {
31✔
303
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
31✔
304
        // refresh source position of first DEVICE directive (to make global-device detection work correctly)
305
        if (1 == ++deviceDirectivesCount) {
31✔
306
                assert(!sourcePosStack.empty());
12✔
307
                globalDeviceSourcePos = sourcePosStack.back();
12✔
308
        }
309
        // check for nullptr id??
310
        bool result = SetDevice(id, ramtop);
31✔
311
        removeLuaSourcePositions(positionsAdded);
31✔
312
        return result;
31✔
313
}
314

315
static void lua_sj_add_byte(int byte) {
199,096✔
316
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
199,096✔
317
        EmitByte(byte);
199,096✔
318
        removeLuaSourcePositions(positionsAdded);
199,096✔
319
}
199,096✔
320

321
static void lua_sj_add_word(int word) {
40✔
322
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
40✔
323
        EmitWord(word);
40✔
324
        removeLuaSourcePositions(positionsAdded);
40✔
325
}
40✔
326

327
static unsigned char lua_sj_get_byte(unsigned int address) {
11✔
328
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
11✔
329
        auto result = MemGetByte(address);
11✔
330
        removeLuaSourcePositions(positionsAdded);
11✔
331
        return result;
11✔
332
}
333

334
static unsigned int lua_sj_get_word(unsigned int address) {
10✔
335
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
10✔
336
        auto result = MemGetWord(address);
10✔
337
        removeLuaSourcePositions(positionsAdded);
10✔
338
        return result;
10✔
339
}
340

341
static const char* lua_sj_get_modules(void) {
27✔
342
        return ModuleName;
27✔
343
}
344

345
static bool lua_zx_trdimage_create(const char* trdname, const char* label = nullptr) {
1✔
346
        // setup label to truncated 8 char array padded with spaces
347
        char l8[9] = "        ";
1✔
348
        char* l8_ptr = l8;
1✔
349
        while (label && *label && (l8_ptr - l8) < 8) *l8_ptr++ = *label++;
1✔
350
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
1✔
351
        bool result = TRD_SaveEmpty(trdname, l8);
1✔
352
        removeLuaSourcePositions(positionsAdded);
1✔
353
        return result;
1✔
354
}
355

356
bool lua_zx_trdimage_add_file(const char* trd, const char* file, int start, int length, int autostart = -1, bool replace = false) {
1✔
357
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
1✔
358
        bool result = nullptr != trd && nullptr != file && TRD_AddFile(trd, file, start, length, autostart, replace, false);
1✔
359
        removeLuaSourcePositions(positionsAdded);
1✔
360
        return result;
1✔
361
}
362

363
static bool lua_zx_save_snapshot_sna(const char* fname, word start) {
1✔
364
        int positionsAdded = addLuaSourcePositions();        // add known script positions to sourcePosStack vector
1✔
365
        bool result = SaveSNA_ZX(fname, start);
1✔
366
        removeLuaSourcePositions(positionsAdded);
1✔
367
        return result;
1✔
368
}
369

370
static void lua_impl_init() {
60✔
371
        assert(nullptr == LUA);
60✔
372

373
        scripts_origin.reserve(64);
60✔
374

375
        // initialise Lua (regular Lua, without sjasmplus bindings/extensions)
376
        LUA = luaL_newstate();
60✔
377
        lua_atpanic(LUA, (lua_CFunction)lua_impl_fatalError);
60✔
378

379
        // for manual testing of lua_atpanic handler
380
//         { lua_error(LUA); }
381
//         { lua_pushstring(LUA, "testing at panic handler"); lua_error(LUA); }
382

383
        luaL_openlibs(LUA);
60✔
384

385
        // initialise sjasmplus bindings/extensions
386
        luabridge::getGlobalNamespace(LUA)
120✔
387
                .addFunction("_c", lua_sj_calc)
60✔
388
                .addFunction("_pl", lua_sj_parse_line)
60✔
389
                .addFunction("_pc", lua_sj_parse_code)
60✔
390
                .beginNamespace("sj")
120✔
391
                        .addProperty("current_address", &CurAddress, false)        // read-only
60✔
392
                        .addProperty("warning_count", &WarningCount, false)        // read-only
60✔
393
                        .addProperty("error_count", &ErrorCount, false)        // read-only
60✔
394
                        // internal functions which are lua-wrapped to enable optional arguments
395
                        .addFunction("error_i", lua_sj_error)
60✔
396
                        .addFunction("warning_i", lua_sj_warning)
60✔
397
                        .addFunction("insert_define_i", lua_sj_insert_define)
60✔
398
                        .addFunction("exit_i", ExitASM)
60✔
399
                        .addFunction("set_device_i", lua_sj_set_device)
60✔
400
                        // remaining public functions with all arguments mandatory (boolean args seems to default to false?)
401
                        .addFunction("get_define", lua_sj_get_define)
60✔
402
                        .addFunction("get_label", lua_sj_get_label)
60✔
403
                        .addFunction("insert_label", lua_sj_insert_label)
60✔
404
                        .addFunction("shellexec", lua_sj_shellexec)
60✔
405
                        .addFunction("calc", lua_sj_calc)
60✔
406
                        .addFunction("parse_line", lua_sj_parse_line)
60✔
407
                        .addFunction("parse_code", lua_sj_parse_code)
60✔
408
                        .addFunction("add_byte", lua_sj_add_byte)
60✔
409
                        .addFunction("add_word", lua_sj_add_word)
60✔
410
                        .addFunction("get_byte", lua_sj_get_byte)
60✔
411
                        .addFunction("get_word", lua_sj_get_word)
60✔
412
                        .addFunction("get_device", GetDeviceName)                // no error/warning, can be called directly
60✔
413
                        .addFunction("get_modules", lua_sj_get_modules)
60✔
414
                        .addFunction("set_page", lua_sj_set_page)
60✔
415
                        .addFunction("set_slot", lua_sj_set_slot)
60✔
416
                        // MMU API will be not added, it is too dynamic, and _pc("MMU ...") works
417
                        .addFunction("file_exists", FileExists)
60✔
418
                .endNamespace()
120✔
419
                .beginNamespace("zx")
120✔
420
                        .addFunction("trdimage_create_i", lua_zx_trdimage_create)
60✔
421
                        .addFunction("trdimage_add_file_i", lua_zx_trdimage_add_file)
60✔
422
                        .addFunction("save_snapshot_sna", lua_zx_save_snapshot_sna)
60✔
423
                .endNamespace();
60✔
424

425
                TextFilePos binding_script_pos(binding_script_name, binding_script_line);
60✔
426
                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))
60✔
427
                        || lua_pcall(LUA, 0, LUA_MULTRET, 0)) {
60✔
428
                        lua_impl_showLoadError(FATAL);                                // unreachable (I hope) // manual testing: damage binding script
×
429
                }
430
}
60✔
431

432
void dirENDLUA() {
3✔
433
        Error("[ENDLUA] End of lua script without script");
3✔
434
}
3✔
435

436
void dirLUA() {
1,026✔
437
        // lazy init of Lua scripting upon first hit of LUA directive
438
        if (nullptr == LUA) lua_impl_init();
1,026✔
439
        assert(LUA);
1,026✔
440

441
        constexpr size_t luaBufferSize = 32768;
1,026✔
442
        char* id, * buff = nullptr, * bp = nullptr;
1,026✔
443

444
        int passToExec = LASTPASS;
1,026✔
445
        if ((id = GetID(lp)) && strlen(id) > 0) {
1,026✔
446
                if (cmphstr(id, "pass1")) {
885✔
447
                        passToExec = 1;
72✔
448
                } else if (cmphstr(id, "pass2")) {
813✔
449
                        passToExec = 2;
33✔
450
                } else if (cmphstr(id, "pass3")) {
780✔
451
                        passToExec = LASTPASS;
111✔
452
                } else if (cmphstr(id, "allpass")) {
669✔
453
                        passToExec = -1;
666✔
454
                } else {
455
                        Error("[LUA] Syntax error", id);
3✔
456
                }
457
        }
458

459
        const EStatus errorType = (1 == passToExec || 2 == passToExec) ? EARLY : PASS3;
1,026✔
460
        const bool execute = (-1 == passToExec) || (passToExec == pass);
1,026✔
461
        // remember warning suppression also from block start
462
        bool showWarning = !suppressedById(W_LUA_MC_PASS);
1,026✔
463

464
        assert(!sourcePosStack.empty());
1,026✔
465
        TextFilePos luaStartPos = sourcePosStack.back();        // position of LUA directive (not ENDLUA)
1,026✔
466
        if (execute) {
1,026✔
467
                buff = new char[luaBufferSize];
786✔
468
                bp = buff;
786✔
469
        }
470
        ListFile();
1,026✔
471

472
        while (1) {
473
                if (!ReadLine(false)) {
4,035✔
474
                        Error("[LUA] Unexpected end of lua script");
3✔
475
                        break;
3✔
476
                }
477
                lp = line;
4,032✔
478
                SkipBlanks(lp);
4,032✔
479
                const int isEndLua = cmphstr(lp, "endlua");
4,032✔
480
                const size_t lineLen = isEndLua ? (lp - 6 - line) : strlen(line);
4,032✔
481
                if (execute) {
4,032✔
482
                        if (luaBufferSize < (bp - buff) + lineLen + 4) {
3,056✔
483
                                ErrorInt("[LUA] Maximum byte-size of Lua script is", luaBufferSize-4, FATAL);
×
484
                        }
485
                        memcpy(bp, line, lineLen);
3,056✔
486
                        bp += lineLen;
3,056✔
487
                        *bp++ = '\n';
3,056✔
488
                }
489
                if (isEndLua) {                // eat also any trailing eol-type of comment
4,032✔
490
                        skipEmitMessagePos = sourcePosStack.back();
1,023✔
491
                        ++CompiledCurrentLine;
1,023✔
492
                        lp = ReplaceDefine(lp);                // skip any empty substitutions and comments
1,023✔
493
                        substitutedLine = line;                // override substituted listing for ENDLUA
1,023✔
494
                        // take into account also warning suppression used at end of block
495
                        showWarning = showWarning && !suppressedById(W_LUA_MC_PASS);
1,023✔
496
                        break;
1,023✔
497
                }
498
                ListFile(true);
3,009✔
499
        }
3,009✔
500

501
        if (execute) {
1,026✔
502
                extraErrorWarningPrefix = lua_err_prefix;
786✔
503
                *bp = 0;
786✔
504
                DidEmitByte();                        // reset the flag before running lua script
786✔
505
                if (luaL_loadbuffer(LUA, buff, bp-buff, lua_impl_get_script_name(luaStartPos)) || lua_pcall(LUA, 0, LUA_MULTRET, 0)) {
786✔
506
                        lua_impl_showLoadError(errorType);
15✔
507
                }
508
                extraErrorWarningPrefix = nullptr;
785✔
509
                delete[] buff;
785✔
510
                if (DidEmitByte() && (-1 != passToExec) && showWarning) {
785✔
511
                        const EWStatus warningType = (1 == passToExec || 2 == passToExec) ? W_EARLY : W_PASS3;
30✔
512
                        WarningById(W_LUA_MC_PASS, nullptr, warningType);
30✔
513
                }
514
        }
515

516
        ++CompiledCurrentLine;
1,025✔
517
        substitutedLine = line;                // override substituted list line for ENDLUA
1,025✔
518
}
1,025✔
519

520
void dirINCLUDELUA() {
51✔
521
        // lazy init of Lua scripting upon first hit of INCLUDELUA directive
522
        if (nullptr == LUA) lua_impl_init();
51✔
523
        assert(LUA);
51✔
524

525
        if (1 != pass) {
51✔
526
                SkipToEol(lp);                // skip till EOL (colon), to avoid parsing file name
34✔
527
                return;
34✔
528
        }
529
        std::unique_ptr<char[]> fnaam(GetFileName(lp));
17✔
530
        EDelimiterType dt = GetDelimiterOfLastFileName();
17✔
531
        char* fullpath = GetPath(fnaam.get(), NULL, DT_ANGLE == dt);
17✔
532
        if (!fullpath[0]) {
17✔
533
                Error("[INCLUDELUA] File doesn't exist", fnaam.get(), EARLY);
3✔
534
        } else {
535
                extraErrorWarningPrefix = lua_err_prefix;
14✔
536
                fileNameFull = ArchiveFilename(fullpath);        // get const pointer into archive
14✔
537
                if (luaL_dofile(LUA, fileNameFull)) {
14✔
538
                        lua_impl_showLoadError(EARLY);
1✔
539
                }
540
                extraErrorWarningPrefix = nullptr;
14✔
541
        }
542
        free(fullpath);
17✔
543
}
17✔
544

545
#endif //USE_LUA
546

547
////////////////////////////////////////////////////////////////////////////////////////////
548
// close LUA engine and release everything related
549
void lua_impl_close() {
496✔
550
        #ifdef USE_LUA
551
                // if Lua was used and initialised, release everything
552
                if (LUA) lua_close(LUA);
496✔
553
        #endif //USE_LUA
554

555
        // do nothing when Lua is compile-time disabled
556
}
496✔
557

558
//eof lua_sjasm.cpp
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc