Skip to content

Commit 683e43a

Browse files
authored
removing semi-colons, except where needed for disambiguation (#505)
* removing semi-colons, except where needed for disambiguation * fixed formatting in new test * added semicolons to manually printed statements which could be followed by parenthesis
1 parent 1cec443 commit 683e43a

File tree

14 files changed

+457
-404
lines changed

14 files changed

+457
-404
lines changed

src/LuaPrinter.ts

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,48 @@ export class LuaPrinter {
172172
}
173173

174174
private printBlock(block: tstl.Block): SourceNode {
175-
return this.createSourceNode(
176-
block,
177-
this.ignoreDeadStatements(block.statements).map(s => this.printStatement(s))
175+
return this.createSourceNode(block, this.printStatementArray(block.statements));
176+
}
177+
178+
private statementMayRequireSemiColon(statement: tstl.Statement): boolean {
179+
// Types of statements that could create ambiguous syntax if followed by parenthesis
180+
return tstl.isVariableDeclarationStatement(statement)
181+
|| tstl.isAssignmentStatement(statement)
182+
|| tstl.isExpressionStatement(statement);
183+
}
184+
185+
private nodeStartsWithParenthesis(sourceNode: SourceNode): boolean {
186+
let result: boolean | undefined;
187+
sourceNode.walk(chunk => {
188+
if (result === undefined) {
189+
chunk = chunk.trimLeft(); // Ignore leading whitespace
190+
191+
if (chunk.length > 0) {
192+
result = chunk.startsWith("(");
193+
}
194+
}
195+
});
196+
return result || false;
197+
}
198+
199+
private printStatementArray(statements: tstl.Statement[]): SourceChunk[] {
200+
const statementNodes: SourceNode[] = [];
201+
statements = this.removeDeadAndEmptyStatements(statements);
202+
statements.forEach(
203+
(s, i) => {
204+
const node = this.printStatement(s);
205+
206+
if (i > 0
207+
&& this.statementMayRequireSemiColon(statements[i - 1])
208+
&& this.nodeStartsWithParenthesis(node))
209+
{
210+
statementNodes[i - 1].add(";");
211+
}
212+
213+
statementNodes.push(node);
214+
}
178215
);
216+
return statementNodes.length > 0 ? [...this.joinChunks("\n", statementNodes), "\n"] : [];
179217
}
180218

181219
private printStatement(statement: tstl.Statement): SourceNode {
@@ -214,13 +252,11 @@ export class LuaPrinter {
214252
private printDoStatement(statement: tstl.DoStatement): SourceNode {
215253
const chunks: SourceChunk[] = [];
216254

217-
if (statement.statements && statement.statements.length > 0) {
218-
chunks.push(this.indent("do\n"));
219-
this.pushIndent();
220-
chunks.push(...this.ignoreDeadStatements(statement.statements).map(s => this.printStatement(s)));
221-
this.popIndent();
222-
chunks.push(this.indent("end\n"));
223-
}
255+
chunks.push(this.indent("do\n"));
256+
this.pushIndent();
257+
chunks.push(...this.printStatementArray(statement.statements));
258+
this.popIndent();
259+
chunks.push(this.indent("end"));
224260

225261
return this.concatNodes(...chunks);
226262
}
@@ -233,7 +269,6 @@ export class LuaPrinter {
233269
if (tstl.isFunctionDefinition(statement)) {
234270
// Print all local functions as `local function foo()` instead of `local foo = function` to allow recursion
235271
chunks.push(this.printFunctionDefinition(statement));
236-
chunks.push("\n");
237272

238273
} else {
239274
chunks.push(...this.joinChunks(", ", statement.left.map(e => this.printExpression(e))));
@@ -242,7 +277,6 @@ export class LuaPrinter {
242277
chunks.push(" = ");
243278
chunks.push(...this.joinChunks(", ", statement.right.map(e => this.printExpression(e))));
244279
}
245-
chunks.push(";\n");
246280
}
247281

248282
return this.concatNodes(...chunks);
@@ -260,15 +294,13 @@ export class LuaPrinter {
260294
const name = this.printExpression(statement.left[0]);
261295
if (tsHelper.isValidLuaFunctionDeclarationName(name.toString())) {
262296
chunks.push(this.printFunctionDefinition(statement));
263-
chunks.push("\n");
264297
return this.createSourceNode(statement, chunks);
265298
}
266299
}
267300

268301
chunks.push(...this.joinChunks(", ", statement.left.map(e => this.printExpression(e))));
269302
chunks.push(" = ");
270303
chunks.push(...this.joinChunks(", ", statement.right.map(e => this.printExpression(e))));
271-
chunks.push(";\n");
272304

273305
return this.createSourceNode(statement, chunks);
274306
}
@@ -292,10 +324,10 @@ export class LuaPrinter {
292324
this.pushIndent();
293325
chunks.push(this.printBlock(statement.elseBlock));
294326
this.popIndent();
295-
chunks.push(this.indent("end\n"));
327+
chunks.push(this.indent("end"));
296328
}
297329
} else {
298-
chunks.push(this.indent("end\n"));
330+
chunks.push(this.indent("end"));
299331
}
300332

301333
return this.concatNodes(...chunks);
@@ -310,7 +342,7 @@ export class LuaPrinter {
310342
chunks.push(this.printBlock(statement.body));
311343
this.popIndent();
312344

313-
chunks.push(this.indent("end\n"));
345+
chunks.push(this.indent("end"));
314346

315347
return this.concatNodes(...chunks);
316348
}
@@ -324,7 +356,7 @@ export class LuaPrinter {
324356
chunks.push(this.printBlock(statement.body));
325357
this.popIndent();
326358

327-
chunks.push(this.indent("until "), this.printExpression(statement.condtion), ";\n");
359+
chunks.push(this.indent("until "), this.printExpression(statement.condtion));
328360

329361
return this.concatNodes(...chunks);
330362
}
@@ -347,7 +379,7 @@ export class LuaPrinter {
347379
chunks.push(this.printBlock(statement.body));
348380
this.popIndent();
349381

350-
chunks.push(this.indent("end\n"));
382+
chunks.push(this.indent("end"));
351383

352384
return this.concatNodes(...chunks);
353385
}
@@ -363,38 +395,37 @@ export class LuaPrinter {
363395
this.pushIndent();
364396
chunks.push(this.printBlock(statement.body));
365397
this.popIndent();
366-
chunks.push(this.indent("end\n"));
398+
chunks.push(this.indent("end"));
367399

368400
return this.createSourceNode(statement, chunks);
369401
}
370402

371403
private printGotoStatement(statement: tstl.GotoStatement): SourceNode {
372-
return this.createSourceNode(statement, [this.indent("goto "), statement.label, ";\n"]);
404+
return this.createSourceNode(statement, [this.indent("goto "), statement.label]);
373405
}
374406

375407
private printLabelStatement(statement: tstl.LabelStatement): SourceNode {
376-
return this.createSourceNode(statement, [this.indent("::"), statement.name, "::\n"]);
408+
return this.createSourceNode(statement, [this.indent("::"), statement.name, "::"]);
377409
}
378410

379411
private printReturnStatement(statement: tstl.ReturnStatement): SourceNode {
380412
if (!statement.expressions || statement.expressions.length === 0) {
381-
return this.createSourceNode(statement, this.indent("return;\n"));
413+
return this.createSourceNode(statement, this.indent("return"));
382414
}
383415

384416
const chunks: SourceChunk[] = [];
385417

386418
chunks.push(...this.joinChunks(", ", statement.expressions.map(e => this.printExpression(e))));
387-
chunks.push(";\n");
388419

389420
return this.createSourceNode(statement, [this.indent(), "return ", ...chunks]);
390421
}
391422

392423
private printBreakStatement(statement: tstl.BreakStatement): SourceNode {
393-
return this.createSourceNode(statement, this.indent("break;\n"));
424+
return this.createSourceNode(statement, this.indent("break"));
394425
}
395426

396427
private printExpressionStatement(statement: tstl.ExpressionStatement): SourceNode {
397-
return this.concatNodes(this.indent(), this.printExpression(statement.expression), ";\n");
428+
return this.concatNodes(this.indent(), this.printExpression(statement.expression));
398429
}
399430

400431
// Expressions
@@ -485,7 +516,6 @@ export class LuaPrinter {
485516
const returnNode: SourceChunk[] = [
486517
"return ",
487518
...this.joinChunks(", ", returnStatement.expressions.map(e => this.printExpression(e))),
488-
";",
489519
];
490520
chunks.push(this.createSourceNode(returnStatement, returnNode));
491521
chunks.push(" end");
@@ -621,10 +651,16 @@ export class LuaPrinter {
621651
return LuaPrinter.operatorMap[kind];
622652
}
623653

624-
private ignoreDeadStatements(statements: tstl.Statement[]): tstl.Statement[] {
654+
private isEmptyStatement(statement: tstl.Statement): boolean {
655+
return tstl.isDoStatement(statement) && (!statement.statements || statement.statements.length === 0);
656+
}
657+
658+
private removeDeadAndEmptyStatements(statements: tstl.Statement[]): tstl.Statement[] {
625659
const aliveStatements = [];
626660
for (const statement of statements) {
627-
aliveStatements.push(statement);
661+
if (!this.isEmptyStatement(statement)) {
662+
aliveStatements.push(statement);
663+
}
628664
if (tstl.isReturnStatement(statement)) {
629665
break;
630666
}

0 commit comments

Comments
 (0)