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
88 changes: 74 additions & 14 deletions src/LuaPrinter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,42 @@ export class LuaPrinter {
[lua.SyntaxKind.BitwiseLeftShiftOperator]: "<<",
[lua.SyntaxKind.BitwiseNotOperator]: "~",
};
private static operatorPrecedence: Record<lua.Operator, number> = {
[lua.SyntaxKind.OrOperator]: 1,
[lua.SyntaxKind.AndOperator]: 2,

[lua.SyntaxKind.EqualityOperator]: 3,
[lua.SyntaxKind.InequalityOperator]: 3,
[lua.SyntaxKind.LessThanOperator]: 3,
[lua.SyntaxKind.LessEqualOperator]: 3,
[lua.SyntaxKind.GreaterThanOperator]: 3,
[lua.SyntaxKind.GreaterEqualOperator]: 3,

[lua.SyntaxKind.BitwiseOrOperator]: 4,
[lua.SyntaxKind.BitwiseExclusiveOrOperator]: 5,
[lua.SyntaxKind.BitwiseAndOperator]: 6,

[lua.SyntaxKind.BitwiseLeftShiftOperator]: 7,
[lua.SyntaxKind.BitwiseRightShiftOperator]: 7,

[lua.SyntaxKind.ConcatOperator]: 8,

[lua.SyntaxKind.AdditionOperator]: 9,
[lua.SyntaxKind.SubtractionOperator]: 9,

[lua.SyntaxKind.MultiplicationOperator]: 10,
[lua.SyntaxKind.DivisionOperator]: 10,
[lua.SyntaxKind.FloorDivisionOperator]: 10,
[lua.SyntaxKind.ModuloOperator]: 10,

[lua.SyntaxKind.NotOperator]: 11,
[lua.SyntaxKind.LengthOperator]: 11,
[lua.SyntaxKind.NegationOperator]: 11,
[lua.SyntaxKind.BitwiseNotOperator]: 11,

[lua.SyntaxKind.PowerOperator]: 12,
};
private static rightAssociativeOperators = new Set([lua.SyntaxKind.ConcatOperator, lua.SyntaxKind.PowerOperator]);

private currentIndent = "";
private luaFile: string;
Expand Down Expand Up @@ -676,34 +712,49 @@ export class LuaPrinter {
const chunks: SourceChunk[] = [];

chunks.push(this.printOperator(expression.operator));
chunks.push(this.printExpressionInParenthesesIfNeeded(expression.operand));
chunks.push(
this.printExpressionInParenthesesIfNeeded(
expression.operand,
LuaPrinter.operatorPrecedence[expression.operator]
)
);

return this.createSourceNode(expression, chunks);
}

public printBinaryExpression(expression: lua.BinaryExpression): SourceNode {
const chunks: SourceChunk[] = [];

chunks.push(this.printExpressionInParenthesesIfNeeded(expression.left));
const isRightAssociative = LuaPrinter.rightAssociativeOperators.has(expression.operator);
const precedence = LuaPrinter.operatorPrecedence[expression.operator];
chunks.push(
this.printExpressionInParenthesesIfNeeded(expression.left, isRightAssociative ? precedence + 1 : precedence)
);
chunks.push(" ", this.printOperator(expression.operator), " ");
chunks.push(this.printExpressionInParenthesesIfNeeded(expression.right));
chunks.push(
this.printExpressionInParenthesesIfNeeded(
expression.right,
isRightAssociative ? precedence : precedence + 1
)
);

return this.createSourceNode(expression, chunks);
}

private printExpressionInParenthesesIfNeeded(expression: lua.Expression): SourceNode {
return this.needsParenthesis(expression)
private printExpressionInParenthesesIfNeeded(expression: lua.Expression, minPrecedenceToOmit?: number): SourceNode {
return this.needsParenthesis(expression, minPrecedenceToOmit)
? this.createSourceNode(expression, ["(", this.printExpression(expression), ")"])
: this.printExpression(expression);
}

private needsParenthesis(expression: lua.Expression): boolean {
return (
lua.isBinaryExpression(expression) ||
lua.isFunctionExpression(expression) ||
lua.isTableExpression(expression) ||
(lua.isUnaryExpression(expression) && expression.operator === lua.SyntaxKind.NotOperator)
);
private needsParenthesis(expression: lua.Expression, minPrecedenceToOmit?: number): boolean {
if (lua.isBinaryExpression(expression) || lua.isUnaryExpression(expression)) {
return (
minPrecedenceToOmit === undefined ||
LuaPrinter.operatorPrecedence[expression.operator] < minPrecedenceToOmit
);
} else {
return lua.isFunctionExpression(expression) || lua.isTableExpression(expression);
}
}

public printCallExpression(expression: lua.CallExpression): SourceNode {
Expand Down Expand Up @@ -769,10 +820,19 @@ export class LuaPrinter {
return intersperse(chunks, ", ");
}

/**
* Returns true if the expression list (table field or parameters) should be printed on one line.
*/
protected isSimpleExpressionList(expressions: lua.Expression[]): boolean {
if (expressions.length <= 1) return true;
if (expressions.length > 4) return false;
return expressions.every(isSimpleExpression);
}

protected printExpressionList(expressions: lua.Expression[]): SourceChunk[] {
const chunks: SourceChunk[] = [];

if (expressions.every(isSimpleExpression)) {
if (this.isSimpleExpressionList(expressions)) {
chunks.push(...this.joinChunksWithComma(expressions.map(e => this.printExpression(e))));
} else {
chunks.push("\n");
Expand Down
26 changes: 25 additions & 1 deletion test/translation/__snapshots__/transformation.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ backQuoteInTemplateString = \\"\` \` \`\\"
escapedCharsInQuotes = \\"\\\\\\\\ \\\\0 \\\\b \\\\t \\\\n \\\\v \\\\f \\\\\\" ' \`\\"
escapedCharsInDoubleQuotes = \\"\\\\\\\\ \\\\0 \\\\b \\\\t \\\\n \\\\v \\\\f \\\\\\" ' \`\\"
escapedCharsInTemplateString = \\"\\\\\\\\ \\\\0 \\\\b \\\\t \\\\n \\\\v \\\\f \\\\\\" ' \`\\"
nonEmptyTemplateString = (\\"Level 0: \\\\n\\\\t \\" .. ((\\"Level 1: \\\\n\\\\t\\\\t \\" .. ((\\"Level 3: \\\\n\\\\t\\\\t\\\\t \\" .. \\"Last level \\\\n --\\") .. \\" \\\\n --\\")) .. \\" \\\\n --\\")) .. \\" \\\\n --\\""
nonEmptyTemplateString = (\\"Level 0: \\\\n\\\\t \\" .. (\\"Level 1: \\\\n\\\\t\\\\t \\" .. (\\"Level 3: \\\\n\\\\t\\\\t\\\\t \\" .. \\"Last level \\\\n --\\") .. \\" \\\\n --\\") .. \\" \\\\n --\\") .. \\" \\\\n --\\""
`;

exports[`Transformation (exportStatement) 1`] = `
Expand Down Expand Up @@ -230,6 +230,30 @@ return ____exports"

exports[`Transformation (modulesVariableNoExport) 1`] = `"foo = \\"bar\\""`;

exports[`Transformation (printFormat) 1`] = `
"stringConcat = ((\\"a\\" .. \\"b\\" .. \\"c\\") .. \\"d\\") .. \\"e\\"
numbers = 2 * 2 + 3 + 4 * (5 + 6) ~= 7
function func(...)
end
func(function()
local b = \\"A function\\"
end)
func(func())
array = {func()}
array2 = {
func(),
func()
}
object = {a = 1, b = 2, c = 3}
bigObject = {
a = 1,
b = 2,
c = 3,
d = \\"value1\\",
e = \\"value2\\"
}"
`;

exports[`Transformation (returnDefault) 1`] = `
"function myFunc(self)
return
Expand Down
27 changes: 27 additions & 0 deletions test/translation/transformation/printFormat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const stringConcat = "a" + ("b" + "c") + "d" + "e";
const numbers = 2 * 2 + 3 + 4 * (5 + 6) !== 7;

function func(this: void, ...args: any) {}

func(() => {
const b = "A function";
});

func(func());

const array = [func()];
const array2 = [func(), func()];

const object = {
a: 1,
b: 2,
c: 3,
};

const bigObject = {
a: 1,
b: 2,
c: 3,
d: "value1",
e: "value2",
};
4 changes: 2 additions & 2 deletions test/unit/__snapshots__/expressions.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ return ____exports"

exports[`Binary expressions ordering parentheses ("1*(3+4*2)") 1`] = `
"local ____exports = {}
____exports.__result = 1 * (3 + (4 * 2))
____exports.__result = 1 * (3 + 4 * 2)
return ____exports"
`;

exports[`Binary expressions ordering parentheses ("1*30+4") 1`] = `
"local ____exports = {}
____exports.__result = (1 * 30) + 4
____exports.__result = 1 * 30 + 4
return ____exports"
`;

Expand Down
12 changes: 4 additions & 8 deletions test/unit/__snapshots__/spread.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ function ____exports.__main(self)
end
return test(
nil,
{
fn = function(____, arg) return arg end
},
{fn = function(____, arg) return arg end},
\\"foobar\\"
)
end
Expand All @@ -108,11 +106,9 @@ function ____exports.__main(self)
end
local function test(self, ...)
do
pcall(
function()
error(\\"foobar\\", 0)
end
)
pcall(function()
error(\\"foobar\\", 0)
end)
do
return pick(nil, ...)
end
Expand Down
14 changes: 7 additions & 7 deletions test/unit/__snapshots__/switch.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ function ____exports.__main(self)
result = hoisted(nil)
break
end
____cond3 = ____cond3 or (____switch3 == 2)
____cond3 = ____cond3 or ____switch3 == 2
if ____cond3 then
result = \\"2\\"
end
if ____cond3 then
result = \\"default\\"
end
____cond3 = ____cond3 or (____switch3 == 3)
____cond3 = ____cond3 or ____switch3 == 3
if ____cond3 then
result = \\"3\\"
break
Expand Down Expand Up @@ -88,14 +88,14 @@ function ____exports.__main(self)
result = hoisted(nil)
break
end
____cond3 = ____cond3 or (____switch3 == 2)
____cond3 = ____cond3 or ____switch3 == 2
if ____cond3 then
result = \\"2\\"
end
if ____cond3 then
result = \\"default\\"
end
____cond3 = ____cond3 or (____switch3 == 3)
____cond3 = ____cond3 or ____switch3 == 3
if ____cond3 then
result = \\"3\\"
break
Expand All @@ -118,19 +118,19 @@ function ____exports.__main(self)
local out = {}
repeat
local ____switch3 = 0
local ____cond3 = ((____switch3 == 0) or (____switch3 == 1)) or (____switch3 == 2)
local ____cond3 = ____switch3 == 0 or ____switch3 == 1 or ____switch3 == 2
if ____cond3 then
__TS__ArrayPush(out, \\"0,1,2\\")
break
end
____cond3 = ____cond3 or (____switch3 == 3)
____cond3 = ____cond3 or ____switch3 == 3
if ____cond3 then
do
__TS__ArrayPush(out, \\"3\\")
break
end
end
____cond3 = ____cond3 or (____switch3 == 4)
____cond3 = ____cond3 or ____switch3 == 4
if ____cond3 then
break
end
Expand Down
Loading