From 631f3d3925de8ec1e23329e934c48bf6b8da6dff Mon Sep 17 00:00:00 2001 From: emmachase Date: Sun, 12 Jan 2025 20:57:20 -0800 Subject: [PATCH 1/3] Allow stacktraces in Lua 5.1 and LuaJIT * Fix the constructor passed when getting the stacktrace * Fix testEachVersion builder --- src/lualib/Error.ts | 10 ++++++++-- test/unit/error.spec.ts | 23 +++++++++++++++++++++++ test/util.ts | 4 ++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/lualib/Error.ts b/src/lualib/Error.ts index ea9cba478..c19e9792b 100644 --- a/src/lualib/Error.ts +++ b/src/lualib/Error.ts @@ -1,3 +1,5 @@ +import { __TS__New } from "./New"; + interface ErrorType { name: string; new (...args: any[]): Error; @@ -22,6 +24,10 @@ function getErrorStack(constructor: () => any): string | undefined { if (_VERSION.includes("Lua 5.0")) { return debug.traceback(`[Level ${level}]`); + } else if (_VERSION === "Lua 5.1") { + // Lua 5.1 and LuaJIT have a bug where it's not possible to specify the level without a message. + // @ts-ignore Fails when compiled with Lua 5.0 types + return string.sub(debug.traceback("", level), 2); } else { // @ts-ignore Fails when compiled with Lua 5.0 types return debug.traceback(undefined, level); @@ -33,7 +39,7 @@ function wrapErrorToString(getDescription: (this: T) => string) const description = getDescription.call(this as T); const caller = debug.getinfo(3, "f"); // @ts-ignore Fails when compiled with Lua 5.0 types - const isClassicLua = _VERSION.includes("Lua 5.0") || _VERSION === "Lua 5.1"; + const isClassicLua = _VERSION.includes("Lua 5.0"); if (isClassicLua || (caller && caller.func !== error)) { return description; } else { @@ -55,7 +61,7 @@ export const Error: ErrorConstructor = initErrorClass( public stack?: string; constructor(public message = "") { - this.stack = getErrorStack((this.constructor as any).new); + this.stack = getErrorStack(__TS__New as any); const metatable = getmetatable(this); if (metatable && !metatable.__errorToStringPatched) { metatable.__errorToStringPatched = true; diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index 388fee290..811be52a0 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -1,4 +1,5 @@ import * as util from "../util"; +import * as tstl from "../../src"; test("throwString", () => { util.testFunction` @@ -343,3 +344,25 @@ test("still works without debug module", () => { stack: undefined, }); }); + +util.testEachVersion( + "error stacktrace omits constructor and __TS_New", + () => util.testFunction` + const e = new Error(); + return e.stack; + `, + { + ...util.expectEachVersionExceptJit(builder => { + builder.expectToHaveNoDiagnostics(); + const luaResult = builder.getLuaExecutionResult(); + expect(luaResult.split('\n').length).toBe(4); + }), + + // 5.0 debug.traceback doesn't support levels + [tstl.LuaTarget.Lua50]: builder => { + builder.expectToHaveNoDiagnostics(); + const luaResult = builder.getLuaExecutionResult(); + expect(luaResult).toContain("Level 4"); + }, + } +); diff --git a/test/util.ts b/test/util.ts index 7ebe1ccd3..501b24bfb 100644 --- a/test/util.ts +++ b/test/util.ts @@ -43,7 +43,7 @@ function getLuaBindingsForVersion(target: tstl.LuaTarget): { lauxlib: LauxLib; l return { lauxlib, lua, lualib }; } if (target === tstl.LuaTarget.LuaJIT) { - throw Error("Can't use executeLua() or expectToMatchJsResult() wit LuaJIT as target!"); + throw Error("Can't use executeLua() or expectToMatchJsResult() with LuaJIT as target!"); } const { lauxlib, lua, lualib } = require("lua-wasm-bindings/dist/lua.54"); @@ -63,7 +63,7 @@ export function testEachVersion( ): void { for (const version of Object.values(tstl.LuaTarget) as tstl.LuaTarget[]) { const specialBuilder = special?.[version]; - if (specialBuilder === false) return; + if (specialBuilder === false) continue; const testName = name === undefined ? version : `${name} [${version}]`; defineTest(testName, () => { From 9471a838c40bf7cb631205fbf1f40707f48a4e08 Mon Sep 17 00:00:00 2001 From: emmachase Date: Mon, 13 Jan 2025 12:51:35 -0800 Subject: [PATCH 2/3] Fix lint --- src/lualib/Error.ts | 1 + test/unit/error.spec.ts | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lualib/Error.ts b/src/lualib/Error.ts index c19e9792b..ae5deb05b 100644 --- a/src/lualib/Error.ts +++ b/src/lualib/Error.ts @@ -24,6 +24,7 @@ function getErrorStack(constructor: () => any): string | undefined { if (_VERSION.includes("Lua 5.0")) { return debug.traceback(`[Level ${level}]`); + // @ts-ignore Fails when compiled with Lua 5.0 types } else if (_VERSION === "Lua 5.1") { // Lua 5.1 and LuaJIT have a bug where it's not possible to specify the level without a message. // @ts-ignore Fails when compiled with Lua 5.0 types diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index 811be52a0..d3e8e3478 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -355,13 +355,15 @@ util.testEachVersion( ...util.expectEachVersionExceptJit(builder => { builder.expectToHaveNoDiagnostics(); const luaResult = builder.getLuaExecutionResult(); - expect(luaResult.split('\n').length).toBe(4); + // eslint-disable-next-line jest/no-standalone-expect + expect(luaResult.split('\n')).toHaveLength(4); }), // 5.0 debug.traceback doesn't support levels - [tstl.LuaTarget.Lua50]: builder => { + [tstl.LuaTarget.Lua50](builder) { builder.expectToHaveNoDiagnostics(); const luaResult = builder.getLuaExecutionResult(); + // eslint-disable-next-line jest/no-standalone-expect expect(luaResult).toContain("Level 4"); }, } From c454e3aa31a1327e9b8b71fd4220fdbcc171f59a Mon Sep 17 00:00:00 2001 From: emmachase Date: Mon, 13 Jan 2025 12:54:30 -0800 Subject: [PATCH 3/3] Run prettier --- test/unit/error.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index d3e8e3478..05399d492 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -356,15 +356,15 @@ util.testEachVersion( builder.expectToHaveNoDiagnostics(); const luaResult = builder.getLuaExecutionResult(); // eslint-disable-next-line jest/no-standalone-expect - expect(luaResult.split('\n')).toHaveLength(4); + expect(luaResult.split("\n")).toHaveLength(4); }), - + // 5.0 debug.traceback doesn't support levels [tstl.LuaTarget.Lua50](builder) { builder.expectToHaveNoDiagnostics(); const luaResult = builder.getLuaExecutionResult(); // eslint-disable-next-line jest/no-standalone-expect expect(luaResult).toContain("Level 4"); - }, + }, } );