Skip to content

Commit 581e009

Browse files
committed
Compiler organisation
1 parent d2418e5 commit 581e009

File tree

10 files changed

+10693
-16
lines changed

10 files changed

+10693
-16
lines changed

Compiler.ts

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,60 @@
11
import * as ts from "typescript";
22
import {readFileSync,writeFileSync} from "fs";
33

4-
import {LuaTranspiler} from "./Transpiler";
4+
import {LuaTranspiler, TranspileError} from "./Transpiler";
55
import {TSHelper as tsEx} from "./TSHelper";
66

77
function compile(fileNames: string[], options: ts.CompilerOptions): void {
8+
// Verify target
9+
if ((<string><any>options.target) != "lua") {
10+
console.error("Wrong compilation target! Add \"target\": \"lua\" to your tsconfig.json!");
11+
process.exit();
12+
}
13+
814
let program = ts.createProgram(fileNames, options);
915
let checker = program.getTypeChecker();
1016

17+
// Get all diagnostics, ignore unsupported extension
18+
const diagnostics = ts.getPreEmitDiagnostics(program).filter(diag => diag.code != 6054);
19+
diagnostics.forEach(diagnostic => {
20+
if (diagnostic.file) {
21+
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
22+
let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
23+
console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
24+
}
25+
else {
26+
console.log(`${ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}`);
27+
}
28+
});
29+
30+
// If there are errors dont emit
31+
if (diagnostics.filter(diag => diag.category == ts.DiagnosticCategory.Error).length > 0) {
32+
console.log("Stopping compilation process because of errors.");
33+
process.exit();
34+
}
35+
1136
program.getSourceFiles().forEach(sourceFile => {
1237
if (!sourceFile.isDeclarationFile) {
1338
// Print AST for debugging
1439
//printAST(sourceFile, 0);
1540

16-
// Transpile AST
17-
let lua = LuaTranspiler.transpileSourceFile(sourceFile, checker);
18-
console.log(lua);
41+
try {
42+
// Transpile AST
43+
let lua = LuaTranspiler.transpileSourceFile(sourceFile, checker);
44+
const outPath = sourceFile.fileName.substring(0, sourceFile.fileName.lastIndexOf(".")) + ".lua";
45+
//console.log(outPath);
46+
// Write output
47+
ts.sys.writeFile(outPath, lua);
48+
} catch (exception) {
49+
if (exception.node) {
50+
const pos = ts.getLineAndCharacterOfPosition(sourceFile, exception.node.pos);
51+
// Graciously handle transpilation errors
52+
console.error("Encountered error parsing file: " + exception.message);
53+
console.error(sourceFile.fileName + " line: " + (1 + pos.line) + " column: " + pos.character);
54+
} else {
55+
throw exception;
56+
}
57+
}
1958
}
2059
});
2160

@@ -30,7 +69,26 @@ function printAST(node: ts.Node, indent: number) {
3069
node.forEachChild(child => printAST(child, indent + 1));
3170
}
3271

33-
compile(process.argv.slice(2), {
34-
noEmitOnError: true, noImplicitAny: true,
35-
target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS
36-
});
72+
// Try to find tsconfig.json
73+
const filename = process.argv[2].split("\\").join("/");
74+
const filepath = filename.substring(0, filename.lastIndexOf("/"));
75+
let configPath = ts.findConfigFile(filepath, ts.sys.fileExists);
76+
77+
if (configPath) {
78+
configPath = configPath.split("\\").join("/");
79+
const projectRoot = configPath.substring(0, configPath.lastIndexOf("/"));
80+
81+
// Find all files
82+
let files = ts.sys.readDirectory(projectRoot, [".ts"]);
83+
84+
// Read config
85+
let configFile = ts.readConfigFile(configPath, ts.sys.readFile);
86+
if (configFile.error) {
87+
console.error("Error occured:");
88+
console.error(configFile.error);
89+
} else {
90+
compile(files, configFile.config.compilerOptions);
91+
}
92+
} else {
93+
console.error("Could not find tsconfig.json, place one in your project root!");
94+
}

Transpiler.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ export class LuaTranspiler {
5555
if (tsEx.getChildrenOfType(node, child => child.kind == ts.SyntaxKind.DeclareKeyword).length > 0) return "";
5656

5757
switch (node.kind) {
58+
case ts.SyntaxKind.ImportDeclaration:
59+
return this.transpileImport(<ts.ImportDeclaration>node);
5860
case ts.SyntaxKind.ClassDeclaration:
5961
return this.transpileClass(<ts.ClassDeclaration>node);
6062
case ts.SyntaxKind.FunctionDeclaration:
@@ -82,13 +84,34 @@ export class LuaTranspiler {
8284
case ts.SyntaxKind.ContinueKeyword:
8385
// Disallow continue
8486
throw new TranspileError("Continue is not supported in Lua", node);
87+
case ts.SyntaxKind.TypeAliasDeclaration:
88+
case ts.SyntaxKind.InterfaceDeclaration:
8589
case ts.SyntaxKind.EndOfFileToken:
90+
// Ignore these
8691
return "";
8792
default:
8893
throw new TranspileError("Unsupported node kind: " + tsEx.enumName(node.kind, ts.SyntaxKind), node);
8994
}
9095
}
9196

97+
transpileImport(node: ts.ImportDeclaration): string {
98+
const name = this.transpileExpression(node.moduleSpecifier);
99+
const imports = node.importClause.namedBindings;
100+
if (ts.isNamespaceImport(imports)) {
101+
return `{$imports.name.escapedText} = require(${name})`;
102+
} else if (ts.isNamedImports(imports)) {
103+
// Forbid renaming
104+
imports.elements.forEach(element => {
105+
if(element.propertyName) {
106+
throw new TranspileError("Renaming of individual imported objects is not allowed", node);
107+
}
108+
});
109+
return `require(${name})`;
110+
} else {
111+
throw new TranspileError("Unsupported import type.", node);
112+
}
113+
}
114+
92115
transpileBreak(): string {
93116
if (this.transpilingSwitch) {
94117
return this.indent + `goto switchDone${this.switchCounter}\n`;
@@ -276,6 +299,11 @@ export class LuaTranspiler {
276299
return this.transpileObjectLiteral(<ts.ObjectLiteralExpression>node);
277300
case ts.SyntaxKind.FunctionExpression:
278301
return this.transpileFunctionExpression(<ts.FunctionExpression>node);
302+
case ts.SyntaxKind.NewExpression:
303+
return this.transpileNewExpression(<ts.NewExpression>node);
304+
case ts.SyntaxKind.TypeAssertionExpression:
305+
// Simply ignore the type assertion
306+
return this.transpileExpression((<ts.TypeAssertion>node).expression);
279307
default:
280308
throw new TranspileError("Unsupported expression kind: " + tsEx.enumName(node.kind, ts.SyntaxKind), node);
281309
}
@@ -366,6 +394,13 @@ export class LuaTranspiler {
366394
}
367395
}
368396

397+
transpileNewExpression(node: ts.NewExpression): string {
398+
const name = this.transpileExpression(node.expression);
399+
const params = this.transpileArguments(node.arguments);
400+
401+
return `${name}(${params})`;
402+
}
403+
369404
transpileCallExpression(node: ts.CallExpression): string {
370405
// Check for calls on primitives to override
371406
if (ts.isPropertyAccessExpression(node.expression)) {

0 commit comments

Comments
 (0)