Skip to content

Commit 9c8c333

Browse files
committed
fixed issues with non-standard values returned from len metamethod and overall handling of errors during evaluation
1 parent ba773dc commit 9c8c333

File tree

5 files changed

+65
-22
lines changed

5 files changed

+65
-22
lines changed

debugger/debugger.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ export namespace Debugger {
254254
) {
255255
metaStack.set(tbl, true);
256256

257-
const meta = getmetatable(tbl) as Record<string, unknown> | undefined;
257+
const meta = debug.getmetatable(tbl) as Record<string, unknown> | undefined;
258258
if (meta !== undefined && type(meta.__index) === "table" && metaStack.get(meta) === undefined) {
259259
populateGlobals(globs, meta.__index as Record<string, unknown>, metaStack);
260260
}
@@ -475,8 +475,11 @@ export namespace Debugger {
475475
let breakInThread: Thread | undefined;
476476
let updateHook: { (): void };
477477
let ignorePatterns: string[] | undefined;
478+
let inDebugBreak = false;
478479

479480
function debugBreak(activeThread: Thread, stackOffset: number, activeLine?: number) {
481+
assert(!inDebugBreak);
482+
inDebugBreak = true;
480483
++stackOffset;
481484
const activeStack = getStack(stackOffset);
482485
if (activeLine && activeStack.length > 0) {
@@ -503,6 +506,7 @@ export namespace Debugger {
503506

504507
} else if (inp === "autocont" || inp === "autocontinue") {
505508
updateHook();
509+
inDebugBreak = false;
506510
return false; //Check breakpoints before resuming
507511

508512
} else if (inp === "help") {
@@ -811,6 +815,7 @@ export namespace Debugger {
811815
}
812816

813817
updateHook();
818+
inDebugBreak = false;
814819
return true; //Resume execution immediately without checking breakpoints
815820
}
816821

@@ -987,7 +992,7 @@ export namespace Debugger {
987992
if (skipNextBreak) {
988993
skipNextBreak = false;
989994

990-
} else {
995+
} else if (!inDebugBreak) {
991996
const thread = getActiveThread();
992997
Send.debugBreak(message, "error", getThreadId(thread));
993998
debugBreak(thread, level);

debugger/luafuncs.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,15 @@ export const luaDebugTraceback = debug.traceback;
4848
export const luaCoroutineCreate = coroutine.create;
4949
export const luaCoroutineResume = coroutine.resume;
5050

51+
export const luaLenMetamethodSupported = (() => (setmetatable({}, {__len: () => 42}) as unknown[]).length === 42)();
52+
5153
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
5254
export const luaRawLen = rawlen ?? function<T extends AnyTable>(v: T | string): number {
53-
const mt = getmetatable(v);
55+
if (!luaLenMetamethodSupported) {
56+
return (v as unknown as unknown[]).length;
57+
}
58+
59+
const mt = debug.getmetatable(v);
5460
if (!mt || !rawget(mt as {__len?: unknown}, "__len")) {
5561
return (v as unknown as unknown[]).length;
5662
} else {

debugger/protocol.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ declare namespace LuaDebug {
6060
type: string;
6161
value?: string;
6262
length?: number;
63+
error?: string;
6364
}
6465

6566
interface Variable extends Value {
@@ -75,7 +76,7 @@ declare namespace LuaDebug {
7576
type: "properties";
7677
properties: Variable[];
7778
metatable?: Value;
78-
length?: number;
79+
length?: Value;
7980
}
8081

8182
interface Result extends MessageBase {

debugger/send.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
//SOFTWARE.
2222

23-
import {luaError, luaRawLen} from "./luafuncs";
23+
import {luaError, luaLenMetamethodSupported, luaRawLen} from "./luafuncs";
2424
import {Format} from "./format";
2525
import {Vars} from "./debugger";
2626
import {Thread, mainThread, mainThreadName} from "./thread";
@@ -173,12 +173,25 @@ export namespace Send {
173173
table.insert(dbgProperties.properties, dbgVar);
174174
}
175175
}
176+
176177
const meta = getmetatable(tbl);
177178
if (meta) {
178179
dbgProperties.metatable = {type: type(meta), value: getPrintableValue(meta)};
179180
}
180-
if (len > 0 || (dbgProperties.properties.length === 0 && !dbgProperties.metatable)) {
181-
dbgProperties.length = len;
181+
182+
const [lenStatus, tblLen] = pcall(() => (tbl as unknown[]).length as unknown);
183+
if (!lenStatus) {
184+
dbgProperties.length = {type: type(tblLen), error: tblLen as string};
185+
} else if (tblLen !== 0) {
186+
dbgProperties.length = {type: type(tblLen), value: tostring(tblLen)};
187+
} else {
188+
const mt = debug.getmetatable(tbl);
189+
if (
190+
(!mt && dbgProperties.properties.length === 0)
191+
|| (mt && luaLenMetamethodSupported && (mt as {__len?: unknown}).__len)
192+
) {
193+
dbgProperties.length = {type: type(tblLen), value: tostring(tblLen)};
194+
}
182195
}
183196
}
184197
send(dbgProperties);

extension/luaDebugSession.ts

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -527,10 +527,15 @@ export class LuaDebugSession extends LoggingDebugSession {
527527
}
528528

529529
if (typeof vars.length !== "undefined" && !isMultiResult) {
530-
const value: LuaDebug.Value = {type: "number", value: vars.length.toString()};
531-
variables.push(this.buildVariable(value, `#${baseName}`, tableLengthDisplayName));
530+
variables.push(this.buildVariable(vars.length, `#${baseName}`, tableLengthDisplayName));
532531
}
533532

533+
} else if (vars.type === "error") {
534+
response.success = false;
535+
response.message = this.filterErrorMessage(vars.error);
536+
this.sendResponse(response);
537+
return;
538+
534539
} else {
535540
response.success = false;
536541
}
@@ -648,8 +653,7 @@ export class LuaDebugSession extends LoggingDebugSession {
648653
this.showOutput(result.error, OutputCategory.Error);
649654
}
650655
response.success = false;
651-
const errorMsg = /^\[.+\]:\d+:(.+)/.exec(result.error);
652-
response.message = (errorMsg !== null && errorMsg.length > 1) ? errorMsg[1] : result.error;
656+
response.message = result.error;
653657
}
654658

655659
} else {
@@ -688,16 +692,15 @@ export class LuaDebugSession extends LoggingDebugSession {
688692
} else if (msg.results.length === 1) {
689693
const result = msg.results[0];
690694
const variablesReference = result.type === "table" ? this.variableHandles.create(expression) : 0;
691-
const value = result.value ?? `[${result.type}]`;
692-
return {success: true, value, variablesReference};
695+
return {success: true, value: this.getValueString(result), variablesReference};
693696
} else {
694697
const variablesReference = this.variableHandles.create(`@({${expression}})`);
695-
const value = `(${msg.results.map(r => r.value ?? `[${r.type}]`).join(", ")})`;
698+
const value = `(${msg.results.map(r => this.getValueString(r)).join(", ")})`;
696699
return {success: true, value, variablesReference};
697700
}
698701

699702
} else if (msg.type === "error") {
700-
return {success: false, error: msg.error};
703+
return {success: false, error: this.filterErrorMessage(msg.error)};
701704

702705
} else {
703706
return {success: false};
@@ -710,15 +713,15 @@ export class LuaDebugSession extends LoggingDebugSession {
710713
let valueStr: string;
711714
let ref: number | undefined;
712715
if (refName === "...") {
713-
valueStr = `(${variable.value ?? ""})`;
716+
valueStr = typeof variable.error !== "undefined"
717+
? `[error: ${this.filterErrorMessage(variable.error)}]`
718+
: `(${variable.value ?? ""})`;
714719
ref = variable.type === "table" ? this.variableHandles.create("@({...})") : 0;
715720
} else if (variable.type === "table") {
716-
valueStr = variable.value ?? "[table]";
721+
valueStr = this.getValueString(variable);
717722
ref = this.variableHandles.create(refName);
718-
} else if (typeof variable.value === "undefined") {
719-
valueStr = `[${variable.type}]`;
720723
} else {
721-
valueStr = variable.value;
724+
valueStr = this.getValueString(variable);
722725
}
723726
const name = typeof variableName !== "undefined" ? variableName : (variable as LuaDebug.Variable).name;
724727
const indexedVariables = typeof variable.length !== "undefined" && variable.length > 0
@@ -739,6 +742,21 @@ export class LuaDebugSession extends LoggingDebugSession {
739742
return value;
740743
}
741744

745+
private filterErrorMessage(errorMsg: string) {
746+
const errorOnly = /^.+:\d+:\s*(.+)/.exec(errorMsg);
747+
return (errorOnly !== null && errorOnly.length > 1) ? errorOnly[1] : errorMsg;
748+
}
749+
750+
private getValueString(value: LuaDebug.Value) {
751+
if (typeof value.error !== "undefined") {
752+
return `[error: ${this.filterErrorMessage(value.error)}]`;
753+
} else if (typeof value.value !== "undefined") {
754+
return value.value;
755+
} else {
756+
return `[${value.type}]`;
757+
}
758+
}
759+
742760
private resolvePath(filePath: string) {
743761
if (filePath.length === 0) {
744762
return;
@@ -804,7 +822,7 @@ export class LuaDebugSession extends LoggingDebugSession {
804822
if (resultMsg.type === "result") {
805823
for (const result of resultMsg.results) {
806824
if (typeof result.value !== "undefined") {
807-
this.showOutput(result.value, OutputCategory.Info);
825+
this.showOutput(this.getValueString(result), OutputCategory.Info);
808826
}
809827
}
810828
} else if (resultMsg.type === "error") {
@@ -820,7 +838,7 @@ export class LuaDebugSession extends LoggingDebugSession {
820838
if (resultMsg.type === "result") {
821839
for (const result of resultMsg.results) {
822840
if (typeof result.value !== "undefined") {
823-
this.showOutput(result.value, OutputCategory.Info);
841+
this.showOutput(this.getValueString(result), OutputCategory.Info);
824842
}
825843
}
826844
} else if (resultMsg.type === "error") {

0 commit comments

Comments
 (0)