Skip to content

Commit e36a767

Browse files
committed
improvements to vararg handling and added support for displaying multiple eval results
1 parent 4cb7b81 commit e36a767

File tree

6 files changed

+152
-68
lines changed

6 files changed

+152
-68
lines changed

debugger/debugger.ts

Lines changed: 72 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@ export interface Vars {
4545
[name: string]: Var | undefined;
4646
}
4747

48-
export interface Local extends Var {
48+
export interface IndexedVar extends Var {
4949
index: number;
5050
}
5151

5252
export interface Locals {
53-
[name: string]: Local;
53+
vars: { [name: string]: IndexedVar };
54+
varargs?: IndexedVar[];
5455
}
5556

5657
export namespace Debugger {
@@ -165,21 +166,21 @@ export namespace Debugger {
165166
}
166167

167168
function getLocals(level: number, thread?: Thread): Locals {
168-
const locs: Locals = {};
169+
const locs: Locals = {vars: {}};
169170

170171
if (thread === mainThreadName) {
171172
return locs; // Accessing locals for main thread, but we're in a coroutine right now
172173
}
173174

174175
//Validate level
176+
let info: debug.FunctionInfo | undefined;
175177
if (thread) {
176-
if (!debug.getinfo(thread, level, "l")) {
177-
return locs;
178-
}
178+
info = debug.getinfo(thread, level, "u");
179179
} else {
180-
if (!debug.getinfo(level + 1, "l")) {
181-
return locs;
182-
}
180+
info = debug.getinfo(level + 1, "u");
181+
}
182+
if (!info) {
183+
return locs;
183184
}
184185

185186
let name: string | undefined;
@@ -198,47 +199,49 @@ export namespace Debugger {
198199
}
199200

200201
if (isValidIdentifier(name)) {
201-
locs[name] = {val, index, type: type(val)};
202+
locs.vars[name] = {val, index, type: type(val)};
202203
}
203204

204205
++index;
205206
}
206207

207208
//Varargs
208-
index = -1;
209-
while (true) {
210-
if (thread) {
211-
[name, val] = debug.getlocal(thread, level, index);
212-
} else {
213-
[name, val] = debug.getlocal(level + 1, index);
209+
const isVarArg = (info as unknown as { isvararg: boolean | undefined }).isvararg;
210+
if (isVarArg !== false) {
211+
if (isVarArg) {
212+
locs.varargs = [];
214213
}
215-
if (!name) {
216-
break;
217-
}
218-
219-
[name] = name.gsub("[^a-zA-Z0-9_]+", "_");
220-
let key = `${name}_${-index}`;
221-
while (locs[key]) {
222-
key = `${key}_`;
214+
index = -1;
215+
while (true) {
216+
if (thread) {
217+
[name, val] = debug.getlocal(thread, level, index);
218+
} else {
219+
[name, val] = debug.getlocal(level + 1, index);
220+
}
221+
if (!name) {
222+
break;
223+
}
224+
if (!locs.varargs) {
225+
locs.varargs = [];
226+
}
227+
table.insert(locs.varargs, {val, index, type: type(val)});
228+
--index;
223229
}
224-
locs[key] = {val, index, type: type(val)};
225-
226-
--index;
227230
}
228231

229232
return locs;
230233
}
231234

232235
function getUpvalues(info: debug.FunctionInfo): Locals {
233-
const ups: Locals = {};
236+
const ups: Locals = {vars: {}};
234237

235238
if (!info.nups || !info.func) {
236239
return ups;
237240
}
238241

239242
for (const index of $range(1, info.nups)) {
240243
const [name, val] = debug.getupvalue(info.func, index);
241-
ups[luaAssert(name)] = {val, index, type: type(val)};
244+
ups.vars[luaAssert(name)] = {val, index, type: type(val)};
242245
}
243246

244247
return ups;
@@ -365,7 +368,7 @@ export namespace Debugger {
365368
level: number,
366369
info: debug.FunctionInfo,
367370
thread?: Thread
368-
): LuaMultiReturn<[true, unknown] | [false, string]> {
371+
): LuaMultiReturn<[true, ...unknown[]] | [false, string]> {
369372
if (thread === mainThreadName) {
370373
return $multi(false, "unable to access main thread while running in a coroutine");
371374
}
@@ -381,15 +384,15 @@ export namespace Debugger {
381384
{},
382385
{
383386
__index(this: unknown, name: string) {
384-
const variable = locs[name] ?? ups[name];
387+
const variable = locs.vars[name] ?? ups.vars[name];
385388
if (variable !== undefined) {
386389
return variable.val;
387390
} else {
388391
return fenv[name];
389392
}
390393
},
391394
__newindex(this: unknown, name: string, val: unknown) {
392-
const variable = locs[name] ?? ups[name];
395+
const variable = locs.vars[name] ?? ups.vars[name];
393396
if (variable !== undefined) {
394397
variable.type = type(val);
395398
variable.val = val;
@@ -400,25 +403,34 @@ export namespace Debugger {
400403
}
401404
);
402405

403-
const [func, err] = loadLuaString(statement, env);
406+
const loadStringResult = loadLuaString(statement, env);
407+
const func = loadStringResult[0];
404408
if (!func) {
405-
return $multi(false, err as string);
409+
return $multi(false, loadStringResult[1]);
410+
}
411+
412+
const varargs: unknown[] = [];
413+
if (locs.varargs) {
414+
for (const vararg of locs.varargs) {
415+
table.insert(varargs, vararg.val);
416+
}
406417
}
407418

408-
const [success, result] = pcall(func);
409-
if (success) {
410-
for (const [_, loc] of pairs(locs)) {
419+
const results = pcall<unknown[], unknown[]>(func, ...unpack(varargs));
420+
if (results[0]) {
421+
for (const [_, loc] of pairs(locs.vars)) {
411422
if (thread) {
412423
debug.setlocal(thread, level, loc.index, loc.val);
413424
} else {
414425
debug.setlocal(level, loc.index, loc.val);
415426
}
416427
}
417-
for (const [_, up] of pairs(ups)) {
428+
for (const [_, up] of pairs(ups.vars)) {
418429
debug.setupvalue(luaAssert(info.func), up.index, up.val);
419430
}
431+
return $multi(true, ...unpack(results, 2));
420432
}
421-
return $multi(success as true, result);
433+
return $multi(false, results[1]);
422434
}
423435

424436
function getInput(): string | undefined {
@@ -455,6 +467,8 @@ export namespace Debugger {
455467
return stack;
456468
}
457469

470+
const varArgTable: LuaDebug.VarArgTable = "{...}";
471+
458472
let breakAtDepth = -1;
459473
let breakInThread: Thread | undefined;
460474
let updateHook: { (): void };
@@ -603,13 +617,20 @@ export namespace Debugger {
603617

604618
} else if (inp === "locals") {
605619
const locs = getLocals(frame + frameOffset, currentThread !== activeThread ? currentThread : undefined);
606-
mapVarNames(locs, sourceMap);
607-
Send.vars(locs);
620+
mapVarNames(locs.vars, sourceMap);
621+
if (locs.varargs) {
622+
const varargVals: unknown[] = [];
623+
for (const vararg of locs.varargs) {
624+
table.insert(varargVals, vararg.val);
625+
}
626+
locs.vars[varArgTable] = {val: varargVals, index: -1, type: "table"};
627+
}
628+
Send.vars(locs.vars);
608629

609630
} else if (inp === "ups") {
610631
const ups = getUpvalues(info);
611-
mapVarNames(ups, sourceMap);
612-
Send.vars(ups);
632+
mapVarNames(ups.vars, sourceMap);
633+
Send.vars(ups.vars);
613634

614635
} else if (inp === "globals") {
615636
const globs = getGlobals(
@@ -691,16 +712,16 @@ export namespace Debugger {
691712

692713
} else {
693714
const mappedExpression = mapExpressionNames(expression, sourceMap);
694-
const [s, r] = execute(
715+
const results = execute(
695716
`return ${mappedExpression}`,
696717
frame + frameOffset,
697718
info,
698719
currentThread !== activeThread ? currentThread : undefined
699720
);
700-
if (s) {
701-
Send.result(r);
721+
if (results[0]) {
722+
Send.result(...unpack(results, 2));
702723
} else {
703-
Send.error(r as string);
724+
Send.error(results[1]);
704725
}
705726
}
706727

@@ -737,16 +758,16 @@ export namespace Debugger {
737758
Send.error("Bad statement");
738759

739760
} else {
740-
const [s, r] = execute(
761+
const results = execute(
741762
statement,
742763
frame + frameOffset,
743764
info,
744765
currentThread !== activeThread ? currentThread : undefined
745766
);
746-
if (s) {
747-
Send.result(r);
767+
if (results[0]) {
768+
Send.result(...unpack(results, 2));
748769
} else {
749-
Send.error(r as string);
770+
Send.error(results[1]);
750771
}
751772
}
752773

debugger/luafuncs.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ declare function load(
2929
chunkname?: string,
3030
mode?: "b" | "t" | "bt",
3131
env?: AnyTable
32-
): LuaMultiReturn<[{ (this: void): unknown }, undefined] | [undefined, string]>;
32+
): LuaMultiReturn<[{ (this: void): LuaMultiReturn<unknown[]> }, undefined] | [undefined, string]>;
3333

3434
declare function loadfile(
3535
this: void,
@@ -69,14 +69,14 @@ export interface Env {
6969
export function loadLuaString(
7070
str: string,
7171
env?: Env
72-
): LuaMultiReturn<[{ (this: void): unknown }, undefined] | [undefined, string]> {
72+
): LuaMultiReturn<[{ (this: void): LuaMultiReturn<unknown[]> }, undefined] | [undefined, string]> {
7373
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
7474
if (setfenv !== undefined) {
7575
const [f, e] = loadstring(str, str);
7676
if (f && env) {
7777
setfenv(f, env);
7878
}
79-
return $multi(f as { (this: void): unknown }, e as undefined);
79+
return $multi(f as { (this: void): LuaMultiReturn<unknown[]> }, e as undefined);
8080

8181
} else {
8282
return load(str, str, "t", env);

debugger/protocol.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ declare namespace LuaDebug {
8080

8181
interface Result extends MessageBase {
8282
type: "result";
83-
result: Value;
83+
results: Value[];
8484
}
8585

8686
interface Breakpoint {
@@ -108,6 +108,8 @@ declare namespace LuaDebug {
108108

109109
type Message = Error | DebugBreak | Result | Stack | Variables | Properties | Breakpoints | Threads;
110110

111+
type VarArgTable = "{...}";
112+
111113
type StartToken = "@lldbg|";
112114
type EndToken = "|lldbg@";
113115

debugger/send.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,12 @@ export namespace Send {
9494
send(dbgBreak);
9595
}
9696

97-
export function result(value: unknown): void {
98-
const dbgVal: LuaDebug.Value = {type: type(value), value: getPrintableValue(value)};
99-
const dbgResult: LuaDebug.Result = {tag: "$luaDebug", type: "result", result: dbgVal};
97+
export function result(...values: unknown[]): void {
98+
const results: LuaDebug.Value[] = Format.makeExplicitArray();
99+
for (const value of values) {
100+
table.insert(results, {type: type(value), value: getPrintableValue(value)});
101+
}
102+
const dbgResult: LuaDebug.Result = {tag: "$luaDebug", type: "result", results};
100103
send(dbgResult);
101104
}
102105

0 commit comments

Comments
 (0)