From c407cae05a8e56d676814e3ff647f61923a3559b Mon Sep 17 00:00:00 2001 From: lolleko Date: Sat, 12 May 2018 00:42:23 +0200 Subject: [PATCH 1/3] Replaced lua.vm.js with fengari and updated tests. --- dist/lualib/typescript.lua | 2 +- package-lock.json | 46 ++++++++++++-- package.json | 2 +- src/Transpiler.ts | 2 +- test/src/util.ts | 43 ++++++++++--- .../translation/lua/assignmentDestructing.lua | 2 +- test/unit/assignments.spec.ts | 2 +- test/unit/conditionals.spec.ts | 16 ++--- test/unit/curry.spec.ts | 2 +- test/unit/expressions.spec.ts | 63 +++++++++++-------- test/unit/lualib.spec.ts | 54 ++++++++-------- test/unit/string.spec.ts | 13 ++-- 12 files changed, 159 insertions(+), 88 deletions(-) diff --git a/dist/lualib/typescript.lua b/dist/lualib/typescript.lua index abdfd4fd3..66c7a533e 100644 --- a/dist/lualib/typescript.lua +++ b/dist/lualib/typescript.lua @@ -116,7 +116,7 @@ function TS_split(str, separator) end function TS_push(list, ...) - for _, v in pairs({...}) do + for _, v in ipairs({...}) do list[#list + 1] = v end end diff --git a/package-lock.json b/package-lock.json index 4e9104a11..3baf9947b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -408,6 +408,25 @@ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, + "fengari": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/fengari/-/fengari-0.1.2.tgz", + "integrity": "sha512-NleQtQymPtbjBPnGOQiXfZfKpP3R7si+Sbkke631PWNnZt86eZSlymRJ0qv/KUTcz0fSsWO1iltZYz5/JV1uYQ==", + "dev": true, + "requires": { + "readline-sync": "1.4.9", + "sprintf-js": "1.1.1", + "tmp": "0.0.33" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz", + "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=", + "dev": true + } + } + }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -665,12 +684,6 @@ "yallist": "2.1.2" } }, - "lua.vm.js": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/lua.vm.js/-/lua.vm.js-0.0.1.tgz", - "integrity": "sha1-qiuWlrkEPxevmCjUrqzW2bwlacc=", - "dev": true - }, "mem": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", @@ -3426,6 +3439,12 @@ "mem": "1.1.0" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -3518,6 +3537,12 @@ "util-deprecate": "1.0.2" } }, + "readline-sync": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.9.tgz", + "integrity": "sha1-PtqOZfI80qF+YTAbHwADOWr17No=", + "dev": true + }, "reflect-metadata": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.12.tgz", @@ -3731,6 +3756,15 @@ "xtend": "4.0.1" } }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", diff --git a/package.json b/package.json index c97680b09..864ebf7e3 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "alsatian": "^2.2.1", "codecov": "^3.0.1", "deep-equal": "^1.0.1", - "lua.vm.js": "0.0.1", + "fengari": "^0.1.2", "nyc": "^11.7.1", "tslint": "^5.9.1" } diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 8d9877919..af4fa8412 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -1203,7 +1203,7 @@ export class LuaTranspiler { ) { return `local ${vars}=${value}\n`; } else { - return `local ${vars}=unpack(${value})\n`; + return `local ${vars}=table.unpack(${value})\n`; } } else { throw new TranspileError( diff --git a/test/src/util.ts b/test/src/util.ts index 30216fdf0..7eac3435f 100644 --- a/test/src/util.ts +++ b/test/src/util.ts @@ -6,7 +6,8 @@ import { Expect } from "alsatian"; import { LuaTranspiler, TranspileError, LuaTarget } from "../../src/Transpiler"; import { CompilerOptions } from "../../src/CommandLineParser"; -const LuaVM = require("lua.vm.js"); +import {lauxlib, lua, lualib, to_luastring} from "fengari"; + const fs = require("fs"); const libSource = fs.readFileSync(path.join(path.dirname(require.resolve('typescript')), 'lib.d.ts')).toString(); @@ -50,16 +51,40 @@ export function transpileFile(path: string): string { diagnostics.forEach(diagnostic => console.log(`${ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}`)); const options: ts.CompilerOptions = { dontRequireLuaLib: true }; - const lua = LuaTranspiler.transpileSourceFile(program.getSourceFile(path), checker, options); - return lua.trim(); + const result = LuaTranspiler.transpileSourceFile(program.getSourceFile(path), checker, options); + return result.trim(); +} + +export enum LuaReturnType { + String, + Number, + Boolean } -export function executeLua(lua: string, withLib = true): any { +export function executeLua(luaStr: string, type: LuaReturnType = LuaReturnType.String, withLib = true): any { if (withLib) { - lua = minimalTestLib + lua + luaStr = minimalTestLib + luaStr; } - const luavm = new LuaVM.Lua.State(); - return luavm.execute(lua)[0]; + + const L = lauxlib.luaL_newstate(); + lualib.luaL_openlibs(L); + lauxlib.luaL_dostring(L, to_luastring(luaStr)); + + let result; + + switch (type) { + case LuaReturnType.String: + result = lua.lua_tojsstring(L, -1); + break; + case LuaReturnType.Number: + result = lua.lua_tonumber(L, -1); + break; + case LuaReturnType.Boolean: + result = lua.lua_toboolean(L, -1); + break; + } + + return result; } export function expectCodeEqual(code1: string, code2: string) { @@ -74,8 +99,8 @@ export function expectCodeEqual(code1: string, code2: string) { Expect(c1).toBe(c2); } -const lualib = fs.readFileSync("dist/lualib/typescript.lua") + "\n"; +const tslualib = fs.readFileSync("dist/lualib/typescript.lua") + "\n"; const jsonlib = fs.readFileSync("test/src/json.lua") + "\n"; -export const minimalTestLib = lualib + jsonlib; +export const minimalTestLib = tslualib + jsonlib; diff --git a/test/translation/lua/assignmentDestructing.lua b/test/translation/lua/assignmentDestructing.lua index 8bb1cb9a3..d136990d4 100644 --- a/test/translation/lua/assignmentDestructing.lua +++ b/test/translation/lua/assignmentDestructing.lua @@ -1 +1 @@ -local a,b=unpack(myFunc()) \ No newline at end of file +local a,b=table.unpack(myFunc()) diff --git a/test/unit/assignments.spec.ts b/test/unit/assignments.spec.ts index b701179d0..5147f4637 100644 --- a/test/unit/assignments.spec.ts +++ b/test/unit/assignments.spec.ts @@ -51,7 +51,7 @@ export class AssignmentTests { public nullAssignment(declaration: string) { const lua = util.transpileString(declaration + " return myvar;"); const result = util.executeLua(lua); - Expect(result).toBe(undefined); + Expect(result).toBe(null); } @TestCase(["a", "b"], ["e", "f"]) diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index e7839f0f3..c2bce872c 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -17,7 +17,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua); + let result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(expected); @@ -38,7 +38,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua); + let result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(expected); @@ -64,7 +64,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua); + let result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(expected); @@ -91,7 +91,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua); + let result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(expected); @@ -122,7 +122,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua); + let result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(expected); @@ -156,7 +156,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua); + let result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(expected); @@ -202,7 +202,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua); + let result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(expected); @@ -246,7 +246,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua); + let result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(expected); diff --git a/test/unit/curry.spec.ts b/test/unit/curry.spec.ts index 7ede40d32..d6de3f8e1 100644 --- a/test/unit/curry.spec.ts +++ b/test/unit/curry.spec.ts @@ -24,7 +24,7 @@ export class LuaCurryTests { ); // Execute - let result = util.executeLua(lua); + let result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(x + y); diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index 4f964aada..acdb63bc9 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -28,34 +28,47 @@ export class ExpressionTests { }).toThrowError(Error, expectedError); } + @TestCase("1+1", "1+1") @TestCase("1-1", "1-1") @TestCase("1*1", "1*1") @TestCase("1/1", "1/1") @TestCase("1%1", "1%1") - @TestCase("1==1", "1==1") - @TestCase("1===1", "1==1") - @TestCase("1!=1", "1~=1") - @TestCase("1!==1", "1~=1") - @TestCase("1>1", "1>1") - @TestCase("1>=1", "1>=1") - @TestCase("1<1", "1<1") - @TestCase("1<=1", "1<=1") - @TestCase("1&&1", "1 and 1") - @TestCase("1||1", "1 or 1") - @Test("Binary expressions basic") - public binary(input: string, output: string) { + @Test("Binary expressions basic numeric") + public binaryNum(input: string, output: string) { // Transpile const lua = util.transpileString(input); // Execute - const result = util.executeLua(`return ${lua}`); + const result = util.executeLua(`return ${lua}`, util.LuaReturnType.Number); // Assert Expect(lua).toBe(output); Expect(result).toBe(eval(input)); } + @TestCase("1==1", true) + @TestCase("1===1", true) + @TestCase("1!=1", false) + @TestCase("1!==1", false) + @TestCase("1>1", false) + @TestCase("1>=1", true) + @TestCase("1<1", false) + @TestCase("1<=1", true) + @TestCase("1&&1", true) // TODO 1&&1 evals to one actually JS LUL + @TestCase("1||1", true) // TODO 1&&1 evals to one actually JS LUL + @Test("Binary expressions basic boolean") + public binaryBool(input: string, expected: any) { + // Transpile + const lua = util.transpileString(input); + + // Execute + const result = util.executeLua(`return ${lua}`, util.LuaReturnType.Boolean); + + // Assert + Expect(result).toBe(expected); + } + @TestCase("'key' in obj") @TestCase("'existingKey' in obj") @TestCase("0 in obj") @@ -66,7 +79,7 @@ export class ExpressionTests { const lua = util.transpileString(input); // Execute - const result = util.executeLua(`obj = { existingKey = 1 }\nreturn ${lua}`); + const result = util.executeLua(`obj = { existingKey = 1 }\nreturn ${lua}`, util.LuaReturnType.Boolean); // Assert Expect(result).toBe(eval(`let obj = { existingKey: 1 }; ${input}`)); @@ -134,7 +147,7 @@ export class ExpressionTests { const lua = util.transpileString(`let add = (a, b) => a+b; return add(1,2);`); // Execute - const result = util.executeLua(lua); + const result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(3); @@ -157,7 +170,7 @@ export class ExpressionTests { + `return add(${callArgs});`); // Execute - const result = util.executeLua(lua); + const result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(v1 + v2); @@ -169,7 +182,7 @@ export class ExpressionTests { const lua = util.transpileString(`let add = function(a, b) {return a+b}; return add(1,2);`); // Execute - const result = util.executeLua(lua); + const result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(3); @@ -202,7 +215,7 @@ export class ExpressionTests { + `return add(${callArgs});`); // Execute - const result = util.executeLua(lua); + const result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(v1 + v2); @@ -211,14 +224,14 @@ export class ExpressionTests { @TestCase("inst.field", 8) @TestCase("inst.field + 3", 8 + 3) @TestCase("inst.field * 3", 8 * 3) - @TestCase("inst.field / 3", 8 / 3) + @TestCase("inst.field / 2", 8 / 2) @TestCase("inst.field && 3", 8 && 3) @TestCase("inst.field || 3", 8 || 3) - // @TestCase("inst.field & 3", 8 & 3) + @TestCase("inst.field & 3", 8 & 3) // @TestCase("inst.field | 3", 8 | 3) // @TestCase("inst.field << 3", 8 << 3) // @TestCase("inst.field >> 1", 8 >> 1) - @TestCase(`"abc" + inst.field`, "abc8") + // @TestCase(`"abc" + inst.field`, "abc8") public getAccessorBinary(expression: string, expected: any) { const source = `class MyClass {` + ` public _field: number;` @@ -233,7 +246,7 @@ export class ExpressionTests { const lua = util.transpileString(source); // Execute - const result = util.executeLua(lua); + const result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(expected); @@ -243,11 +256,11 @@ export class ExpressionTests { @TestCase("-= 3", 4 - 3 + 4) @TestCase("+= 3", 4 + 3 + 4) @TestCase("*= 3", 4 * 3 + 4) - @TestCase("/= 3", 4 / 3 + 4) + @TestCase("/= 2", 4 / 2 + 4) // @TestCase("&= 3", 4 & 3 + 4) // @TestCase("|= 3", 4 | 3 + 4) // @TestCase("<<= 3", 4 << 3 + 4) - // @TestCase(">>= 3", 4 >> 3 + 4) + @TestCase(">>= 3", 4 >> 3 + 4) public setAccessorBinary(expression: string, expected: any) { const source = `class MyClass {` + ` public _field: number = 4;` @@ -262,7 +275,7 @@ export class ExpressionTests { const lua = util.transpileString(source); // Execute - const result = util.executeLua(lua); + const result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(expected); diff --git a/test/unit/lualib.spec.ts b/test/unit/lualib.spec.ts index d1a1f94ab..f2ff2e034 100644 --- a/test/unit/lualib.spec.ts +++ b/test/unit/lualib.spec.ts @@ -7,7 +7,7 @@ export class LuaLibArrayTests { @Test("forEach") public forEach(inp: number[], expected: number[]) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let arrTest = ${JSON.stringify(inp)}; arrTest.forEach((elem, index) => { arrTest[index] = arrTest[index] + 1; @@ -16,7 +16,7 @@ export class LuaLibArrayTests { ); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua); // Assert Expect(result).toBe(JSON.stringify(expected)); @@ -31,10 +31,10 @@ export class LuaLibArrayTests { @Test("array.map") public map(inp: T[], func: string) { // Transpile - let lua = util.transpileString(`return JSONStringify([${inp.toString()}].map(${func}))`); + const lua = util.transpileString(`return JSONStringify([${inp.toString()}].map(${func}))`); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua); // Assert Expect(result).toBe(JSON.stringify(inp.map(eval(func)))); @@ -50,10 +50,10 @@ export class LuaLibArrayTests { @Test("array.filter") public filter(inp: T[], func: string) { // Transpile - let lua = util.transpileString(`return JSONStringify([${inp.toString()}].filter(${func}))`); + const lua = util.transpileString(`return JSONStringify([${inp.toString()}].filter(${func}))`); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua); // Assert Expect(result).toBe(JSON.stringify(inp.filter(eval(func)))); @@ -66,13 +66,13 @@ export class LuaLibArrayTests { @Test("array.every") public every(inp: T[], func: string) { // Transpile - let lua = util.transpileString(`return [${inp.toString()}].every(${func}))`); + const lua = util.transpileString(`return JSONStringify([${inp.toString()}].every(${func})))`); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua); // Assert - Expect(JSON.stringify(result)).toBe(JSON.stringify(inp.every(eval(func)))); + Expect(result).toBe(JSON.stringify(inp.every(eval(func)))); } @TestCase([], "x => x > 1") @@ -82,13 +82,13 @@ export class LuaLibArrayTests { @Test("array.some") public some(inp: T[], func: string) { // Transpile - let lua = util.transpileString(`return [${inp.toString()}].some(${func}))`); + const lua = util.transpileString(`return JSONStringify([${inp.toString()}].some(${func})))`); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua); // Assert - Expect(JSON.stringify(result)).toBe(JSON.stringify(inp.some(eval(func)))); + Expect(result).toBe(JSON.stringify(inp.some(eval(func)))); } @TestCase([], 1, 2) @@ -101,10 +101,10 @@ export class LuaLibArrayTests { @Test("array.slice") public slice(inp: T[], start: number, end?: number) { // Transpile - let lua = util.transpileString(`return JSONStringify([${inp.toString()}].slice(${start}, ${end}))`); + const lua = util.transpileString(`return JSONStringify([${inp.toString()}].slice(${start}, ${end}))`); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua); // Assert Expect(result).toBe(JSON.stringify(inp.slice(start, end))); @@ -120,14 +120,14 @@ export class LuaLibArrayTests { @Test("array.splice[Insert]") public spliceInsert(inp: T[], start: number, deleteCount: number, ...newElements: any[]) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let spliceTestTable = [${inp.toString()}]; spliceTestTable.splice(${start}, ${deleteCount}, ${newElements}); return JSONStringify(spliceTestTable);` ); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua); // Assert inp.splice(start, deleteCount, ...newElements) @@ -144,10 +144,10 @@ export class LuaLibArrayTests { @Test("array.splice[Remove]") public spliceRemove(inp: T[], start: number, deleteCount?: number, ...newElements: any[]) { // Transpile - let lua = util.transpileString(`return JSONStringify([${inp.toString()}].splice(${start}, ${deleteCount}, ${newElements}))`); + const lua = util.transpileString(`return JSONStringify([${inp.toString()}].splice(${start}, ${deleteCount}, ${newElements}))`); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua); // Assert if (deleteCount) { @@ -173,16 +173,16 @@ export class LuaLibArrayTests { seperatorLua = ""; } // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let joinTestTable = ${JSON.stringify(inp)}; return joinTestTable.join(${seperatorLua});` ); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua); // Assert - let joinedInp = inp.join(seperator); + const joinedInp = inp.join(seperator); Expect(result).toBe(joinedInp); } @@ -192,13 +192,13 @@ export class LuaLibArrayTests { @Test("array.indexOf") public indexOf(inp: string[], element: string) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `return ${JSON.stringify(inp)}.indexOf("${element}"))` ); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua, util.LuaReturnType.Number); // Assert // Acount for lua indexing (-1) @@ -210,13 +210,13 @@ export class LuaLibArrayTests { @Test("array.destructuring.simple") public arrayDestructuringSimple(inp: number[], expected: number) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let [x, y, z] = ${JSON.stringify(inp)} return z; `); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(expected); @@ -227,7 +227,7 @@ export class LuaLibArrayTests { @Test("array.push") public arrayPush(inp: number[]) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let testArray = [0]; testArray.push(${inp.join(', ')}); return JSONStringify(testArray); @@ -235,7 +235,7 @@ export class LuaLibArrayTests { ); // Execute - let result = util.executeLua(lua); + const result = util.executeLua(lua); // Assert Expect(result).toBe(JSON.stringify([0].concat(inp))); diff --git a/test/unit/string.spec.ts b/test/unit/string.spec.ts index 6a0c12ea6..5b52c0a35 100644 --- a/test/unit/string.spec.ts +++ b/test/unit/string.spec.ts @@ -62,7 +62,8 @@ export class StringTests { public replace(inp: string, searchValue: string, replaceValue: string) { // Transpile const lua = util.transpileString( - `return "${inp}".replace("${searchValue}", "${replaceValue}")` + `local res = "${inp}".replace("${searchValue}", "${replaceValue}"); + return res;` ); // Execute @@ -100,12 +101,10 @@ export class StringTests { @Test("string.indexOf") public indexOf(inp: string, searchValue: string) { // Transpile - const lua = util.transpileString( - `return "${inp}".indexOf("${searchValue}")` - ); + const lua = util.transpileString(`return "${inp}".indexOf("${searchValue}")`); // Execute - const result = util.executeLua(lua); + const result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(inp.indexOf(searchValue)); @@ -123,7 +122,7 @@ export class StringTests { ); // Execute - const result = util.executeLua(lua); + const result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(inp.indexOf(searchValue, offset)); @@ -159,7 +158,7 @@ export class StringTests { ); // Execute - const result = util.executeLua(lua); + const result = util.executeLua(lua, util.LuaReturnType.Number); // Assert Expect(result).toBe(inp.length); From 1e23cb4094a0f2075d7d41bc30da36917e29db5b Mon Sep 17 00:00:00 2001 From: lolleko Date: Sat, 12 May 2018 11:11:07 +0200 Subject: [PATCH 2/3] Fixed minor issue, caused by string.gsub returning a pair of values --- dist/lualib/typescript.lua | 5 +++++ src/Transpiler.ts | 2 +- test/unit/string.spec.ts | 3 +-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/dist/lualib/typescript.lua b/dist/lualib/typescript.lua index 66c7a533e..9b8c8654d 100644 --- a/dist/lualib/typescript.lua +++ b/dist/lualib/typescript.lua @@ -85,6 +85,11 @@ function TS_indexOf(list, object ) return -1 end +function TS_replace(source, searchVal, newVal) + local result = string.gsub(source, searchVal, newVal) + return result +end + function TS_split(str, separator) local out = {} diff --git a/src/Transpiler.ts b/src/Transpiler.ts index af4fa8412..6e2d4d9f0 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -953,7 +953,7 @@ export class LuaTranspiler { const caller = this.transpileExpression(expression.expression); switch (expression.name.escapedText) { case "replace": - return `string.gsub(${caller},${params})`; + return `TS_replace(${caller},${params})`; case "indexOf": if (node.arguments.length === 1) { return `(string.find(${caller},${params},1,true) or 0)-1`; diff --git a/test/unit/string.spec.ts b/test/unit/string.spec.ts index 5b52c0a35..d1684377d 100644 --- a/test/unit/string.spec.ts +++ b/test/unit/string.spec.ts @@ -62,8 +62,7 @@ export class StringTests { public replace(inp: string, searchValue: string, replaceValue: string) { // Transpile const lua = util.transpileString( - `local res = "${inp}".replace("${searchValue}", "${replaceValue}"); - return res;` + `return "${inp}".replace("${searchValue}", "${replaceValue}");` ); // Execute From 885d92ca3a601c4d8c18cbd070969e798ba5c0f3 Mon Sep 17 00:00:00 2001 From: Perryvw Date: Sat, 12 May 2018 14:00:16 +0200 Subject: [PATCH 3/3] Fixed some issues with fengari VM execution for tests --- test/src/util.ts | 49 ++++++++++++++++---------------- test/unit/conditionals.spec.ts | 36 ++++++++++++------------ test/unit/curry.spec.ts | 8 +++--- test/unit/error.spec.ts | 2 +- test/unit/expressions.spec.ts | 51 +++++++++++++++++----------------- test/unit/lualib.spec.ts | 10 +++---- test/unit/string.spec.ts | 6 ++-- 7 files changed, 81 insertions(+), 81 deletions(-) diff --git a/test/src/util.ts b/test/src/util.ts index 7eac3435f..a64308815 100644 --- a/test/src/util.ts +++ b/test/src/util.ts @@ -6,13 +6,13 @@ import { Expect } from "alsatian"; import { LuaTranspiler, TranspileError, LuaTarget } from "../../src/Transpiler"; import { CompilerOptions } from "../../src/CommandLineParser"; -import {lauxlib, lua, lualib, to_luastring} from "fengari"; +import {lauxlib, lua, lualib, to_luastring, to_jsstring } from "fengari"; const fs = require("fs"); const libSource = fs.readFileSync(path.join(path.dirname(require.resolve('typescript')), 'lib.d.ts')).toString(); -export function transpileString(str: string, options: CompilerOptions = { dontRequireLuaLib: true, luaTarget: LuaTarget.LuaJIT }): string { +export function transpileString(str: string, options: CompilerOptions = { dontRequireLuaLib: true, luaTarget: LuaTarget.Lua53 }): string { let compilerHost = { getSourceFile: (filename, languageVersion) => { if (filename === "file.ts") { @@ -55,36 +55,35 @@ export function transpileFile(path: string): string { return result.trim(); } -export enum LuaReturnType { - String, - Number, - Boolean -} - -export function executeLua(luaStr: string, type: LuaReturnType = LuaReturnType.String, withLib = true): any { +export function executeLua(luaStr: string, withLib = true): any { if (withLib) { luaStr = minimalTestLib + luaStr; } const L = lauxlib.luaL_newstate(); lualib.luaL_openlibs(L); - lauxlib.luaL_dostring(L, to_luastring(luaStr)); - - let result; - - switch (type) { - case LuaReturnType.String: - result = lua.lua_tojsstring(L, -1); - break; - case LuaReturnType.Number: - result = lua.lua_tonumber(L, -1); - break; - case LuaReturnType.Boolean: - result = lua.lua_toboolean(L, -1); - break; + const status = lauxlib.luaL_dostring(L, to_luastring(luaStr)); + + if (status === lua.LUA_OK) { + // Read the return value from stack depending on its type. + if (lua.lua_isboolean(L, -1)) { + return lua.lua_toboolean(L, -1); + } else if (lua.lua_isnil(L, -1)) { + return null; + } else if (lua.lua_isnumber(L, -1)) { + return lua.lua_tonumber(L, -1); + } else if (lua.lua_isstring(L, -1)) { + return lua.lua_tojsstring(L, -1); + } else { + throw new Error("Unsupported lua return type: " + to_jsstring(lua.lua_typename(L, lua.lua_type(L, -1)))); + } + } else { + // If the lua VM did not terminate with status code LUA_OK an error occurred. + // Throw a JS error with the message, retrieved by reading a string from the stack. + + // Filter control characters out of string which are in there because ???? + throw new Error("LUA ERROR: " + to_jsstring(lua.lua_tostring(L, -1).filter(c => c >= 20))); } - - return result; } export function expectCodeEqual(code1: string, code2: string) { diff --git a/test/unit/conditionals.spec.ts b/test/unit/conditionals.spec.ts index c2bce872c..19d755149 100644 --- a/test/unit/conditionals.spec.ts +++ b/test/unit/conditionals.spec.ts @@ -1,5 +1,5 @@ -import { Expect, Test, TestCase, FocusTest } from "alsatian"; -import * as util from "../src/util" +import { Expect, Test, TestCase } from "alsatian"; +import * as util from "../src/util"; export class LuaConditionalsTests { @@ -8,7 +8,7 @@ export class LuaConditionalsTests { @Test("if") public if(inp: number, expected: number) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let input = ${inp} if (input === 0) { return 0; @@ -17,7 +17,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(expected); @@ -28,7 +28,7 @@ export class LuaConditionalsTests { @Test("ifelse") public ifelse(inp: number, expected: number) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let input = ${inp} if (input === 0) { return 0; @@ -38,7 +38,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(expected); @@ -51,7 +51,7 @@ export class LuaConditionalsTests { @Test("ifelseif") public ifelseif(inp: number, expected: number) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let input = ${inp} if (input === 0) { return 0; @@ -64,7 +64,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(expected); @@ -77,7 +77,7 @@ export class LuaConditionalsTests { @Test("ifelseifelse") public ifelseifelse(inp: number, expected: number) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let input = ${inp} if (input === 0) { return 0; @@ -91,7 +91,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(expected); @@ -104,7 +104,7 @@ export class LuaConditionalsTests { @Test("switch") public switch(inp: number, expected: number) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let result = -1; switch (${inp}) { @@ -122,7 +122,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(expected); @@ -135,7 +135,7 @@ export class LuaConditionalsTests { @Test("switchdefault") public switchdefault(inp: number, expected: number) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let result = -1; switch (${inp}) { @@ -156,7 +156,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(expected); @@ -172,7 +172,7 @@ export class LuaConditionalsTests { @Test("switchfallthrough") public switchfallthrough(inp: number, expected: number) { /// Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let result = -1; switch (${inp}) { @@ -202,7 +202,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(expected); @@ -215,7 +215,7 @@ export class LuaConditionalsTests { @Test("nestedSwitch") public nestedSwitch(inp: number, expected: number) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let result = -1; switch (${inp}) { @@ -246,7 +246,7 @@ export class LuaConditionalsTests { ); // Execute - let result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(expected); diff --git a/test/unit/curry.spec.ts b/test/unit/curry.spec.ts index d6de3f8e1..99d927ff6 100644 --- a/test/unit/curry.spec.ts +++ b/test/unit/curry.spec.ts @@ -1,12 +1,12 @@ import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util" +import * as util from "../src/util"; export class LuaCurryTests { @Test("currying") public currying() { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `(x: number) => (y: number) => x + y;` ); // Assert @@ -18,13 +18,13 @@ export class LuaCurryTests { @TestCase(5, 4) public curryingAdd(x: number, y: number) { // Transpile - let lua = util.transpileString( + const lua = util.transpileString( `let add = (x: number) => (y: number) => x + y; return add(${x})(${y})` ); // Execute - let result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(x + y); diff --git a/test/unit/error.spec.ts b/test/unit/error.spec.ts index 51f5c33c0..d2d817252 100644 --- a/test/unit/error.spec.ts +++ b/test/unit/error.spec.ts @@ -1,5 +1,5 @@ import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util" +import * as util from "../src/util"; export class LuaErrorTests { diff --git a/test/unit/expressions.spec.ts b/test/unit/expressions.spec.ts index acdb63bc9..4511fa7e7 100644 --- a/test/unit/expressions.spec.ts +++ b/test/unit/expressions.spec.ts @@ -28,7 +28,6 @@ export class ExpressionTests { }).toThrowError(Error, expectedError); } - @TestCase("1+1", "1+1") @TestCase("1-1", "1-1") @TestCase("1*1", "1*1") @@ -40,7 +39,7 @@ export class ExpressionTests { const lua = util.transpileString(input); // Execute - const result = util.executeLua(`return ${lua}`, util.LuaReturnType.Number); + const result = util.executeLua(`return ${lua}`); // Assert Expect(lua).toBe(output); @@ -55,15 +54,15 @@ export class ExpressionTests { @TestCase("1>=1", true) @TestCase("1<1", false) @TestCase("1<=1", true) - @TestCase("1&&1", true) // TODO 1&&1 evals to one actually JS LUL - @TestCase("1||1", true) // TODO 1&&1 evals to one actually JS LUL + @TestCase("1&&1", 1) + @TestCase("1||1", 1) @Test("Binary expressions basic boolean") public binaryBool(input: string, expected: any) { // Transpile const lua = util.transpileString(input); // Execute - const result = util.executeLua(`return ${lua}`, util.LuaReturnType.Boolean); + const result = util.executeLua(`return ${lua}`); // Assert Expect(result).toBe(expected); @@ -79,7 +78,7 @@ export class ExpressionTests { const lua = util.transpileString(input); // Execute - const result = util.executeLua(`obj = { existingKey = 1 }\nreturn ${lua}`, util.LuaReturnType.Boolean); + const result = util.executeLua(`obj = { existingKey = 1 }\nreturn ${lua}`); // Assert Expect(result).toBe(eval(`let obj = { existingKey: 1 }; ${input}`)); @@ -147,7 +146,7 @@ export class ExpressionTests { const lua = util.transpileString(`let add = (a, b) => a+b; return add(1,2);`); // Execute - const result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(3); @@ -170,7 +169,7 @@ export class ExpressionTests { + `return add(${callArgs});`); // Execute - const result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(v1 + v2); @@ -182,7 +181,7 @@ export class ExpressionTests { const lua = util.transpileString(`let add = function(a, b) {return a+b}; return add(1,2);`); // Execute - const result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(3); @@ -215,7 +214,7 @@ export class ExpressionTests { + `return add(${callArgs});`); // Execute - const result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(v1 + v2); @@ -227,11 +226,12 @@ export class ExpressionTests { @TestCase("inst.field / 2", 8 / 2) @TestCase("inst.field && 3", 8 && 3) @TestCase("inst.field || 3", 8 || 3) - @TestCase("inst.field & 3", 8 & 3) - // @TestCase("inst.field | 3", 8 | 3) - // @TestCase("inst.field << 3", 8 << 3) - // @TestCase("inst.field >> 1", 8 >> 1) - // @TestCase(`"abc" + inst.field`, "abc8") + @TestCase("(inst.field + 3) & 3", (8 + 3) & 3) + @TestCase("inst.field | 3", 8 | 3) + @TestCase("inst.field << 3", 8 << 3) + @TestCase("inst.field >> 1", 8 >> 1) + @TestCase(`"abc" + inst.field`, "abc8") + @Test("Get accessor expression") public getAccessorBinary(expression: string, expected: any) { const source = `class MyClass {` + ` public _field: number;` @@ -246,21 +246,22 @@ export class ExpressionTests { const lua = util.transpileString(source); // Execute - const result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(expected); } @TestCase("= 4", 4 + 4) - @TestCase("-= 3", 4 - 3 + 4) - @TestCase("+= 3", 4 + 3 + 4) - @TestCase("*= 3", 4 * 3 + 4) - @TestCase("/= 2", 4 / 2 + 4) - // @TestCase("&= 3", 4 & 3 + 4) - // @TestCase("|= 3", 4 | 3 + 4) - // @TestCase("<<= 3", 4 << 3 + 4) - @TestCase(">>= 3", 4 >> 3 + 4) + @TestCase("-= 3", (4 - 3) + 4) + @TestCase("+= 3", (4 + 3) + 4) + @TestCase("*= 3", (4 * 3) + 4) + @TestCase("/= 2", (4 / 2) + 4) + @TestCase("&= 3", (4 & 3) + 4) + @TestCase("|= 3", (4 | 3) + 4) + @TestCase("<<= 3", (4 << 3) + 4) + @TestCase(">>= 3", (4 >> 3) + 4) + @Test("Set accessorExpression") public setAccessorBinary(expression: string, expected: any) { const source = `class MyClass {` + ` public _field: number = 4;` @@ -275,7 +276,7 @@ export class ExpressionTests { const lua = util.transpileString(source); // Execute - const result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(expected); diff --git a/test/unit/lualib.spec.ts b/test/unit/lualib.spec.ts index f2ff2e034..865a88f33 100644 --- a/test/unit/lualib.spec.ts +++ b/test/unit/lualib.spec.ts @@ -1,5 +1,5 @@ import { Expect, Test, TestCase } from "alsatian"; -import * as util from "../src/util" +import * as util from "../src/util"; export class LuaLibArrayTests { @@ -130,7 +130,7 @@ export class LuaLibArrayTests { const result = util.executeLua(lua); // Assert - inp.splice(start, deleteCount, ...newElements) + inp.splice(start, deleteCount, ...newElements); Expect(result).toBe(JSON.stringify(inp)); } @@ -198,7 +198,7 @@ export class LuaLibArrayTests { ); // Execute - const result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert // Acount for lua indexing (-1) @@ -216,7 +216,7 @@ export class LuaLibArrayTests { `); // Execute - const result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(expected); @@ -229,7 +229,7 @@ export class LuaLibArrayTests { // Transpile const lua = util.transpileString( `let testArray = [0]; - testArray.push(${inp.join(', ')}); + testArray.push(${inp.join(", ")}); return JSONStringify(testArray); ` ); diff --git a/test/unit/string.spec.ts b/test/unit/string.spec.ts index d1684377d..ccbdae962 100644 --- a/test/unit/string.spec.ts +++ b/test/unit/string.spec.ts @@ -103,7 +103,7 @@ export class StringTests { const lua = util.transpileString(`return "${inp}".indexOf("${searchValue}")`); // Execute - const result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(inp.indexOf(searchValue)); @@ -121,7 +121,7 @@ export class StringTests { ); // Execute - const result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(inp.indexOf(searchValue, offset)); @@ -157,7 +157,7 @@ export class StringTests { ); // Execute - const result = util.executeLua(lua, util.LuaReturnType.Number); + const result = util.executeLua(lua); // Assert Expect(result).toBe(inp.length);