diff --git a/src/Decorator.ts b/src/Decorator.ts index c73dff6b2..e0b3b6a00 100644 --- a/src/Decorator.ts +++ b/src/Decorator.ts @@ -21,5 +21,4 @@ export enum DecoratorKind { Phantom = "Phantom", TupleReturn = "TupleReturn", NoClassOr = "NoClassOr", - NoContext = "NoContext", } diff --git a/src/Errors.ts b/src/Errors.ts index 9c0319904..37331ef36 100644 --- a/src/Errors.ts +++ b/src/Errors.ts @@ -68,4 +68,10 @@ export class TSTLErrors { public static UnsupportedObjectLiteralElement = (elementKind: ts.SyntaxKind, node: ts.Node) => new TranspileError(`Unsupported object literal element: ${elementKind}.`, node) + + public static UnsupportedFunctionConversion = (node: ts.Node) => + new TranspileError(`Unsupported conversion from method to function.`, node) + + public static UnsupportedMethodConversion = (node: ts.Node) => + new TranspileError(`Unsupported conversion from function to method.`, node) } diff --git a/src/TSHelper.ts b/src/TSHelper.ts index 03db7e577..c1c0bae25 100644 --- a/src/TSHelper.ts +++ b/src/TSHelper.ts @@ -248,4 +248,38 @@ export class TSHelper { } return [false, null, null]; } + + public static isDeclarationWithContext(sigDecl: ts.SignatureDeclaration, checker: ts.TypeChecker): boolean { + const thisArg = sigDecl.parameters.find(p => ts.isIdentifier(p.name) + && p.name.originalKeywordKind === ts.SyntaxKind.ThisKeyword); + if (thisArg) { + // Explicit 'this' + return !thisArg.type || thisArg.type.kind !== ts.SyntaxKind.VoidKeyword; + } + if ((ts.isMethodDeclaration(sigDecl) || ts.isMethodSignature(sigDecl)) + && !(ts.getCombinedModifierFlags(sigDecl) & ts.ModifierFlags.Static)) { + // Non-static method + return true; + } + if ((ts.isPropertySignature(sigDecl.parent) || ts.isPropertyDeclaration(sigDecl.parent)) + && !(ts.getCombinedModifierFlags(sigDecl.parent) & ts.ModifierFlags.Static)) { + // Non-static lambda property + return true; + } + if (ts.isBinaryExpression(sigDecl.parent) + && this.isFunctionWithContext(checker.getTypeAtLocation(sigDecl.parent.left), checker)) { + // Function expression: check type being assigned to + return true; + } + return false; + } + + public static isFunctionWithContext(type: ts.Type, checker: ts.TypeChecker): boolean { + const sigs = checker.getSignaturesOfType(type, ts.SignatureKind.Call); + if (sigs.length === 0) { + return false; + } + const sigDecls = sigs.map(s => s.getDeclaration()); + return sigDecls.every(s => this.isDeclarationWithContext(s, checker)); + } } diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 59aaa2d9c..86a7ad4e2 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -942,8 +942,12 @@ export abstract class LuaTranspiler { return this.transpileSetAccessor(node.left as ts.PropertyAccessExpression, rhs); } + // Validate assignment + const rightType = this.checker.getTypeAtLocation(node.right); + const leftType = this.checker.getTypeAtLocation(node.left); + this.validateAssignment(node.right, rightType, leftType); + if (ts.isArrayLiteralExpression(node.left)) { - // Destructing assignment const vars = node.left.elements.map(e => this.transpileExpression(e)).join(","); const vals = tsHelper.isTupleReturnCall(node.right, this.checker) ? rhs : this.transpileDestructingAssignmentValue(node.right); @@ -1144,7 +1148,8 @@ export abstract class LuaTranspiler { public transpileNewExpression(node: ts.NewExpression): string { const name = this.transpileExpression(node.expression); - let params = node.arguments ? this.transpileArguments(node.arguments, ts.createTrue()) : "true"; + const sig = this.checker.getResolvedSignature(node); + const params = node.arguments ? this.transpileArguments(node.arguments, sig, ts.createTrue()) : "true"; const type = this.checker.getTypeAtLocation(node); const classDecorators = tsHelper.getCustomDecorators(type, this.checker); @@ -1159,15 +1164,7 @@ export abstract class LuaTranspiler { if (!customDecorator.args[0]) { throw TSTLErrors.InvalidDecoratorArgumentNumber("!CustomConstructor", 0, 1, node); } - if (!ts.isPropertyAccessExpression(node.expression) - && !ts.isElementAccessExpression(node.expression) - && !tsHelper.getCustomDecorators(type, this.checker).has(DecoratorKind.NoContext)) { - const context = this.isStrict ? ts.createNull() : ts.createIdentifier("_G"); - params = this.transpileArguments(node.arguments, context); - } else { - params = this.transpileArguments(node.arguments); - } - return `${customDecorator.args[0]}(${params})`; + return `${customDecorator.args[0]}(${this.transpileArguments(node.arguments)})`; } return `${name}.new(${params})`; @@ -1190,22 +1187,25 @@ export abstract class LuaTranspiler { ? `({ ${result} })` : result; } + const sig = this.checker.getResolvedSignature(node); + // Handle super calls properly if (node.expression.kind === ts.SyntaxKind.SuperKeyword) { - params = this.transpileArguments(node.arguments, ts.createNode(ts.SyntaxKind.ThisKeyword) as ts.Expression); + params = this.transpileArguments(node.arguments, sig, + ts.createNode(ts.SyntaxKind.ThisKeyword) as ts.Expression); const className = this.classStack[this.classStack.length - 1]; return `${className}.__base.constructor(${params})`; } - callPath = this.transpileExpression(node.expression); const type = this.checker.getTypeAtLocation(node.expression); - if (!ts.isPropertyAccessExpression(node.expression) - && !ts.isElementAccessExpression(node.expression) - && !tsHelper.getCustomDecorators(type, this.checker).has(DecoratorKind.NoContext)) { + callPath = this.transpileExpression(node.expression); + if (tsHelper.isFunctionWithContext(type, this.checker) + && !ts.isPropertyAccessExpression(node.expression) + && !ts.isElementAccessExpression(node.expression)) { const context = this.isStrict ? ts.createNull() : ts.createIdentifier("_G"); - params = this.transpileArguments(node.arguments, context); + params = this.transpileArguments(node.arguments, sig, context); } else { - params = this.transpileArguments(node.arguments); + params = this.transpileArguments(node.arguments, sig); } return isTupleReturn && !isTupleReturnForward && !isInDestructingAssignment && returnValueIsUsed ? `({ ${callPath}(${params}) })` : `${callPath}(${params})`; @@ -1248,10 +1248,13 @@ export abstract class LuaTranspiler { return this.transpileFunctionCallExpression(node); } + const sig = this.checker.getResolvedSignature(node); + // Get the type of the function if (node.expression.expression.kind === ts.SyntaxKind.SuperKeyword) { // Super calls take the format of super.call(self,...) - params = this.transpileArguments(node.arguments, ts.createNode(ts.SyntaxKind.ThisKeyword) as ts.Expression); + params = this.transpileArguments(node.arguments, sig, + ts.createNode(ts.SyntaxKind.ThisKeyword) as ts.Expression); return `${this.transpileExpression(node.expression)}(${params})`; } else { // Replace last . with : here @@ -1260,13 +1263,13 @@ export abstract class LuaTranspiler { return `tostring(${this.transpileExpression(node.expression.expression)})`; } else if (name === "hasOwnProperty") { const expr = this.transpileExpression(node.expression.expression); - params = this.transpileArguments(node.arguments); + params = this.transpileArguments(node.arguments, sig); return `(rawget(${expr}, ${params} )~=nil)`; } else { const type = this.checker.getTypeAtLocation(node.expression); - const op = tsHelper.getCustomDecorators(type, this.checker).has(DecoratorKind.NoContext) ? "." : ":"; + const op = tsHelper.isFunctionWithContext(type, this.checker) ? ":" : "."; callPath = `${this.transpileExpression(node.expression.expression)}${op}${name}`; - params = this.transpileArguments(node.arguments); + params = this.transpileArguments(node.arguments, sig); return `${callPath}(${params})`; } } @@ -1387,6 +1390,10 @@ export abstract class LuaTranspiler { public transpileFunctionCallExpression(node: ts.CallExpression): string { const expression = node.expression as ts.PropertyAccessExpression; + const callerType = this.checker.getTypeAtLocation(expression.expression); + if (!tsHelper.isFunctionWithContext(callerType, this.checker)) { + throw TSTLErrors.UnsupportedMethodConversion(node); + } const params = this.transpileArguments(node.arguments); const caller = this.transpileExpression(expression.expression); const expressionName = this.transpileIdentifier(expression.name); @@ -1402,7 +1409,31 @@ export abstract class LuaTranspiler { } } - public transpileArguments(params: ts.NodeArray, context?: ts.Expression): string { + public validateAssignment(node: ts.Node, fromType: ts.Type, toType: ts.Type): void { + if ((toType.flags & ts.TypeFlags.Any) !== 0) { + // Assigning to un-typed variable + return; + } else if ((fromType as ts.TypeReference).typeArguments && (toType as ts.TypeReference).typeArguments) { + // Recurse into tuples/arrays + (toType as ts.TypeReference).typeArguments.forEach((t, i) => { + this.validateAssignment(node, (fromType as ts.TypeReference).typeArguments[i], t); + }); + } else { + // Check function assignments + const fromHasContext = tsHelper.isFunctionWithContext(fromType, this.checker); + const toHasContext = tsHelper.isFunctionWithContext(toType, this.checker); + if (fromHasContext !== toHasContext) { + if (fromHasContext) { + throw TSTLErrors.UnsupportedFunctionConversion(node); + } else { + throw TSTLErrors.UnsupportedMethodConversion(node); + } + } + } + } + + public transpileArguments(params: ts.NodeArray, sig?: ts.Signature, + context?: ts.Expression): string { const parameters: string[] = []; // Add context as first param if present @@ -1410,9 +1441,19 @@ export abstract class LuaTranspiler { parameters.push(this.transpileExpression(context)); } - params.forEach(param => { - parameters.push(this.transpileExpression(param)); - }); + if (sig && sig.parameters.length >= params.length) { + for (let i = 0; i < params.length; ++i) { + const param = params[i]; + const paramType = this.checker.getTypeAtLocation(param); + const sigType = this.checker.getTypeAtLocation(sig.parameters[i].valueDeclaration); + this.validateAssignment(param, paramType, sigType); + parameters.push(this.transpileExpression(param)); + } + } else { + params.forEach(param => { + parameters.push(this.transpileExpression(param)); + }); + } return parameters.join(","); } @@ -1592,6 +1633,13 @@ export abstract class LuaTranspiler { } public transpileVariableDeclaration(node: ts.VariableDeclaration): string { + if (node.initializer) { + // Validate assignment + const initializerType = this.checker.getTypeAtLocation(node.initializer); + const varType = this.checker.getTypeFromTypeNode(node.type); + this.validateAssignment(node.initializer, initializerType, varType); + } + if (ts.isIdentifier(node.name)) { // Find variable identifier const identifierName = this.transpileIdentifier(node.name); @@ -1635,7 +1683,7 @@ export abstract class LuaTranspiler { const methodName = this.transpileIdentifier(node.name); const type = this.checker.getTypeAtLocation(node); - const context = tsHelper.getCustomDecorators(type, this.checker).has(DecoratorKind.NoContext) ? null : "self"; + const context = tsHelper.isFunctionWithContext(type, this.checker) ? "self" : null; const [paramNames, spreadIdentifier] = this.transpileParameters(node.parameters, context); let prefix = this.accessPrefix(node); @@ -1672,6 +1720,9 @@ export abstract class LuaTranspiler { // Only push parameter name to paramName array if it isn't a spread parameter for (const param of parameters) { + if (ts.isIdentifier(param.name) && param.name.originalKeywordKind === ts.SyntaxKind.ThisKeyword) { + continue; + } const paramName = this.transpileIdentifier(param.name as ts.Identifier); // This parameter is a spread parameter (...param) @@ -1718,7 +1769,7 @@ export abstract class LuaTranspiler { } const type = this.checker.getTypeAtLocation(node); - const context = tsHelper.getCustomDecorators(type, this.checker).has(DecoratorKind.NoContext) ? null : "self"; + const context = tsHelper.isFunctionWithContext(type, this.checker) ? "self" : null; const [paramNames, spreadIdentifier] = this.transpileParameters(node.parameters, context); // Build function header @@ -1918,6 +1969,9 @@ export abstract class LuaTranspiler { public transpileConstructor(node: ts.ConstructorDeclaration, className: string): string { + // Don't transpile methods without body (overload declarations) + if (!node.body) { return ""; } + const extraInstanceFields = []; const parameters = ["self"]; @@ -1987,8 +2041,10 @@ export abstract class LuaTranspiler { } public transpileFunctionExpression(node: ts.FunctionLikeDeclaration, context: string | null): string { + const type = this.checker.getTypeAtLocation(node); + const hasContext = tsHelper.isFunctionWithContext(type, this.checker); // Build parameter string - const [paramNames, spreadIdentifier] = this.transpileParameters(node.parameters, context); + const [paramNames, spreadIdentifier] = this.transpileParameters(node.parameters, hasContext ? context : null); let result = `function(${paramNames.join(",")})\n`; this.pushIndent(); const body = ts.isBlock(node.body) ? node.body : ts.createBlock([ts.createReturn(node.body)]); diff --git a/src/lualib/ArrayConcat.ts b/src/lualib/ArrayConcat.ts index 145673ab1..06d5206b3 100644 --- a/src/lualib/ArrayConcat.ts +++ b/src/lualib/ArrayConcat.ts @@ -1,9 +1,6 @@ -/** !NoContext */ declare function pcall(func: () => any): any; -/** !NoContext */ declare function type(val: any): string; -/** !NoContext */ function __TS__ArrayConcat(arr1: any[], ...args: any[]): any[] { const out: any[] = []; for (const val of arr1) { diff --git a/src/lualib/ArrayEvery.ts b/src/lualib/ArrayEvery.ts index 7774eb911..e8434175a 100644 --- a/src/lualib/ArrayEvery.ts +++ b/src/lualib/ArrayEvery.ts @@ -1,4 +1,3 @@ -/** !NoContext */ function __TS__ArrayEvery(arr: T[], callbackfn: (value: T, index?: number, array?: any[]) => boolean): boolean { for (let i = 0; i < arr.length; i++) { if (!callbackfn(arr[i], i, arr)) { diff --git a/src/lualib/ArrayFilter.ts b/src/lualib/ArrayFilter.ts index d0495c399..8f0ac2fde 100644 --- a/src/lualib/ArrayFilter.ts +++ b/src/lualib/ArrayFilter.ts @@ -1,4 +1,3 @@ -/** !NoContext */ function __TS__ArrayFilter(arr: T[], callbackfn: (value: T, index?: number, array?: any[]) => boolean): T[] { const result: T[] = []; for (let i = 0; i < arr.length; i++) { diff --git a/src/lualib/ArrayForEach.ts b/src/lualib/ArrayForEach.ts index 28cd54b8b..3001915f0 100644 --- a/src/lualib/ArrayForEach.ts +++ b/src/lualib/ArrayForEach.ts @@ -1,4 +1,3 @@ -/** !NoContext */ function __TS__ArrayForEach(arr: T[], callbackFn: (value: T, index?: number, array?: any[]) => any): void { for (let i = 0; i < arr.length; i++) { callbackFn(arr[i], i, arr); diff --git a/src/lualib/ArrayIndexOf.ts b/src/lualib/ArrayIndexOf.ts index fd2e19da5..c50ce5ded 100644 --- a/src/lualib/ArrayIndexOf.ts +++ b/src/lualib/ArrayIndexOf.ts @@ -1,4 +1,3 @@ -/** !NoContext */ function __TS__ArrayIndexOf(arr: T[], searchElement: T, fromIndex?: number): number { const len = arr.length; if (len === 0) { diff --git a/src/lualib/ArrayMap.ts b/src/lualib/ArrayMap.ts index dd595b329..f7ea7aa50 100644 --- a/src/lualib/ArrayMap.ts +++ b/src/lualib/ArrayMap.ts @@ -1,4 +1,3 @@ -/** !NoContext */ function __TS__ArrayMap(arr: T[], callbackfn: (value: T, index?: number, array?: T[]) => U): U[] { const newArray: U[] = []; for (let i = 0; i < arr.length; i++) { diff --git a/src/lualib/ArrayPush.ts b/src/lualib/ArrayPush.ts index 104663375..8e1d8e324 100644 --- a/src/lualib/ArrayPush.ts +++ b/src/lualib/ArrayPush.ts @@ -1,4 +1,3 @@ -/** !NoContext */ function __TS__ArrayPush(arr: T[], ...items: T[]): number { for (const item of items) { arr[arr.length] = item; diff --git a/src/lualib/ArrayReverse.ts b/src/lualib/ArrayReverse.ts index 65349a905..3c4839417 100644 --- a/src/lualib/ArrayReverse.ts +++ b/src/lualib/ArrayReverse.ts @@ -1,4 +1,3 @@ -/** !NoContext */ function __TS__ArrayReverse(arr: any[]): any[] { let i = 0; let j = arr.length - 1; diff --git a/src/lualib/ArrayShift.ts b/src/lualib/ArrayShift.ts index 11a5b9a89..a95df1a49 100644 --- a/src/lualib/ArrayShift.ts +++ b/src/lualib/ArrayShift.ts @@ -1,8 +1,6 @@ declare namespace table { - /** !NoContext */ function remove(arr: T[], idx: number): T; } -/** !NoContext */ function __TS__ArrayShift(arr: T[]): T { return table.remove(arr, 1); } diff --git a/src/lualib/ArraySlice.ts b/src/lualib/ArraySlice.ts index bfb0d021c..f3eb5b3d6 100644 --- a/src/lualib/ArraySlice.ts +++ b/src/lualib/ArraySlice.ts @@ -1,5 +1,4 @@ // https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf 22.1.3.23 -/** !NoContext */ function __TS__ArraySlice(list: T[], first: number, last: number): T[] { const len = list.length; diff --git a/src/lualib/ArraySome.ts b/src/lualib/ArraySome.ts index ad2817eac..d03e7a9fe 100644 --- a/src/lualib/ArraySome.ts +++ b/src/lualib/ArraySome.ts @@ -1,4 +1,3 @@ -/** !NoContext */ function __TS__ArraySome(arr: T[], callbackfn: (value: T, index?: number, array?: any[]) => boolean): boolean { for (let i = 0; i < arr.length; i++) { if (callbackfn(arr[i], i, arr)) { diff --git a/src/lualib/ArraySort.ts b/src/lualib/ArraySort.ts index 2e02d2572..18745695c 100644 --- a/src/lualib/ArraySort.ts +++ b/src/lualib/ArraySort.ts @@ -1,8 +1,6 @@ declare namespace table { - /** !NoContext */ function sort(arr: T[], compareFn?: (a: T, b: T) => number): void; } -/** !NoContext */ function __TS__ArraySort(arr: T[], compareFn?: (a: T, b: T) => number): T[] { table.sort(arr, compareFn); return arr; diff --git a/src/lualib/ArraySplice.ts b/src/lualib/ArraySplice.ts index 2c20c98e0..b875d706c 100644 --- a/src/lualib/ArraySplice.ts +++ b/src/lualib/ArraySplice.ts @@ -1,4 +1,3 @@ -/** !NoContext */ function __TS__ArraySplice(list: T[], start: number, deleteCount: number, ...items: T[]): T[] { const len = list.length; diff --git a/src/lualib/ArrayUnshift.ts b/src/lualib/ArrayUnshift.ts index 3c5508b02..cb0031100 100644 --- a/src/lualib/ArrayUnshift.ts +++ b/src/lualib/ArrayUnshift.ts @@ -1,8 +1,6 @@ declare namespace table { - /** !NoContext */ function insert(arr: T[], idx: number, val: T): void; } -/** !NoContext */ function __TS__ArrayUnshift(arr: T[], ...items: T[]): number { for (let i = items.length - 1; i >= 0; --i) { table.insert(arr, 1, items[i]); diff --git a/src/lualib/FunctionApply.ts b/src/lualib/FunctionApply.ts index c58691959..6776f0e02 100644 --- a/src/lualib/FunctionApply.ts +++ b/src/lualib/FunctionApply.ts @@ -1,15 +1,11 @@ -/** !NoContext */ declare function unpack(list: T[], i?: number, j?: number): T[]; declare namespace table { - /** !NoContext */ export function unpack(list: T[], i?: number, j?: number): T[]; } -/** !NoContext */ type ApplyFn = (...argArray: any[]) => any; -/** !NoContext */ function __TS__FunctionApply(fn: ApplyFn, thisArg: any, argsArray?: any[]): any { if (argsArray) { return fn(thisArg, (unpack || table.unpack)(argsArray)); diff --git a/src/lualib/FunctionBind.ts b/src/lualib/FunctionBind.ts index fad7c70ae..e1e7675b5 100644 --- a/src/lualib/FunctionBind.ts +++ b/src/lualib/FunctionBind.ts @@ -1,18 +1,13 @@ -/** !NoContext */ declare function unpack(list: T[], i?: number, j?: number): T[]; declare namespace table { - /** !NoContext */ export function insert(t: T[], pos: number, value: T): void; - /** !NoContext */ export function unpack(list: T[], i?: number, j?: number): T[]; } -/** !NoContext */ type BindFn = (...argArray: any[]) => any; -/** !NoContext */ function __TS__FunctionBind(fn: BindFn, thisArg: any, ...boundArgs: any[]): (...args: any[]) => any { return (...argArray: any[]) => { for (let i = 0; i < boundArgs.length; ++i) { diff --git a/src/lualib/FunctionCall.ts b/src/lualib/FunctionCall.ts index 5f7acd3d7..fe126ccd5 100644 --- a/src/lualib/FunctionCall.ts +++ b/src/lualib/FunctionCall.ts @@ -1,15 +1,11 @@ -/** !NoContext */ declare function unpack(list: T[], i?: number, j?: number): T[]; declare namespace table { - /** !NoContext */ export function unpack(list: T[], i?: number, j?: number): T[]; } -/** !NoContext */ type CallFn = (...argArray: any[]) => any; -/** !NoContext */ function __TS__FunctionCall(fn: CallFn, thisArg: any, ...args: any[]): any { return fn(thisArg, (unpack || table.unpack)(args)); } diff --git a/src/lualib/InstanceOf.ts b/src/lualib/InstanceOf.ts index eb013aaaf..3b6a12dab 100644 --- a/src/lualib/InstanceOf.ts +++ b/src/lualib/InstanceOf.ts @@ -3,7 +3,6 @@ interface LuaClass { __base: LuaClass; } -/** !NoContext */ function __TS__InstanceOf(obj: LuaClass, classTbl: LuaClass): boolean { while (obj !== undefined) { if (obj.__index === classTbl) { diff --git a/src/lualib/StringReplace.ts b/src/lualib/StringReplace.ts index f5b6fd4d3..7a5df979c 100644 --- a/src/lualib/StringReplace.ts +++ b/src/lualib/StringReplace.ts @@ -1,10 +1,8 @@ declare namespace string { - /** !NoContext */ /** !TupleReturn */ function gsub(source: string, searchValue: string, replaceValue: string): [string, number]; } -/** !NoContext */ function __TS__StringReplace(source: string, searchValue: string, replaceValue: string): string { return string.gsub(source, searchValue, replaceValue)[0]; } diff --git a/src/lualib/StringSplit.ts b/src/lualib/StringSplit.ts index 862e71ddc..005f57436 100644 --- a/src/lualib/StringSplit.ts +++ b/src/lualib/StringSplit.ts @@ -1,4 +1,3 @@ -/** !NoContext */ function __TS__StringSplit(source: string, separator?: string, limit?: number): string[] { if (limit === undefined) { limit = 4294967295; diff --git a/src/lualib/Ternary.ts b/src/lualib/Ternary.ts index 4e2201d7d..f1331f4f4 100644 --- a/src/lualib/Ternary.ts +++ b/src/lualib/Ternary.ts @@ -1,4 +1,3 @@ -/** !NoContext */ function __TS__Ternary(condition: boolean, cb1: () => T, cb2: () => T): T { if (condition) { return cb1(); diff --git a/test/src/util.ts b/test/src/util.ts index c4a0f8872..490323d3e 100644 --- a/test/src/util.ts +++ b/test/src/util.ts @@ -3,7 +3,7 @@ import * as ts from "typescript"; import { Expect } from "alsatian"; -import { transpileString as _transpileString } from "../../src/Compiler"; +import { transpileString } from "../../src/Compiler"; import { CompilerOptions } from "../../src/CompilerOptions"; import { LuaTarget, LuaTranspiler } from "../../src/Transpiler"; import { createTranspiler } from "../../src/TranspilerFactory"; @@ -12,9 +12,7 @@ import {lauxlib, lua, lualib, to_jsstring, to_luastring } from "fengari"; import * as fs from "fs"; -export function transpileString(str: string, options?: CompilerOptions): string { - return _transpileString("/** !NoContext */ declare function JSONStringify(t: any): string;\n" + str, options); -} +export { transpileString }; export function executeLua(luaStr: string, withLib = true): any { if (withLib) { diff --git a/test/translation/lua/callNamespace.lua b/test/translation/lua/callNamespace.lua index 40b907163..b0ec0d650 100644 --- a/test/translation/lua/callNamespace.lua +++ b/test/translation/lua/callNamespace.lua @@ -1 +1 @@ -Namespace:myFunction(); +Namespace.myFunction(); diff --git a/test/translation/lua/dotColonFunctionCalls.lua b/test/translation/lua/dotColonFunctionCalls.lua index 5deaffabb..554ca6709 100644 --- a/test/translation/lua/dotColonFunctionCalls.lua +++ b/test/translation/lua/dotColonFunctionCalls.lua @@ -2,5 +2,5 @@ classInstance:colonMethod(); classInstance:dotMethod(); interfaceInstance:colonMethod(); interfaceInstance:dotMethod(); -TestNameSpace:dotMethod(); -TestNameSpace:dotMethod2(); +TestNameSpace.dotMethod(); +TestNameSpace.dotMethod2(); diff --git a/test/translation/lua/functionRestArguments.lua b/test/translation/lua/functionRestArguments.lua index f2db4825d..78d60a18e 100644 --- a/test/translation/lua/functionRestArguments.lua +++ b/test/translation/lua/functionRestArguments.lua @@ -1,3 +1,3 @@ -function varargsFunction(self,a,...) +function varargsFunction(a,...) local b = { ... } end diff --git a/test/translation/lua/modulesFunctionExport.lua b/test/translation/lua/modulesFunctionExport.lua index 6fce9cb9e..5b447e5b2 100644 --- a/test/translation/lua/modulesFunctionExport.lua +++ b/test/translation/lua/modulesFunctionExport.lua @@ -1,5 +1,5 @@ local exports = exports or {} -local function publicFunc(self) +local function publicFunc() end exports.publicFunc = publicFunc return exports diff --git a/test/translation/lua/modulesFunctionNoExport.lua b/test/translation/lua/modulesFunctionNoExport.lua index 855900df8..e0e619215 100644 --- a/test/translation/lua/modulesFunctionNoExport.lua +++ b/test/translation/lua/modulesFunctionNoExport.lua @@ -1,2 +1,2 @@ -function publicFunc(self) +function publicFunc() end diff --git a/test/translation/lua/modulesNamespaceNestedWithMemberExport.lua b/test/translation/lua/modulesNamespaceNestedWithMemberExport.lua index 1c9884b12..326a00294 100644 --- a/test/translation/lua/modulesNamespaceNestedWithMemberExport.lua +++ b/test/translation/lua/modulesNamespaceNestedWithMemberExport.lua @@ -3,7 +3,7 @@ local TestSpace = exports.TestSpace or TestSpace or {} do local TestNestedSpace = TestNestedSpace or {} do - local function innerFunc(self) + local function innerFunc() end TestNestedSpace.innerFunc = innerFunc end diff --git a/test/translation/lua/modulesNamespaceWithMemberExport.lua b/test/translation/lua/modulesNamespaceWithMemberExport.lua index fe2a50e3c..7e9204160 100644 --- a/test/translation/lua/modulesNamespaceWithMemberExport.lua +++ b/test/translation/lua/modulesNamespaceWithMemberExport.lua @@ -1,7 +1,7 @@ local exports = exports or {} local TestSpace = exports.TestSpace or TestSpace or {} do - local function innerFunc(self) + local function innerFunc() end TestSpace.innerFunc = innerFunc end diff --git a/test/translation/lua/modulesNamespaceWithMemberNoExport.lua b/test/translation/lua/modulesNamespaceWithMemberNoExport.lua index 752f8edfe..a2afe84fe 100644 --- a/test/translation/lua/modulesNamespaceWithMemberNoExport.lua +++ b/test/translation/lua/modulesNamespaceWithMemberNoExport.lua @@ -1,7 +1,7 @@ local exports = exports or {} local TestSpace = exports.TestSpace or TestSpace or {} do - local function innerFunc(self) + local function innerFunc() end end exports.TestSpace = TestSpace diff --git a/test/translation/lua/namespace.lua b/test/translation/lua/namespace.lua index dd63c6b89..c5a266c7f 100644 --- a/test/translation/lua/namespace.lua +++ b/test/translation/lua/namespace.lua @@ -1,5 +1,5 @@ myNamespace = myNamespace or {} do - local function nsMember(self) + local function nsMember() end end diff --git a/test/translation/lua/namespaceMerge.lua b/test/translation/lua/namespaceMerge.lua index cb5157727..3259d6488 100644 --- a/test/translation/lua/namespaceMerge.lua +++ b/test/translation/lua/namespaceMerge.lua @@ -9,10 +9,10 @@ end end function MergedClass.constructor(self) end -function MergedClass.staticMethodA(self) +function MergedClass.staticMethodA() end -function MergedClass.staticMethodB(self) - self:staticMethodA(); +function MergedClass.staticMethodB() + self.staticMethodA(); end function MergedClass.methodA(self) end @@ -22,12 +22,12 @@ function MergedClass.methodB(self) end MergedClass = MergedClass or {} do - local function namespaceFunc(self) + local function namespaceFunc() end MergedClass.namespaceFunc = namespaceFunc end local mergedClass = MergedClass.new(true); mergedClass:methodB(); mergedClass:propertyFunc(); -MergedClass:staticMethodB(); -MergedClass:namespaceFunc(); +MergedClass.staticMethodB(); +MergedClass.namespaceFunc(); diff --git a/test/translation/lua/namespaceNested.lua b/test/translation/lua/namespaceNested.lua index a8ec92f30..bff87b32e 100644 --- a/test/translation/lua/namespaceNested.lua +++ b/test/translation/lua/namespaceNested.lua @@ -2,7 +2,7 @@ myNamespace = myNamespace or {} do local myNestedNamespace = myNestedNamespace or {} do - local function nsMember(self) + local function nsMember() end end end diff --git a/test/translation/lua/namespacePhantom.lua b/test/translation/lua/namespacePhantom.lua index 2f3381780..b74a81173 100644 --- a/test/translation/lua/namespacePhantom.lua +++ b/test/translation/lua/namespacePhantom.lua @@ -1,2 +1,2 @@ -function nsMember(self) +function nsMember() end diff --git a/test/translation/lua/returnDefault.lua b/test/translation/lua/returnDefault.lua index 436b8ed62..52c2123e3 100644 --- a/test/translation/lua/returnDefault.lua +++ b/test/translation/lua/returnDefault.lua @@ -1,3 +1,3 @@ -function myFunc(self) +function myFunc() return end diff --git a/test/translation/lua/shorthandPropertyAssignment.lua b/test/translation/lua/shorthandPropertyAssignment.lua index 3514556fe..5caf484a0 100644 --- a/test/translation/lua/shorthandPropertyAssignment.lua +++ b/test/translation/lua/shorthandPropertyAssignment.lua @@ -1,3 +1,3 @@ -local f; f = function(_,x) +local f; f = function(x) return ({x = x}) end; diff --git a/test/translation/lua/tupleReturn.lua b/test/translation/lua/tupleReturn.lua index 30816b99a..7d33868fc 100644 --- a/test/translation/lua/tupleReturn.lua +++ b/test/translation/lua/tupleReturn.lua @@ -1,28 +1,28 @@ -function tupleReturn(self) +function tupleReturn() return 0,"foobar" end -tupleReturn(_G); -noTupleReturn(_G); -local a,b=tupleReturn(_G); -local c,d=table.unpack(noTupleReturn(_G)); -do local __TS_tmp0,__TS_tmp1 = tupleReturn(_G); a,b = __TS_tmp0,__TS_tmp1 end; -do local __TS_tmp0,__TS_tmp1 = table.unpack(noTupleReturn(_G)); c,d = __TS_tmp0,__TS_tmp1 end; -local e = ({ tupleReturn(_G) }); -local f = noTupleReturn(_G); -e = ({ tupleReturn(_G) }); -f = noTupleReturn(_G); -foo(_G,({ tupleReturn(_G) })); -foo(_G,noTupleReturn(_G)); -function tupleReturnFromVar(self) +tupleReturn(); +noTupleReturn(); +local a,b=tupleReturn(); +local c,d=table.unpack(noTupleReturn()); +do local __TS_tmp0,__TS_tmp1 = tupleReturn(); a,b = __TS_tmp0,__TS_tmp1 end; +do local __TS_tmp0,__TS_tmp1 = table.unpack(noTupleReturn()); c,d = __TS_tmp0,__TS_tmp1 end; +local e = ({ tupleReturn() }); +local f = noTupleReturn(); +e = ({ tupleReturn() }); +f = noTupleReturn(); +foo(({ tupleReturn() })); +foo(noTupleReturn()); +function tupleReturnFromVar() local r = {1,"baz"}; return table.unpack(r) end -function tupleReturnForward(self) - return tupleReturn(_G) +function tupleReturnForward() + return tupleReturn() end -function tupleNoForward(self) - return ({ tupleReturn(_G) }) +function tupleNoForward() + return ({ tupleReturn() }) end -function tupleReturnUnpack(self) - return table.unpack(tupleNoForward(_G)) +function tupleReturnUnpack() + return table.unpack(tupleNoForward()) end diff --git a/test/translation/ts/assignments.ts b/test/translation/ts/assignments.ts index e124a3019..a8e51e59a 100644 --- a/test/translation/ts/assignments.ts +++ b/test/translation/ts/assignments.ts @@ -2,19 +2,14 @@ declare let x: number; declare let y: number; declare let z: number; declare let obj: {prop: number, arr: number[]}; -/** !NoContext */ declare function getObj(): typeof obj; declare let arr: number[]; declare let arr2: number[][]; -/** !NoContext */ declare function getArr(): typeof arr; -/** !NoContext */ declare function getIndex(): number; declare let xTup: [number, number]; declare let yTup: [number, number]; -/** !NoContext */ declare function getTup(): [number, number]; -/** !NoContext */ /** !TupleReturn */ declare function getTupRet(): [number, number]; x = y; diff --git a/test/unit/assignmentDestructuring.spec.ts b/test/unit/assignmentDestructuring.spec.ts index 7c7241d8e..650e13024 100644 --- a/test/unit/assignmentDestructuring.spec.ts +++ b/test/unit/assignmentDestructuring.spec.ts @@ -15,7 +15,7 @@ export class AssignmentDestructuringTests { this.assignmentDestruturingTs, {luaTarget: LuaTarget.Lua51, luaLibImport: "none"} ); // Assert - Expect(lua).toBe(`local a,b=unpack(myFunc(_G));`); + Expect(lua).toBe(`local a,b=unpack(myFunc());`); } @Test("Assignment destructuring [5.2]") @@ -25,6 +25,6 @@ export class AssignmentDestructuringTests { this.assignmentDestruturingTs, {luaTarget: LuaTarget.Lua52, luaLibImport: "none"} ); // Assert - Expect(lua).toBe(`local a,b=table.unpack(myFunc(_G));`); + Expect(lua).toBe(`local a,b=table.unpack(myFunc());`); } } diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index 5f41581ba..e3ccb60c0 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -81,7 +81,7 @@ export class AssignmentTests { + `let [a,b] = abc();`; const lua = util.transpileString(code); - Expect(lua).toBe("local a,b=abc(_G);"); + Expect(lua).toBe("local a,b=abc();"); } @Test("TupleReturn Single assignment") @@ -92,7 +92,7 @@ export class AssignmentTests { + `a = abc();`; const lua = util.transpileString(code); - Expect(lua).toBe("local a = ({ abc(_G) });\na = ({ abc(_G) });"); + Expect(lua).toBe("local a = ({ abc() });\na = ({ abc() });"); } @Test("TupleReturn interface assignment") @@ -116,7 +116,7 @@ export class AssignmentTests { + `let [a,b] = def.abc();`; const lua = util.transpileString(code); - Expect(lua).toBe("local a,b=def:abc();"); + Expect(lua).toBe("local a,b=def.abc();"); } @Test("TupleReturn method assignment") diff --git a/test/unit/curry.spec.ts b/test/unit/curry.spec.ts index e73a7a813..06b27f057 100644 --- a/test/unit/curry.spec.ts +++ b/test/unit/curry.spec.ts @@ -10,8 +10,8 @@ export class LuaCurryTests { `(x: number) => (y: number) => x + y;` ); // Assert - Expect(lua).toBe(`function(_,x) - return function(_,y) + Expect(lua).toBe(`function(x) + return function(y) return x+y end end;`); diff --git a/test/unit/functions.spec.ts b/test/unit/functions.spec.ts index 4e5748824..cf0da8287 100644 --- a/test/unit/functions.spec.ts +++ b/test/unit/functions.spec.ts @@ -233,7 +233,7 @@ export class FunctionTests { @Test("Function bind") public functionBind(): void { - const source = `const abc = function (a: string, b: string) { return this.a + a + b; } + const source = `const abc = function (this: { a: number }, a: string, b: string) { return this.a + a + b; } return abc.bind({ a: 4 }, "b")("c");`; const result = util.transpileAndExecute(source); @@ -243,7 +243,7 @@ export class FunctionTests { @Test("Function apply") public functionApply(): void { - const source = `const abc = function (a: string) { return this.a + a; } + const source = `const abc = function (this: { a: number }, a: string) { return this.a + a; } return abc.apply({ a: 4 }, ["b"]);`; const result = util.transpileAndExecute(source); @@ -253,7 +253,7 @@ export class FunctionTests { @Test("Function call") public functionCall(): void { - const source = `const abc = function (a: string) { return this.a + a; } + const source = `const abc = function (this: { a: number }, a: string) { return this.a + a; } return abc.call({ a: 4 }, "b");`; const result = util.transpileAndExecute(source); diff --git a/test/unit/objectLiteral.spec.ts b/test/unit/objectLiteral.spec.ts index 55d488741..68fa4049d 100644 --- a/test/unit/objectLiteral.spec.ts +++ b/test/unit/objectLiteral.spec.ts @@ -9,7 +9,7 @@ export class ObjectLiteralTests { @TestCase(`{"a":3,b:"4"}`, `{["a"] = 3,b = "4"};`) @TestCase(`{["a"]:3,b:"4"}`, `{["a"] = 3,b = "4"};`) @TestCase(`{["a"+123]:3,b:"4"}`, `{["a" .. 123] = 3,b = "4"};`) - @TestCase(`{[myFunc()]:3,b:"4"}`, `{[myFunc(_G)] = 3,b = "4"};`) + @TestCase(`{[myFunc()]:3,b:"4"}`, `{[myFunc()] = 3,b = "4"};`) @TestCase(`{x}`, `{x = x};`) @Test("Object Literal") public objectLiteral(inp: string, out: string) {