From 2eced0479ad34fce95782f940df9a27b2734b8a3 Mon Sep 17 00:00:00 2001 From: lolleko Date: Mon, 20 Aug 2018 22:29:34 +0200 Subject: [PATCH 01/18] Added target --- src/Transpiler.ts | 1 + src/targets/Transpilet.GLua.ts | 0 2 files changed, 1 insertion(+) create mode 100644 src/targets/Transpilet.GLua.ts diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 9f04f129d..8cf03a677 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -16,6 +16,7 @@ export enum LuaTarget { Lua52 = "5.2", Lua53 = "5.3", LuaJIT = "JIT", + GLua = "GLua", } export enum LuaLibFeature { diff --git a/src/targets/Transpilet.GLua.ts b/src/targets/Transpilet.GLua.ts new file mode 100644 index 000000000..e69de29bb From 46484a6c624763339ac56ce5994a3b4bc19ac7fa Mon Sep 17 00:00:00 2001 From: lolleko Date: Mon, 20 Aug 2018 22:59:52 +0200 Subject: [PATCH 02/18] Added include isntead of require for glua --- src/Compiler.ts | 8 ++++++-- src/Transpiler.ts | 10 +++++++--- src/targets/Transpiler.GLua.ts | 21 +++++++++++++++++++++ src/targets/Transpilet.GLua.ts | 0 4 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 src/targets/Transpiler.GLua.ts delete mode 100644 src/targets/Transpilet.GLua.ts diff --git a/src/Compiler.ts b/src/Compiler.ts index 73f2c01f4..9f903c811 100644 --- a/src/Compiler.ts +++ b/src/Compiler.ts @@ -6,6 +6,7 @@ import { CompilerOptions, parseCommandLine } from "./CommandLineParser"; import { LuaTranspiler51 } from "./targets/Transpiler.51"; import { LuaTranspiler52 } from "./targets/Transpiler.52"; import { LuaTranspiler53 } from "./targets/Transpiler.53"; +import { LuaTranspilerGLua } from "./targets/Transpiler.GLua"; import { LuaTranspilerJIT } from "./targets/Transpiler.JIT"; import { LuaLibImportKind, LuaTarget, LuaTranspiler } from "./Transpiler"; @@ -155,10 +156,10 @@ function emitFilesAndReportErrors(program: ts.Program): number { } export function createTranspiler(checker: ts.TypeChecker, - options: ts.CompilerOptions, + options: CompilerOptions, sourceFile: ts.SourceFile): LuaTranspiler { let luaTargetTranspiler: LuaTranspiler; - switch (options.luaTarget) { + switch (options.luaTarget.toLowerCase()) { case LuaTarget.Lua51: luaTargetTranspiler = new LuaTranspiler51(checker, options, sourceFile); break; @@ -168,6 +169,9 @@ export function createTranspiler(checker: ts.TypeChecker, case LuaTarget.Lua53: luaTargetTranspiler = new LuaTranspiler53(checker, options, sourceFile); break; + case LuaTarget.GLua: + luaTargetTranspiler = new LuaTranspilerGLua(checker, options, sourceFile); + break; default: luaTargetTranspiler = new LuaTranspilerJIT(checker, options, sourceFile); break; diff --git a/src/Transpiler.ts b/src/Transpiler.ts index ce2c212e5..98b07c486 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -15,8 +15,8 @@ export enum LuaTarget { Lua51 = "5.1", Lua52 = "5.2", Lua53 = "5.3", - LuaJIT = "JIT", - GLua = "GLua", + LuaJIT = "jit", + GLua = "glua", } export enum LuaLibFeature { @@ -174,6 +174,10 @@ export abstract class LuaTranspiler { return `"${this.pathToLuaRequirePath(relativePath)}"`; } + public getRequireKeyword(): string { + return "require"; + } + public pathToLuaRequirePath(filePath: string): string { return filePath.replace(new RegExp("\\\\|\/", "g"), "."); } @@ -320,7 +324,7 @@ export abstract class LuaTranspiler { const fileImportTable = path.basename(importPathWithoutQuotes) + this.importCount; const resolvedImportPath = this.getImportPath(importPathWithoutQuotes); - let result = `local ${fileImportTable} = require(${resolvedImportPath})\n`; + let result = `local ${fileImportTable} = ${this.getRequireKeyword()}(${resolvedImportPath})\n`; this.importCount++; imports.elements.forEach(element => { diff --git a/src/targets/Transpiler.GLua.ts b/src/targets/Transpiler.GLua.ts new file mode 100644 index 000000000..79f6e5cf2 --- /dev/null +++ b/src/targets/Transpiler.GLua.ts @@ -0,0 +1,21 @@ +import { LuaTranspiler } from "../Transpiler"; + +import * as path from "path"; + +export class LuaTranspilerGLua extends LuaTranspiler { + /** @override */ + public getImportPath(relativePath: string): string { + if (path.isAbsolute(relativePath)) { + // Get Path relative to baseDir (baseDir should be set to /lua/) + return `${this.getAbsoluteImportPath(relativePath)}`; + } else { + // We can use realtive paths in gmod + return `"${this.pathToLuaRequirePath(relativePath)}"`; + } + } + + /** @override */ + public getRequireKeyword(): string { + return "include"; + } +} diff --git a/src/targets/Transpilet.GLua.ts b/src/targets/Transpilet.GLua.ts deleted file mode 100644 index e69de29bb..000000000 From 43d1d9c26857ef0491f24fcdaf4d14ba5dc089ff Mon Sep 17 00:00:00 2001 From: lolleko Date: Mon, 20 Aug 2018 23:07:15 +0200 Subject: [PATCH 03/18] Fixed test :) --- src/Compiler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Compiler.ts b/src/Compiler.ts index 9f903c811..3f4cb30f6 100644 --- a/src/Compiler.ts +++ b/src/Compiler.ts @@ -159,7 +159,8 @@ export function createTranspiler(checker: ts.TypeChecker, options: CompilerOptions, sourceFile: ts.SourceFile): LuaTranspiler { let luaTargetTranspiler: LuaTranspiler; - switch (options.luaTarget.toLowerCase()) { + const target = options.luaTarget ? options.luaTarget.toLowerCase : ""; + switch (target) { case LuaTarget.Lua51: luaTargetTranspiler = new LuaTranspiler51(checker, options, sourceFile); break; From b20fdc48c5c502fc061dfae79a3595cb96904a04 Mon Sep 17 00:00:00 2001 From: lolleko Date: Mon, 20 Aug 2018 23:08:08 +0200 Subject: [PATCH 04/18] Added missing quotes --- src/targets/Transpiler.GLua.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/targets/Transpiler.GLua.ts b/src/targets/Transpiler.GLua.ts index 79f6e5cf2..56de7c5aa 100644 --- a/src/targets/Transpiler.GLua.ts +++ b/src/targets/Transpiler.GLua.ts @@ -7,7 +7,7 @@ export class LuaTranspilerGLua extends LuaTranspiler { public getImportPath(relativePath: string): string { if (path.isAbsolute(relativePath)) { // Get Path relative to baseDir (baseDir should be set to /lua/) - return `${this.getAbsoluteImportPath(relativePath)}`; + return `"${this.getAbsoluteImportPath(relativePath)}"`; } else { // We can use realtive paths in gmod return `"${this.pathToLuaRequirePath(relativePath)}"`; From 586381cc0949516b9d0465937a7cdabbe0cc7d07 Mon Sep 17 00:00:00 2001 From: lolleko Date: Mon, 20 Aug 2018 23:15:02 +0200 Subject: [PATCH 05/18] Fixed missing parantheses --- src/Compiler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler.ts b/src/Compiler.ts index 3f4cb30f6..fb9d179dc 100644 --- a/src/Compiler.ts +++ b/src/Compiler.ts @@ -159,7 +159,7 @@ export function createTranspiler(checker: ts.TypeChecker, options: CompilerOptions, sourceFile: ts.SourceFile): LuaTranspiler { let luaTargetTranspiler: LuaTranspiler; - const target = options.luaTarget ? options.luaTarget.toLowerCase : ""; + const target = options.luaTarget ? options.luaTarget.toLowerCase() : ""; switch (target) { case LuaTarget.Lua51: luaTargetTranspiler = new LuaTranspiler51(checker, options, sourceFile); From ef6ad0edafabc17c87c533ea56a50ed1e9df80fd Mon Sep 17 00:00:00 2001 From: lolleko Date: Tue, 21 Aug 2018 00:08:35 +0200 Subject: [PATCH 06/18] Adde missing .lua extension --- src/Transpiler.ts | 6 ++++-- src/targets/Transpiler.GLua.ts | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 98b07c486..d67547edc 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -320,11 +320,13 @@ export abstract class LuaTranspiler { const imports = node.importClause.namedBindings; + const reqKeyword = this.getRequireKeyword(); + if (ts.isNamedImports(imports)) { const fileImportTable = path.basename(importPathWithoutQuotes) + this.importCount; const resolvedImportPath = this.getImportPath(importPathWithoutQuotes); - let result = `local ${fileImportTable} = ${this.getRequireKeyword()}(${resolvedImportPath})\n`; + let result = `local ${fileImportTable} = ${reqKeyword}(${resolvedImportPath})\n`; this.importCount++; imports.elements.forEach(element => { @@ -340,7 +342,7 @@ export abstract class LuaTranspiler { return result; } else if (ts.isNamespaceImport(imports)) { const resolvedImportPath = this.getImportPath(importPathWithoutQuotes); - return `local ${this.transpileIdentifier(imports.name)} = require(${resolvedImportPath})\n`; + return `local ${this.transpileIdentifier(imports.name)} = ${reqKeyword}(${resolvedImportPath})\n`; } else { throw TSTLErrors.UnsupportedImportType(imports); } diff --git a/src/targets/Transpiler.GLua.ts b/src/targets/Transpiler.GLua.ts index 56de7c5aa..fcb8d10c0 100644 --- a/src/targets/Transpiler.GLua.ts +++ b/src/targets/Transpiler.GLua.ts @@ -7,10 +7,10 @@ export class LuaTranspilerGLua extends LuaTranspiler { public getImportPath(relativePath: string): string { if (path.isAbsolute(relativePath)) { // Get Path relative to baseDir (baseDir should be set to /lua/) - return `"${this.getAbsoluteImportPath(relativePath)}"`; + return `"${this.getAbsoluteImportPath(relativePath)}.lua"`; } else { // We can use realtive paths in gmod - return `"${this.pathToLuaRequirePath(relativePath)}"`; + return `"${relativePath}.lua"`; } } From d0f7a1d33975bf88c387e8eeafad53cdcadf5b55 Mon Sep 17 00:00:00 2001 From: lolleko Date: Wed, 22 Aug 2018 01:16:48 +0200 Subject: [PATCH 07/18] Array concat and spread operator Import filter for extension/metaextension classes --- src/Errors.ts | 3 +++ src/Transpiler.ts | 26 ++++++++++++++++++++++++-- src/lualib/ArrayConcat.ts | 10 ++++++++++ src/lualib/ArrayPush.ts | 6 ++++-- src/targets/Transpiler.52.ts | 5 +++++ src/targets/Transpiler.GLua.ts | 4 ++-- tslint.json | 6 +++--- 7 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 src/lualib/ArrayConcat.ts diff --git a/src/Errors.ts b/src/Errors.ts index 7a32f3926..9c0319904 100644 --- a/src/Errors.ts +++ b/src/Errors.ts @@ -34,6 +34,9 @@ export class TSTLErrors { public static InvalidExtensionMetaExtension = (node: ts.Node) => new TranspileError(`Cannot use both '!Extension' and '!MetaExtension' decorators on the same class.`, node) + public static InvalidNewExpressionOnExtension = (node: ts.Node) => + new TranspileError(`Cannot construct classes with decorator '!Extension' or '!MetaExtension'.`, node) + public static InvalidPropertyCall = (node: ts.Node) => new TranspileError(`Tried to transpile a non-property call as property call.`, node) diff --git a/src/Transpiler.ts b/src/Transpiler.ts index d67547edc..6f2a184e7 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -20,6 +20,7 @@ export enum LuaTarget { } export enum LuaLibFeature { + ArrayConcat = "ArrayConcat", ArrayEvery = "ArrayEvery", ArrayFilter = "ArrayFilter", ArrayForEach = "ArrayForEach", @@ -329,7 +330,16 @@ export abstract class LuaTranspiler { let result = `local ${fileImportTable} = ${reqKeyword}(${resolvedImportPath})\n`; this.importCount++; - imports.elements.forEach(element => { + const filteredElements = imports.elements.filter(e => { + const decs = tsHelper.getCustomDecorators(this.checker.getTypeAtLocation(e), this.checker); + return !decs.has(DecoratorKind.Extension) && !decs.has(DecoratorKind.MetaExtension); + }); + + if (filteredElements.length === 0) { + return ""; + } + + filteredElements.forEach(element => { const nameText = this.transpileIdentifier(element.name); if (element.propertyName) { const propertyText = this.transpileIdentifier(element.propertyName); @@ -793,7 +803,9 @@ export abstract class LuaTranspiler { case ts.SyntaxKind.TypeOfExpression: return this.transpileTypeOfExpression(node as ts.TypeOfExpression); case ts.SyntaxKind.EmptyStatement: - return ""; + return ""; + case ts.SyntaxKind.SpreadElement: + return this.transpileSpreadElement(node as ts.SpreadElement); default: throw TSTLErrors.UnsupportedKind("expression", node.kind, node); } @@ -1036,6 +1048,10 @@ export abstract class LuaTranspiler { this.checkForLuaLibType(type); + if (classDecorators.has(DecoratorKind.Extension) || classDecorators.has(DecoratorKind.MetaExtension)) { + throw TSTLErrors.InvalidNewExpressionOnExtension(node); + } + if (classDecorators.has(DecoratorKind.CustomConstructor)) { const customDecorator = classDecorators.get(DecoratorKind.CustomConstructor); if (!customDecorator.args[0]) { @@ -1193,6 +1209,8 @@ export abstract class LuaTranspiler { const caller = this.transpileExpression(expression.expression); const expressionName = this.transpileIdentifier(expression.name); switch (expressionName) { + case "concat": + return this.transpileLuaLibFunction(LuaLibFeature.ArrayConcat, caller, params); case "push": return this.transpileLuaLibFunction(LuaLibFeature.ArrayPush, caller, params); case "forEach": @@ -1371,6 +1389,10 @@ export abstract class LuaTranspiler { return escapedText; } + public transpileSpreadElement(node: ts.SpreadElement): string { + return "unpack(" + this.transpileExpression(node.expression) + ")"; + } + public transpileArrayBindingElement(name: ts.ArrayBindingElement): string { if (ts.isOmittedExpression(name)) { return "__"; diff --git a/src/lualib/ArrayConcat.ts b/src/lualib/ArrayConcat.ts new file mode 100644 index 000000000..8a1f33fae --- /dev/null +++ b/src/lualib/ArrayConcat.ts @@ -0,0 +1,10 @@ +function __TS__ArrayConcat(arr1: T[], arr2: T[]): T[] { + const out: T[] = []; + for (let i = 0; i < arr1.length; i++) { + out[i] = arr1[i]; + } + for (let i = 0; i < arr2.length; i++) { + out[i] = arr2[i]; + } + return out; +} diff --git a/src/lualib/ArrayPush.ts b/src/lualib/ArrayPush.ts index 8e1d8e324..8387b8ae3 100644 --- a/src/lualib/ArrayPush.ts +++ b/src/lualib/ArrayPush.ts @@ -1,6 +1,8 @@ function __TS__ArrayPush(arr: T[], ...items: T[]): number { - for (const item of items) { - arr[arr.length] = item; + /* tslint:disable */ + for (let i = 0; i < items.length; i++) { + /* tslint:enable */ + arr[arr.length] = items[i]; } return arr.length; } diff --git a/src/targets/Transpiler.52.ts b/src/targets/Transpiler.52.ts index 196f63a2a..bd2dc79d4 100644 --- a/src/targets/Transpiler.52.ts +++ b/src/targets/Transpiler.52.ts @@ -63,4 +63,9 @@ export class LuaTranspiler52 extends LuaTranspiler51 { public transpileDestructingAssignmentValue(node: ts.Expression): string { return `table.unpack(${this.transpileExpression(node)})`; } + + /** @override */ + public transpileSpreadElement(node: ts.SpreadElement): string { + return "table.unpack(" + this.transpileExpression(node.expression) + ")"; + } } diff --git a/src/targets/Transpiler.GLua.ts b/src/targets/Transpiler.GLua.ts index fcb8d10c0..ea0434481 100644 --- a/src/targets/Transpiler.GLua.ts +++ b/src/targets/Transpiler.GLua.ts @@ -1,8 +1,8 @@ -import { LuaTranspiler } from "../Transpiler"; +import { LuaTranspilerJIT } from "./Transpiler.JIT"; import * as path from "path"; -export class LuaTranspilerGLua extends LuaTranspiler { +export class LuaTranspilerGLua extends LuaTranspilerJIT { /** @override */ public getImportPath(relativePath: string): string { if (path.isAbsolute(relativePath)) { diff --git a/tslint.json b/tslint.json index bb6058aba..d4505f068 100644 --- a/tslint.json +++ b/tslint.json @@ -31,9 +31,9 @@ "interface-name": false, "radix": false, "typedef": [ - true, - "call-signature", - "property-declaration" + true, + "call-signature", + "property-declaration" ] }, "rulesDirectory": [] From f24e6ff15688347f8c0e080280bc1bb83d4fdc68 Mon Sep 17 00:00:00 2001 From: lolleko Date: Wed, 22 Aug 2018 19:09:21 +0200 Subject: [PATCH 08/18] Fixes getAccessor with `this` and added isntancefield translation for extension classes --- src/Transpiler.ts | 27 ++++++++++++++++++--------- src/targets/Transpiler.52.ts | 2 +- src/targets/Transpiler.GLua.ts | 13 +++++++++++++ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 6f2a184e7..f4339b631 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -1259,6 +1259,10 @@ export abstract class LuaTranspiler { public transpilePropertyAccessExpression(node: ts.PropertyAccessExpression): string { const property = node.name.text; + if (tsHelper.hasGetAccessor(node, this.checker)) { + return this.transpileGetAccessor(node); + } + // Check for primitive types to override const type = this.checker.getTypeAtLocation(node.expression); switch (type.flags) { @@ -1268,8 +1272,6 @@ export abstract class LuaTranspiler { case ts.TypeFlags.Object: if (tsHelper.isArrayType(type, this.checker)) { return this.transpileArrayProperty(node); - } else if (tsHelper.hasGetAccessor(node, this.checker)) { - return this.transpileGetAccessor(node); } } @@ -1593,13 +1595,6 @@ export abstract class LuaTranspiler { let result = ""; - if (!isExtension && !isMetaExtension) { - result += this.transpileClassCreationMethods(node, instanceFields, extendsType); - } else { - // export empty table - this.pushExport(className, node, true); - } - // Overwrite the original className with the class we are overriding for extensions if (isMetaExtension) { if (!extendsType) { @@ -1619,6 +1614,20 @@ export abstract class LuaTranspiler { } } + if (!isExtension && !isMetaExtension) { + result += this.transpileClassCreationMethods(node, instanceFields, extendsType); + } else { + for (const f of instanceFields) { + // Get identifier + const fieldIdentifier = f.name as ts.Identifier; + const fieldName = this.transpileIdentifier(fieldIdentifier); + + const value = this.transpileExpression(f.initializer); + + result += this.indent + `${className}.${fieldName} = ${value}\n`; + } + } + // Add static declarations for (const field of staticFields) { const fieldName = this.transpileIdentifier(field.name as ts.Identifier); diff --git a/src/targets/Transpiler.52.ts b/src/targets/Transpiler.52.ts index bd2dc79d4..31a6f4dcb 100644 --- a/src/targets/Transpiler.52.ts +++ b/src/targets/Transpiler.52.ts @@ -67,5 +67,5 @@ export class LuaTranspiler52 extends LuaTranspiler51 { /** @override */ public transpileSpreadElement(node: ts.SpreadElement): string { return "table.unpack(" + this.transpileExpression(node.expression) + ")"; - } + } } diff --git a/src/targets/Transpiler.GLua.ts b/src/targets/Transpiler.GLua.ts index ea0434481..53fdb628a 100644 --- a/src/targets/Transpiler.GLua.ts +++ b/src/targets/Transpiler.GLua.ts @@ -1,6 +1,9 @@ import { LuaTranspilerJIT } from "./Transpiler.JIT"; import * as path from "path"; +import * as ts from "typescript"; + +import { LuaTranspiler } from "../Transpiler"; export class LuaTranspilerGLua extends LuaTranspilerJIT { /** @override */ @@ -18,4 +21,14 @@ export class LuaTranspilerGLua extends LuaTranspilerJIT { public getRequireKeyword(): string { return "include"; } + + /** @override */ + public transpileDestructingAssignmentValue(node: ts.Expression): string { + return LuaTranspiler.prototype.transpileDestructingAssignmentValue.call(this, node); + } + + /** @override */ + public transpileSpreadElement(node: ts.SpreadElement): string { + return LuaTranspiler.prototype.transpileSpreadElement.call(this, node); + } } From 2bb7c1af2900f36a69315a1a7b893d44c4061b17 Mon Sep 17 00:00:00 2001 From: lolleko Date: Thu, 30 Aug 2018 12:01:17 +0200 Subject: [PATCH 09/18] Removed glua target --- src/Compiler.ts | 4 ---- src/Transpiler.ts | 1 - src/targets/Transpiler.GLua.ts | 34 ---------------------------------- 3 files changed, 39 deletions(-) delete mode 100644 src/targets/Transpiler.GLua.ts diff --git a/src/Compiler.ts b/src/Compiler.ts index fb9d179dc..7d01f0ea9 100644 --- a/src/Compiler.ts +++ b/src/Compiler.ts @@ -6,7 +6,6 @@ import { CompilerOptions, parseCommandLine } from "./CommandLineParser"; import { LuaTranspiler51 } from "./targets/Transpiler.51"; import { LuaTranspiler52 } from "./targets/Transpiler.52"; import { LuaTranspiler53 } from "./targets/Transpiler.53"; -import { LuaTranspilerGLua } from "./targets/Transpiler.GLua"; import { LuaTranspilerJIT } from "./targets/Transpiler.JIT"; import { LuaLibImportKind, LuaTarget, LuaTranspiler } from "./Transpiler"; @@ -170,9 +169,6 @@ export function createTranspiler(checker: ts.TypeChecker, case LuaTarget.Lua53: luaTargetTranspiler = new LuaTranspiler53(checker, options, sourceFile); break; - case LuaTarget.GLua: - luaTargetTranspiler = new LuaTranspilerGLua(checker, options, sourceFile); - break; default: luaTargetTranspiler = new LuaTranspilerJIT(checker, options, sourceFile); break; diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 11600423f..b79e93253 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -16,7 +16,6 @@ export enum LuaTarget { Lua52 = "5.2", Lua53 = "5.3", LuaJIT = "jit", - GLua = "glua", } export enum LuaLibFeature { diff --git a/src/targets/Transpiler.GLua.ts b/src/targets/Transpiler.GLua.ts deleted file mode 100644 index 53fdb628a..000000000 --- a/src/targets/Transpiler.GLua.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { LuaTranspilerJIT } from "./Transpiler.JIT"; - -import * as path from "path"; -import * as ts from "typescript"; - -import { LuaTranspiler } from "../Transpiler"; - -export class LuaTranspilerGLua extends LuaTranspilerJIT { - /** @override */ - public getImportPath(relativePath: string): string { - if (path.isAbsolute(relativePath)) { - // Get Path relative to baseDir (baseDir should be set to /lua/) - return `"${this.getAbsoluteImportPath(relativePath)}.lua"`; - } else { - // We can use realtive paths in gmod - return `"${relativePath}.lua"`; - } - } - - /** @override */ - public getRequireKeyword(): string { - return "include"; - } - - /** @override */ - public transpileDestructingAssignmentValue(node: ts.Expression): string { - return LuaTranspiler.prototype.transpileDestructingAssignmentValue.call(this, node); - } - - /** @override */ - public transpileSpreadElement(node: ts.SpreadElement): string { - return LuaTranspiler.prototype.transpileSpreadElement.call(this, node); - } -} From 8dffc3ea972c117beb99315da0a52affcb16f3b0 Mon Sep 17 00:00:00 2001 From: lolleko Date: Thu, 30 Aug 2018 12:53:44 +0200 Subject: [PATCH 10/18] Added Array.concat test --- src/lualib/ArrayConcat.ts | 24 +++++++++++++++++++----- test/unit/lualib/lualib.spec.ts | 31 ++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/lualib/ArrayConcat.ts b/src/lualib/ArrayConcat.ts index 8a1f33fae..ca4030d74 100644 --- a/src/lualib/ArrayConcat.ts +++ b/src/lualib/ArrayConcat.ts @@ -1,10 +1,24 @@ -function __TS__ArrayConcat(arr1: T[], arr2: T[]): T[] { - const out: T[] = []; +/* tslint:disable */ +declare function pcall(func: Function): any; +declare function type(val: any): string; + +function __TS__ArrayConcat(arr1: any[], ...args: any[]): any[] { + const out: any[] = []; for (let i = 0; i < arr1.length; i++) { - out[i] = arr1[i]; + out[out.length] = arr1[i]; } - for (let i = 0; i < arr2.length; i++) { - out[i] = arr2[i]; + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + // Hack because we don't have an isArray function + if (pcall(() => (arg as any[]).length) && type(arg) !== "string") { + const argAsArray = (arg as any[]); + for (let j = 0; j < argAsArray.length; j++) { + out[out.length] = argAsArray[j]; + } + } else { + out[out.length] = arg; + } } + return out; } diff --git a/test/unit/lualib/lualib.spec.ts b/test/unit/lualib/lualib.spec.ts index 30279827c..147ea7f99 100644 --- a/test/unit/lualib/lualib.spec.ts +++ b/test/unit/lualib/lualib.spec.ts @@ -172,6 +172,35 @@ export class LuaLibArrayTests { } } + @TestCase([], []) + @TestCase([1, 2, 3], []) + @TestCase([1, 2, 3], [4]) + @TestCase([1, 2, 3], [4, 5]) + @TestCase([1, 2, 3], [4, 5]) + @TestCase([1, 2, 3], 4, [5]) + @TestCase([1, 2, 3], 4, [5, 6]) + @TestCase([1, 2, 3], 4, [5, 6], 7) + @TestCase([1, 2, 3], "test", [5, 6], 7, ["test1", "test2"]) + @TestCase([1, 2, "test"], "test", ["test1", "test2"]) + @Test("array.concat") + public concat(arr: T[], ...args: T[]) { + const argStr = args.map(arg => JSON.stringify(arg)).join(","); + console.log(argStr); + console.log("\n"); + // Transpile + const lua = util.transpileString( + `let concatTestTable = ${JSON.stringify(arr)}; + return JSONStringify(concatTestTable.concat(${argStr}));` + ); + + // Execute + const result = util.executeLua(lua); + + // Assert + const concatArr = arr.concat(...args); + Expect(result).toBe(JSON.stringify(concatArr)); + } + @TestCase([], "") @TestCase(["test1"], "test1") @TestCase(["test1", "test2"], "test1,test2") @@ -308,7 +337,7 @@ export class LuaLibArrayTests { // Assert Expect(result).toBe(expected); } - + @TestCase("true", 11) @TestCase("false", 13) @TestCase("a < 4", 13) From 845529e09e889606533fbb3cc29ce64aec4ac97e Mon Sep 17 00:00:00 2001 From: lolleko Date: Thu, 30 Aug 2018 13:05:03 +0200 Subject: [PATCH 11/18] Added spread element test --- test/unit/spreadElement.spec.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 test/unit/spreadElement.spec.ts diff --git a/test/unit/spreadElement.spec.ts b/test/unit/spreadElement.spec.ts new file mode 100644 index 000000000..08b84323e --- /dev/null +++ b/test/unit/spreadElement.spec.ts @@ -0,0 +1,16 @@ +import { Expect, Test, TestCase } from "alsatian"; + +import * as util from "../src/util"; + +export class SpreadElementTest { + + @TestCase([]) + @TestCase([1, 2, 3]) + @TestCase([1, "test", 3]) + @Test("Spread Element Push") + public spreadElementPush(inp: any[]) { + const lua = util.transpileString(`return JSONStringify([].push(...${JSON.stringify(inp)}));`); + const result = util.executeLua(lua); + Expect(result).toBe([].push(...inp)); + } +} From 9136e1598fa6b5d7df53770ec5bf2c1cc3989689 Mon Sep 17 00:00:00 2001 From: lolleko Date: Thu, 30 Aug 2018 13:10:36 +0200 Subject: [PATCH 12/18] Added test for Extension decorator instantiation throw --- test/unit/decoratorMetaExtension.spec.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/test/unit/decoratorMetaExtension.spec.ts b/test/unit/decoratorMetaExtension.spec.ts index c8b5694e9..d29f51467 100644 --- a/test/unit/decoratorMetaExtension.spec.ts +++ b/test/unit/decoratorMetaExtension.spec.ts @@ -1,4 +1,4 @@ -import { Expect, Test, TestCase } from "alsatian"; +import { Expect, Test } from "alsatian"; import * as util from "../src/util"; import { TranspileError } from "../../src/Errors"; @@ -44,4 +44,20 @@ export class DecoratorMetaExtension { }).toThrowError(TranspileError, "!MetaExtension requires the extension of the metatable class."); } + + @Test("DontAllowInstantiation") + public dontAllowInstantiation(): void { + Expect(() => { + util.transpileString( + ` + declare class _LOADED; + /** !MetaExtension */ + class Ext extends _LOADED { + } + const e = new Ext(); + ` + ); + }).toThrowError(TranspileError, + "Cannot construct classes with decorator '!Extension' or '!MetaExtension'."); + } } From 21c21e77d16d29b93061fe69ba7a7399a7899b10 Mon Sep 17 00:00:00 2001 From: lolleko Date: Thu, 30 Aug 2018 13:16:55 +0200 Subject: [PATCH 13/18] Fixed tests that were borken because JIT is now lowecase (jit) --- test/unit/expressions.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 4447f0c2c..24bbb759e 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -322,7 +322,7 @@ export class ExpressionTests { const identifier = ts.createIdentifier("fromCodePoint"); Expect(() => transpiler.transpileStringExpression(identifier)) .toThrowError(TranspileError, "string property fromCodePoint is/are not supported " + - "for target Lua JIT."); + "for target Lua jit."); } @Test("Unknown string expression error") @@ -331,7 +331,7 @@ export class ExpressionTests { const identifier = ts.createIdentifier("abcd"); Expect(() => transpiler.transpileStringExpression(identifier)) - .toThrowError(TranspileError, "string property abcd is/are not supported for target Lua JIT."); + .toThrowError(TranspileError, "string property abcd is/are not supported for target Lua jit."); } @Test("Unsupported array function error") From e33b0286172f41e3accf4033ba278a67ccf97c83 Mon Sep 17 00:00:00 2001 From: lolleko Date: Thu, 30 Aug 2018 13:36:03 +0200 Subject: [PATCH 14/18] Added test for Extension instance fields Also removed debug print from array concat test --- test/translation/lua/classExtension4.lua | 4 ++++ test/translation/ts/classExtension1.ts | 4 ++-- test/translation/ts/classExtension2.ts | 2 +- test/translation/ts/classExtension3.ts | 4 ++-- test/translation/ts/classExtension4.ts | 6 ++++++ test/unit/lualib/lualib.spec.ts | 2 -- 6 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 test/translation/lua/classExtension4.lua create mode 100644 test/translation/ts/classExtension4.ts diff --git a/test/translation/lua/classExtension4.lua b/test/translation/lua/classExtension4.lua new file mode 100644 index 000000000..2d0c01b99 --- /dev/null +++ b/test/translation/lua/classExtension4.lua @@ -0,0 +1,4 @@ +MyClass.test = "test" +MyClass.testP = "testP" +function MyClass.myFunction(self) +end \ No newline at end of file diff --git a/test/translation/ts/classExtension1.ts b/test/translation/ts/classExtension1.ts index 922185c25..cf293483d 100644 --- a/test/translation/ts/classExtension1.ts +++ b/test/translation/ts/classExtension1.ts @@ -1,4 +1,4 @@ /** !Extension */ class MyClass { - myFunction() {} -} \ No newline at end of file + public myFunction() {} +} diff --git a/test/translation/ts/classExtension2.ts b/test/translation/ts/classExtension2.ts index 1b9d54732..109160d97 100644 --- a/test/translation/ts/classExtension2.ts +++ b/test/translation/ts/classExtension2.ts @@ -4,5 +4,5 @@ class TestClass { /** !Extension */ class MyClass extends TestClass { - myFunction() {} + public myFunction() {} } diff --git a/test/translation/ts/classExtension3.ts b/test/translation/ts/classExtension3.ts index a31129841..287c46d3f 100644 --- a/test/translation/ts/classExtension3.ts +++ b/test/translation/ts/classExtension3.ts @@ -1,9 +1,9 @@ /** !Extension RenamedTestClass */ class TestClass { - myFunction() {} + public myFunction() {} } /** !Extension RenamedMyClass */ class MyClass extends TestClass { - myFunction() {} + public myFunction() {} } diff --git a/test/translation/ts/classExtension4.ts b/test/translation/ts/classExtension4.ts new file mode 100644 index 000000000..2183c5610 --- /dev/null +++ b/test/translation/ts/classExtension4.ts @@ -0,0 +1,6 @@ +/** !Extension */ +class MyClass { + public test: string = "test"; + private testP: string = "testP"; + public myFunction() {} +} diff --git a/test/unit/lualib/lualib.spec.ts b/test/unit/lualib/lualib.spec.ts index 147ea7f99..328e346ee 100644 --- a/test/unit/lualib/lualib.spec.ts +++ b/test/unit/lualib/lualib.spec.ts @@ -185,8 +185,6 @@ export class LuaLibArrayTests { @Test("array.concat") public concat(arr: T[], ...args: T[]) { const argStr = args.map(arg => JSON.stringify(arg)).join(","); - console.log(argStr); - console.log("\n"); // Transpile const lua = util.transpileString( `let concatTestTable = ${JSON.stringify(arr)}; From a4cf0de752843a837dccf266ffcd6eb9c4f5c2bc Mon Sep 17 00:00:00 2001 From: lolleko Date: Thu, 30 Aug 2018 13:52:07 +0200 Subject: [PATCH 15/18] Added spreadelement test for Lua 5.1 --- test/unit/spreadElement.spec.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/unit/spreadElement.spec.ts b/test/unit/spreadElement.spec.ts index 08b84323e..149ab6e47 100644 --- a/test/unit/spreadElement.spec.ts +++ b/test/unit/spreadElement.spec.ts @@ -1,5 +1,6 @@ import { Expect, Test, TestCase } from "alsatian"; +import { LuaTarget } from "../../src/Transpiler"; import * as util from "../src/util"; export class SpreadElementTest { @@ -13,4 +14,11 @@ export class SpreadElementTest { const result = util.executeLua(lua); Expect(result).toBe([].push(...inp)); } + + @Test("Spread Element Lua 5.1") + public spreadElement51() { + // Cant test functional because our VM doesn't run on 5.1 + const lua = util.transpileString(`[].push(...${JSON.stringify([1, 2, 3])});`, {luaTarget: LuaTarget.Lua51}); + Expect(lua).toBe("__TS__ArrayPush({}, unpack({1,2,3}))"); + } } From 257df03c7f47ef378237a02afb09071ecdbaf728 Mon Sep 17 00:00:00 2001 From: lolleko Date: Tue, 4 Sep 2018 16:18:02 +0200 Subject: [PATCH 16/18] Replaced numeric loops woth for of and removed useless getRequireKeyword --- src/Transpiler.ts | 14 +++++--------- src/lualib/ArrayConcat.ts | 12 +++++------- src/lualib/ArrayPush.ts | 6 ++---- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/Transpiler.ts b/src/Transpiler.ts index b79e93253..81d54fe62 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -174,10 +174,6 @@ export abstract class LuaTranspiler { return `"${this.pathToLuaRequirePath(relativePath)}"`; } - public getRequireKeyword(): string { - return "require"; - } - public pathToLuaRequirePath(filePath: string): string { return filePath.replace(new RegExp("\\\\|\/", "g"), "."); } @@ -320,18 +316,18 @@ export abstract class LuaTranspiler { const imports = node.importClause.namedBindings; - const reqKeyword = this.getRequireKeyword(); + const requireKeyword = "require"; if (ts.isNamedImports(imports)) { const fileImportTable = path.basename(importPathWithoutQuotes) + this.importCount; const resolvedImportPath = this.getImportPath(importPathWithoutQuotes); - let result = `local ${fileImportTable} = ${reqKeyword}(${resolvedImportPath})\n`; + let result = `local ${fileImportTable} = ${requireKeyword}(${resolvedImportPath})\n`; this.importCount++; const filteredElements = imports.elements.filter(e => { - const decs = tsHelper.getCustomDecorators(this.checker.getTypeAtLocation(e), this.checker); - return !decs.has(DecoratorKind.Extension) && !decs.has(DecoratorKind.MetaExtension); + const decorators = tsHelper.getCustomDecorators(this.checker.getTypeAtLocation(e), this.checker); + return !decorators.has(DecoratorKind.Extension) && !decorators.has(DecoratorKind.MetaExtension); }); if (filteredElements.length === 0) { @@ -351,7 +347,7 @@ export abstract class LuaTranspiler { return result; } else if (ts.isNamespaceImport(imports)) { const resolvedImportPath = this.getImportPath(importPathWithoutQuotes); - return `local ${this.transpileIdentifier(imports.name)} = ${reqKeyword}(${resolvedImportPath})\n`; + return `local ${this.transpileIdentifier(imports.name)} = ${requireKeyword}(${resolvedImportPath})\n`; } else { throw TSTLErrors.UnsupportedImportType(imports); } diff --git a/src/lualib/ArrayConcat.ts b/src/lualib/ArrayConcat.ts index ca4030d74..ef4504655 100644 --- a/src/lualib/ArrayConcat.ts +++ b/src/lualib/ArrayConcat.ts @@ -1,19 +1,17 @@ -/* tslint:disable */ declare function pcall(func: Function): any; declare function type(val: any): string; function __TS__ArrayConcat(arr1: any[], ...args: any[]): any[] { const out: any[] = []; - for (let i = 0; i < arr1.length; i++) { - out[out.length] = arr1[i]; + for (const val of arr1) { + out[out.length] = val; } - for (let i = 0; i < args.length; i++) { - const arg = args[i]; + for (const arg of args) { // Hack because we don't have an isArray function if (pcall(() => (arg as any[]).length) && type(arg) !== "string") { const argAsArray = (arg as any[]); - for (let j = 0; j < argAsArray.length; j++) { - out[out.length] = argAsArray[j]; + for (const val of argAsArray) { + out[out.length] = val; } } else { out[out.length] = arg; diff --git a/src/lualib/ArrayPush.ts b/src/lualib/ArrayPush.ts index 8387b8ae3..8e1d8e324 100644 --- a/src/lualib/ArrayPush.ts +++ b/src/lualib/ArrayPush.ts @@ -1,8 +1,6 @@ function __TS__ArrayPush(arr: T[], ...items: T[]): number { - /* tslint:disable */ - for (let i = 0; i < items.length; i++) { - /* tslint:enable */ - arr[arr.length] = items[i]; + for (const item of items) { + arr[arr.length] = item; } return arr.length; } From 83a0135bcd1eab20ebff2945c9f46d1b3d5202bc Mon Sep 17 00:00:00 2001 From: lolleko Date: Tue, 4 Sep 2018 16:22:30 +0200 Subject: [PATCH 17/18] Fixed lint issue --- src/lualib/ArrayConcat.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lualib/ArrayConcat.ts b/src/lualib/ArrayConcat.ts index ef4504655..06d5206b3 100644 --- a/src/lualib/ArrayConcat.ts +++ b/src/lualib/ArrayConcat.ts @@ -1,4 +1,4 @@ -declare function pcall(func: Function): any; +declare function pcall(func: () => any): any; declare function type(val: any): string; function __TS__ArrayConcat(arr1: any[], ...args: any[]): any[] { From c8182102ada60eb0347b8aaef9d1a9250ba4d80f Mon Sep 17 00:00:00 2001 From: lolleko Date: Tue, 4 Sep 2018 16:44:09 +0200 Subject: [PATCH 18/18] Fixed missing semicolon --- test/unit/spreadElement.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/spreadElement.spec.ts b/test/unit/spreadElement.spec.ts index 149ab6e47..50bf8f2dc 100644 --- a/test/unit/spreadElement.spec.ts +++ b/test/unit/spreadElement.spec.ts @@ -19,6 +19,6 @@ export class SpreadElementTest { public spreadElement51() { // Cant test functional because our VM doesn't run on 5.1 const lua = util.transpileString(`[].push(...${JSON.stringify([1, 2, 3])});`, {luaTarget: LuaTarget.Lua51}); - Expect(lua).toBe("__TS__ArrayPush({}, unpack({1,2,3}))"); + Expect(lua).toBe("__TS__ArrayPush({}, unpack({1,2,3}));"); } }