Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/LuaTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1817,6 +1817,14 @@ export class LuaTransformer {
);
}

if (!ts.isCallLikeExpression(expression)) {
// Assign expression statements to dummy to make sure they're legal lua
return tstl.createVariableDeclarationStatement(
tstl.createAnnonymousIdentifier(),
this.transformExpression(expression)
);
}

return tstl.createExpressionStatement(this.transformExpression(expression));
}

Expand Down Expand Up @@ -3481,7 +3489,10 @@ export class LuaTransformer {
const logCall1 = tstl.createCallExpression(log1, params);
const e = tstl.createNumericLiteral(expressionName === "log10" ? Math.LN10 : Math.LN2);
const div = tstl.createBinaryExpression(logCall1, e, tstl.SyntaxKind.DivisionOperator);
return tstl.createParenthesizedExpression(div, node);
return ts.isExpressionStatement(node.parent)
// if used as a stand-alone statement, needs to be a call expression to be valid lua
? this.createImmediatelyInvokedFunctionExpression([], div, node)
: tstl.createParenthesizedExpression(div, node);
}

// math.log(1 + x)
Expand Down Expand Up @@ -4235,7 +4246,8 @@ export class LuaTransformer {
{
const body = statements ? statements.slice(0) : [];
body.push(tstl.createReturnStatement(Array.isArray(result) ? result : [result]));
const iife = tstl.createFunctionExpression(tstl.createBlock(body));
const flags = statements.length === 0 ? tstl.FunctionExpressionFlags.Inline : tstl.FunctionExpressionFlags.None;
const iife = tstl.createFunctionExpression(tstl.createBlock(body), undefined, undefined, undefined, flags);
return tstl.createCallExpression(tstl.createParenthesizedExpression(iife), [], tsOriginal);
}

Expand Down
2 changes: 1 addition & 1 deletion test/unit/compiler/configuration/options.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ test.each([LuaTarget.LuaJIT, "jit", "JiT"])("Options luaTarget case-insensitive
const options = { luaTarget: target as LuaTarget };
const result = util.transpileString("~a", options);

expect(result).toBe("bit.bnot(a);");
expect(result).toBe("local ____ = bit.bnot(a);");
});

test.each([LuaLibImportKind.None, "none", "NoNe"])(
Expand Down
77 changes: 51 additions & 26 deletions test/unit/expressions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ test.each([
{ input: "++i", lua: "i = i + 1;" },
{ input: "i--", lua: "i = i - 1;" },
{ input: "--i", lua: "i = i - 1;" },
{ input: "!a", lua: "not a;" },
{ input: "-a", lua: "-a;" },
{ input: "+a", lua: "a;" },
{ input: "!a", lua: "local ____ = not a;" },
{ input: "-a", lua: "local ____ = -a;" },
{ input: "+a", lua: "local ____ = a;" },
{
input: "let a = delete tbl['test']",
lua: "local a = (function()\n tbl.test = nil;\n return true;\nend)();",
Expand Down Expand Up @@ -106,54 +106,54 @@ test.each([
});

test.each([
{ input: "~a", lua: "bit.bnot(a);" },
{ input: "a&b", lua: "bit.band(a, b);" },
{ input: "~a", lua: "local ____ = bit.bnot(a);" },
{ input: "a&b", lua: "local ____ = bit.band(a, b);" },
{ input: "a&=b", lua: "a = bit.band(a, b);" },
{ input: "a|b", lua: "bit.bor(a, b);" },
{ input: "a|b", lua: "local ____ = bit.bor(a, b);" },
{ input: "a|=b", lua: "a = bit.bor(a, b);" },
{ input: "a^b", lua: "bit.bxor(a, b);" },
{ input: "a^b", lua: "local ____ = bit.bxor(a, b);" },
{ input: "a^=b", lua: "a = bit.bxor(a, b);" },
{ input: "a<<b", lua: "bit.lshift(a, b);" },
{ input: "a<<b", lua: "local ____ = bit.lshift(a, b);" },
{ input: "a<<=b", lua: "a = bit.lshift(a, b);" },
{ input: "a>>b", lua: "bit.arshift(a, b);" },
{ input: "a>>b", lua: "local ____ = bit.arshift(a, b);" },
{ input: "a>>=b", lua: "a = bit.arshift(a, b);" },
{ input: "a>>>b", lua: "bit.rshift(a, b);" },
{ input: "a>>>b", lua: "local ____ = bit.rshift(a, b);" },
{ input: "a>>>=b", lua: "a = bit.rshift(a, b);" },
])("Bitop [JIT] (%p)", ({ input, lua }) => {
const options = { luaTarget: LuaTarget.LuaJIT, luaLibImport: LuaLibImportKind.None };
expect(util.transpileString(input, options)).toBe(lua);
});

test.each([
{ input: "~a", lua: "bit32.bnot(a);" },
{ input: "a&b", lua: "bit32.band(a, b);" },
{ input: "~a", lua: "local ____ = bit32.bnot(a);" },
{ input: "a&b", lua: "local ____ = bit32.band(a, b);" },
{ input: "a&=b", lua: "a = bit32.band(a, b);" },
{ input: "a|b", lua: "bit32.bor(a, b);" },
{ input: "a|b", lua: "local ____ = bit32.bor(a, b);" },
{ input: "a|=b", lua: "a = bit32.bor(a, b);" },
{ input: "a^b", lua: "bit32.bxor(a, b);" },
{ input: "a^b", lua: "local ____ = bit32.bxor(a, b);" },
{ input: "a^=b", lua: "a = bit32.bxor(a, b);" },
{ input: "a<<b", lua: "bit32.lshift(a, b);" },
{ input: "a<<b", lua: "local ____ = bit32.lshift(a, b);" },
{ input: "a<<=b", lua: "a = bit32.lshift(a, b);" },
{ input: "a>>b", lua: "bit32.arshift(a, b);" },
{ input: "a>>b", lua: "local ____ = bit32.arshift(a, b);" },
{ input: "a>>=b", lua: "a = bit32.arshift(a, b);" },
{ input: "a>>>b", lua: "bit32.rshift(a, b);" },
{ input: "a>>>b", lua: "local ____ = bit32.rshift(a, b);" },
{ input: "a>>>=b", lua: "a = bit32.rshift(a, b);" },
])("Bitop [5.2] (%p)", ({ input, lua }) => {
const options = { luaTarget: LuaTarget.Lua52, luaLibImport: LuaLibImportKind.None };
expect(util.transpileString(input, options)).toBe(lua);
});

test.each([
{ input: "~a", lua: "~a;" },
{ input: "a&b", lua: "a & b;" },
{ input: "~a", lua: "local ____ = ~a;" },
{ input: "a&b", lua: "local ____ = a & b;" },
{ input: "a&=b", lua: "a = a & b;" },
{ input: "a|b", lua: "a | b;" },
{ input: "a|b", lua: "local ____ = a | b;" },
{ input: "a|=b", lua: "a = a | b;" },
{ input: "a^b", lua: "a ~ b;" },
{ input: "a^b", lua: "local ____ = a ~ b;" },
{ input: "a^=b", lua: "a = a ~ b;" },
{ input: "a<<b", lua: "a << b;" },
{ input: "a<<b", lua: "local ____ = a << b;" },
{ input: "a<<=b", lua: "a = a << b;" },
{ input: "a>>>b", lua: "a >> b;" },
{ input: "a>>>b", lua: "local ____ = a >> b;" },
{ input: "a>>>=b", lua: "a = a >> b;" },
])("Bitop [5.3] (%p)", ({ input, lua }) => {
const options = { luaTarget: LuaTarget.Lua53, luaLibImport: LuaLibImportKind.None };
Expand Down Expand Up @@ -183,7 +183,7 @@ test.each([
{ input: "1*(3+4*2)", lua: "1 * (3 + 4 * 2);" },
{ input: "10-(4+5)", lua: "10 - (4 + 5);" },
])("Binary expressions ordering parentheses (%p)", ({ input, lua }) => {
expect(util.transpileString(input)).toBe(lua);
expect(util.transpileString(input)).toBe("local ____ = " + lua);
});

test.each([
Expand All @@ -208,11 +208,11 @@ test("Binary Comma Statement in For Loop", () => {
});

test("Null Expression", () => {
expect(util.transpileString("null")).toBe("nil;");
expect(util.transpileString("null")).toBe("local ____ = nil;");
});

test("Undefined Expression", () => {
expect(util.transpileString("undefined")).toBe("nil;");
expect(util.transpileString("undefined")).toBe("local ____ = nil;");
});

test.each([
Expand Down Expand Up @@ -553,3 +553,28 @@ test("Unsupported object literal element error", () => {
),
);
});

test.each([
'"foobar"',
"17",
"true",
"{}",
"[]",
"[].length",
"foo() + foo()",
"!foo()",
"foo()",
"typeof foo",
'"bar" in bar',
"foo as Function",
"Math.log2(2)",
"Math.log10(2)",
])("Expression statements (%p)", input => {
const code = `
function foo() { return 17; }
const bar = {};
${input};
return 1;
`;
expect(util.transpileAndExecute(code)).toBe(1);
});
8 changes: 5 additions & 3 deletions test/unit/math.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ test.each([
{ inp: "Math.sin()", expected: "math.sin();" },
{ inp: "Math.min()", expected: "math.min();" },
{ inp: "Math.atan2(2, 3)", expected: "math.atan(2 / 3);" },
{ inp: "Math.log2(3)", expected: `(math.log(3) / ${Math.LN2});` },
{ inp: "Math.log10(3)", expected: `(math.log(3) / ${Math.LN10});` },
{ inp: "Math.log2(3)", expected: `(function() return math.log(3) / ${Math.LN2}; end)();` },
{ inp: "Math.log10(3)", expected: `(function() return math.log(3) / ${Math.LN10}; end)();` },
{ inp: "const x = Math.log2(3)", expected: `local x = (math.log(3) / ${Math.LN2});` },
{ inp: "const x = Math.log10(3)", expected: `local x = (math.log(3) / ${Math.LN10});` },
{ inp: "Math.log1p(3)", expected: "math.log(1 + 3);" },
{ inp: "Math.round(3.3)", expected: "math.floor(3.3 + 0.5);" },
{ inp: "Math.PI", expected: "math.pi;" },
{ inp: "Math.PI", expected: "local ____ = math.pi;" },
])("Math (%p)", ({ inp, expected }) => {
const lua = util.transpileString(inp);

Expand Down
6 changes: 3 additions & 3 deletions test/unit/spreadElement.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ test("Spread Element Lua 5.1", () => {
test("Spread Element Lua 5.2", () => {
const options = { luaTarget: LuaTarget.Lua52, luaLibImport: LuaLibImportKind.None };
const lua = util.transpileString(`[...[0, 1, 2]]`, options);
expect(lua).toBe("{table.unpack({\n 0,\n 1,\n 2,\n})};");
expect(lua).toBe("local ____ = {table.unpack({\n 0,\n 1,\n 2,\n})};");
});

test("Spread Element Lua 5.3", () => {
const options = { luaTarget: LuaTarget.Lua53, luaLibImport: LuaLibImportKind.None };
const lua = util.transpileString(`[...[0, 1, 2]]`, options);
expect(lua).toBe("{table.unpack({\n 0,\n 1,\n 2,\n})};");
expect(lua).toBe("local ____ = {table.unpack({\n 0,\n 1,\n 2,\n})};");
});

test("Spread Element Lua JIT", () => {
const options = { luaTarget: "JiT" as LuaTarget, luaLibImport: LuaLibImportKind.None };
const lua = util.transpileString(`[...[0, 1, 2]]`, options);
expect(lua).toBe("{unpack({\n 0,\n 1,\n 2,\n})};");
expect(lua).toBe("local ____ = {unpack({\n 0,\n 1,\n 2,\n})};");
});