Skip to content

Commit eecd0a6

Browse files
committed
Explicit context for functions
1 parent f217c90 commit eecd0a6

File tree

1 file changed

+76
-49
lines changed

1 file changed

+76
-49
lines changed

src/Transpiler.ts

Lines changed: 76 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,15 @@ export class LuaTranspiler {
4242
transpileBlock(node: ts.Node): string {
4343
let result = "";
4444

45-
node.forEachChild(child => {
46-
result += this.transpileNode(child);
47-
})
45+
if (ts.isBlock(node)) {
46+
node.statements.forEach(statement => {
47+
result += this.transpileNode(statement);
48+
});
49+
} else {
50+
node.forEachChild(child => {
51+
result += this.transpileNode(child);
52+
});
53+
}
4854

4955
return result;
5056
}
@@ -62,7 +68,7 @@ export class LuaTranspiler {
6268
case ts.SyntaxKind.EnumDeclaration:
6369
return this.transpileEnum(<ts.EnumDeclaration>node);
6470
case ts.SyntaxKind.FunctionDeclaration:
65-
return this.transpileFunctionDeclaration(<ts.FunctionDeclaration>node, "");
71+
return this.transpileFunctionDeclaration(<ts.FunctionDeclaration>node);
6672
case ts.SyntaxKind.VariableStatement:
6773
return this.indent + this.transpileVariableStatement(<ts.VariableStatement>node) + "\n";
6874
case ts.SyntaxKind.ExpressionStatement:
@@ -92,7 +98,7 @@ export class LuaTranspiler {
9298
// Ignore these
9399
return "";
94100
default:
95-
throw new TranspileError("Unsupported node kind: " + tsEx.enumName(node.kind, ts.SyntaxKind), node);
101+
return this.indent + this.transpileExpression(node) + "\n";
96102
}
97103
}
98104

@@ -323,6 +329,10 @@ export class LuaTranspiler {
323329
return "true";
324330
case ts.SyntaxKind.FalseKeyword:
325331
return "false";
332+
case ts.SyntaxKind.NullKeyword:
333+
return "nil";
334+
case ts.SyntaxKind.ThisKeyword:
335+
return "self";
326336
case ts.SyntaxKind.PostfixUnaryExpression:
327337
return this.transpilePostfixUnaryExpression(<ts.PostfixUnaryExpression>node);
328338
case ts.SyntaxKind.PrefixUnaryExpression:
@@ -332,6 +342,7 @@ export class LuaTranspiler {
332342
case ts.SyntaxKind.ObjectLiteralExpression:
333343
return this.transpileObjectLiteral(<ts.ObjectLiteralExpression>node);
334344
case ts.SyntaxKind.FunctionExpression:
345+
case ts.SyntaxKind.ArrowFunction:
335346
return this.transpileFunctionExpression(<ts.FunctionExpression>node);
336347
case ts.SyntaxKind.NewExpression:
337348
return this.transpileNewExpression(<ts.NewExpression>node);
@@ -403,28 +414,30 @@ export class LuaTranspiler {
403414
}
404415

405416
transpilePostfixUnaryExpression(node: ts.PostfixUnaryExpression): string {
406-
const operand = this.transpileExpression(node.operand);
417+
const operand = this.transpileExpression(node.operand, true);
407418
switch (node.operator) {
408419
case ts.SyntaxKind.PlusPlusToken:
409420
return `${operand} = ${operand} + 1`;
410421
case ts.SyntaxKind.MinusMinusToken:
411422
return `${operand} = ${operand} - 1`;
412423
default:
413-
throw new TranspileError("Unsupported expression kind: " + tsEx.enumName(node.kind, ts.SyntaxKind), node);
424+
throw new TranspileError("Unsupported unary postfix: " + tsEx.enumName(node.kind, ts.SyntaxKind), node);
414425
}
415426
}
416427

417428
transpilePrefixUnaryExpression(node: ts.PrefixUnaryExpression): string {
418-
const operand = this.transpileExpression(node.operand);
429+
const operand = this.transpileExpression(node.operand, true);
419430
switch (node.operator) {
420431
case ts.SyntaxKind.PlusPlusToken:
421432
return `${operand} = ${operand} + 1`;
422433
case ts.SyntaxKind.MinusMinusToken:
423434
return `${operand} = ${operand} - 1`;
424435
case ts.SyntaxKind.ExclamationToken:
425436
return `not ${operand}`;
437+
case ts.SyntaxKind.MinusToken:
438+
return `-${operand}`;
426439
default:
427-
throw new TranspileError("Unsupported expression kind: " + tsEx.enumName(node.kind, ts.SyntaxKind), node);
440+
throw new TranspileError("Unsupported unary prefix: " + tsEx.enumName(node.kind, ts.SyntaxKind), node);
428441
}
429442
}
430443

@@ -447,14 +460,14 @@ export class LuaTranspiler {
447460
if (tsEx.isArrayType(type))
448461
return this.transpileArrayCallExpression(node);
449462
}
450-
}
451463

452-
let callPath = this.transpileExpression(node.expression);
453-
// Remove last . with :
454-
if (callPath.indexOf(".") > -1) {
455-
callPath = callPath.substr(0, callPath.lastIndexOf(".")) + ":" + callPath.substr(callPath.lastIndexOf(".") + 1);
464+
// Include context parameter if present
465+
let callPath = this.transpileExpression(node.expression);
466+
const params = this.transpileArguments(node.arguments, node.expression.expression);
467+
return `${callPath}(${params})`;
456468
}
457469

470+
let callPath = this.transpileExpression(node.expression);
458471
const params = this.transpileArguments(node.arguments);
459472
return `${callPath}(${params})`;
460473
}
@@ -483,11 +496,18 @@ export class LuaTranspiler {
483496
}
484497
}
485498

486-
transpileArguments(params: ts.NodeArray<ts.Expression>): string {
499+
transpileArguments(params: ts.NodeArray<ts.Expression>, context?: ts.Expression): string {
487500
const parameters: string[] = [];
501+
502+
// Add context as first param if present
503+
if (context) {
504+
parameters.push(this.transpileExpression(context));
505+
}
506+
488507
params.forEach(param => {
489508
parameters.push(this.transpileExpression(param));
490509
});
510+
491511
return parameters.join(",");
492512
}
493513

@@ -505,32 +525,13 @@ export class LuaTranspiler {
505525
return this.transpileArrayProperty(node);
506526
}
507527

508-
// Do regular handling
509-
switch(node.expression.kind) {
510-
case ts.SyntaxKind.ThisKeyword:
511-
return `self.${property}`;
512-
case ts.SyntaxKind.Identifier:
513-
// If identifier is enum translate to raw member
514-
if (tsEx.isCompileMembersOnlyEnum(type)) {
515-
return property;
516-
} else {
517-
let path = (<ts.Identifier>node.expression).text;
518-
return `${path}.${property}`;
519-
}
520-
case ts.SyntaxKind.StringLiteral:
521-
case ts.SyntaxKind.NumericLiteral:
522-
case ts.SyntaxKind.ArrayLiteralExpression:
523-
let path = this.transpileExpression(node.expression);
524-
return `${path}.${property}`;
525-
case ts.SyntaxKind.CallExpression:
526-
path = this.transpileCallExpression(<ts.CallExpression>node.expression);
527-
return `${path}.${property}`;
528-
case ts.SyntaxKind.PropertyAccessExpression:
529-
path = this.transpilePropertyAccessExpression(<ts.PropertyAccessExpression>node.expression);
530-
return `${path}.${property}`;
531-
default:
532-
throw new TranspileError("Unsupported access kind: " + tsEx.enumName(node.expression.kind, ts.SyntaxKind), node);
528+
// Do not output path for member only enums
529+
if (tsEx.isCompileMembersOnlyEnum(type)) {
530+
return property;
533531
}
532+
533+
let path = this.transpileExpression(node.expression);
534+
return `${path}.${property}`;
534535
}
535536

536537
// Transpile access of string properties, only supported properties are allowed
@@ -587,24 +588,50 @@ export class LuaTranspiler {
587588
return `local ${identifier.escapedText} = ${value}`;
588589
}
589590

590-
transpileFunctionDeclaration(node: ts.Declaration, path: string): string {
591+
transpileFunctionDeclaration(node: ts.FunctionDeclaration): string {
591592
let result = "";
592-
const identifier = tsEx.getFirstChildOfType<ts.Identifier>(node, ts.isIdentifier);
593+
const identifier = node.name;
593594
const methodName = identifier.escapedText;
594-
const parameters = tsEx.getChildrenOfType<ts.ParameterDeclaration>(node, ts.isParameter);
595-
const block = tsEx.getFirstChildOfType<ts.Block>(node, ts.isBlock);
595+
const parameters = node.parameters
596+
const body = node.body;
596597

597598
// Build parameter string
598599
let paramNames: string[] = [];
599600
parameters.forEach(param => {
600601
paramNames.push(<string>(<ts.Identifier>param.name).escapedText);
601602
});
602603

604+
// Build function header
605+
result += this.indent + `function ${methodName}(${paramNames.join(",")})\n`;
606+
607+
this.pushIndent();
608+
result += this.transpileBlock(body);
609+
this.popIndent();
610+
611+
// Close function block
612+
result += this.indent + "end\n";
613+
614+
return result;
615+
}
616+
617+
transpileMethodDeclaration(node: ts.MethodDeclaration, path: string): string {
618+
let result = "";
619+
const identifier = <ts.Identifier>node.name;
620+
const methodName = identifier.escapedText;
621+
const parameters = node.parameters;
622+
const body = node.body;
623+
624+
// Build parameter string
625+
let paramNames: string[] = ["self"];
626+
parameters.forEach(param => {
627+
paramNames.push(<string>(<ts.Identifier>param.name).escapedText);
628+
});
629+
603630
// Build function header
604631
result += this.indent + `function ${path}${methodName}(${paramNames.join(",")})\n`;
605632

606633
this.pushIndent();
607-
result += this.transpileBlock(block);
634+
result += this.transpileBlock(body);
608635
this.popIndent();
609636

610637
// Close function block
@@ -617,7 +644,7 @@ export class LuaTranspiler {
617644
transpileClass(node: ts.ClassDeclaration): string {
618645
// Write class declaration
619646
const className = <string>node.name.escapedText;
620-
let result = this.indent + `${className} = ${className} or {}\n`;
647+
let result = this.indent + `${className} = ${className} or class({})\n`;
621648

622649
// Get all properties
623650
const properties = tsEx.getChildrenOfType<ts.PropertyDeclaration>(node, ts.isPropertyDeclaration);
@@ -674,7 +701,7 @@ export class LuaTranspiler {
674701
// Find all methods
675702
const methods = tsEx.getChildrenOfType<ts.MethodDeclaration>(node, ts.isMethodDeclaration);
676703
methods.forEach(method => {
677-
result += this.transpileFunctionDeclaration(method, `${className}:`);
704+
result += this.transpileMethodDeclaration(method, `${className}.`);
678705
});
679706

680707
return result;
@@ -732,12 +759,12 @@ export class LuaTranspiler {
732759
// Build parameter string
733760
let paramNames: string[] = [];
734761
node.parameters.forEach(param => {
735-
paramNames.push(<string>tsEx.getFirstChildOfType<ts.Identifier>(param, ts.isIdentifier).escapedText);
762+
paramNames.push(<string>(<ts.Identifier>param.name).escapedText);
736763
});
737764

738765
let result = `function(${paramNames.join(",")})\n`;
739766
this.pushIndent();
740-
result += this.transpileBlock(node.body);
767+
result += this.transpileNode(node.body);
741768
this.popIndent();
742769
return result + this.indent + "end ";
743770
}

0 commit comments

Comments
 (0)