├── src
├── test
│ ├── resources
│ │ ├── me
│ │ │ └── saharnooby
│ │ │ │ └── luajssyntax
│ │ │ │ ├── Power.txt
│ │ │ │ ├── Literals.txt
│ │ │ │ ├── Parenthesis.txt
│ │ │ │ ├── DoWhile.txt
│ │ │ │ ├── Increment.txt
│ │ │ │ ├── Throw.txt
│ │ │ │ ├── Math.txt
│ │ │ │ ├── Require.txt
│ │ │ │ ├── Break.txt
│ │ │ │ ├── Logic.txt
│ │ │ │ ├── ChainCalls.txt
│ │ │ │ ├── ForOf.txt
│ │ │ │ ├── Concat.txt
│ │ │ │ ├── ForIn.txt
│ │ │ │ ├── Label.txt
│ │ │ │ ├── Globals.txt
│ │ │ │ ├── Return.txt
│ │ │ │ ├── Numbers.txt
│ │ │ │ ├── Unary.txt
│ │ │ │ ├── Lists.txt
│ │ │ │ ├── Bitwise.txt
│ │ │ │ ├── Comparison.txt
│ │ │ │ ├── For.txt
│ │ │ │ ├── ArrowFunctionLiteral.txt
│ │ │ │ ├── Locals.txt
│ │ │ │ ├── TryCatch.txt
│ │ │ │ ├── FunctionLiteral.txt
│ │ │ │ ├── Strings.txt
│ │ │ │ ├── Ternary.txt
│ │ │ │ ├── Continue.txt
│ │ │ │ ├── Tables.txt
│ │ │ │ ├── If.txt
│ │ │ │ ├── PrioritiesBitwise.txt
│ │ │ │ ├── Compound.txt
│ │ │ │ ├── OOP.txt
│ │ │ │ ├── ForOptimized.txt
│ │ │ │ ├── PrioritiesUnary.txt
│ │ │ │ └── Priorities.txt
│ │ └── test_module.lua
│ └── java
│ │ └── me
│ │ └── saharnooby
│ │ └── luajssyntax
│ │ ├── util
│ │ └── HashUtilTest.java
│ │ ├── ErrorTest.java
│ │ ├── OptimizationTest.java
│ │ ├── TestGenerator.java
│ │ └── ConverterTest.java
└── main
│ ├── java
│ └── me
│ │ └── saharnooby
│ │ └── luajssyntax
│ │ ├── util
│ │ ├── HashUtil.java
│ │ └── Printer.java
│ │ ├── Main.java
│ │ ├── exception
│ │ └── InvalidSyntaxException.java
│ │ ├── LuaJSToLua.java
│ │ └── LuaJSToLuaConverter.java
│ └── antlr4
│ └── me
│ └── saharnooby
│ └── luajssyntax
│ └── LuaJSSyntax.g4
├── LICENSE
├── README.md
├── pom.xml
└── COMPARISON.md
/src/test/resources/me/saharnooby/luajssyntax/Power.txt:
--------------------------------------------------------------------------------
1 | consume(32 ** 3)
2 | consume(3478 ** 0.243)
3 |
4 | ===
5 |
6 | consume(32 ^ 3)
7 | consume(3478 ^ 0.243)
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Literals.txt:
--------------------------------------------------------------------------------
1 | consume(nil)
2 | consume(true)
3 | consume(false)
4 |
5 | ===
6 |
7 | consume(nil)
8 | consume(true)
9 | consume(false)
--------------------------------------------------------------------------------
/src/test/resources/test_module.lua:
--------------------------------------------------------------------------------
1 | if test_module then
2 | return
3 | end
4 |
5 | test_module = {}
6 |
7 | function test_module.calculate(arg)
8 | return arg * 10
9 | end
10 |
11 | return test_module
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Parenthesis.txt:
--------------------------------------------------------------------------------
1 | let x = ((5 * 6) * 7 / 8)
2 | let y = 5 * 6 * 7 / 8
3 |
4 | consume(x == y)
5 |
6 | ===
7 |
8 | local x = ((5 * 6) * 7 / 8)
9 | local y = 5 * 6 * 7 / 8
10 |
11 | consume(x == y)
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/DoWhile.txt:
--------------------------------------------------------------------------------
1 | let x = 100
2 |
3 | do {
4 | consume(x)
5 | x--
6 | } while(x > 1)
7 |
8 | ===
9 |
10 | local x = 100
11 |
12 | repeat
13 | consume(x)
14 | x = x - 1
15 | until (not(x > 1))
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Increment.txt:
--------------------------------------------------------------------------------
1 | let x = 340
2 | consume(x)
3 | x++
4 | consume(x)
5 | x--
6 | consume(x)
7 |
8 | ===
9 |
10 | local x = 340
11 | consume(x)
12 | x = x + 1
13 | consume(x)
14 | x = x - 1
15 | consume(x)
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Throw.txt:
--------------------------------------------------------------------------------
1 |
2 | try {
3 |
4 | throw 'message'
5 |
6 | } catch (e) {
7 | consume('error!', e)
8 | }
9 |
10 | ===
11 |
12 | local r, e = pcall(function()
13 |
14 | error('message')
15 |
16 | end)
17 |
18 | if not r then
19 | consume('error!', e)
20 | end
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Math.txt:
--------------------------------------------------------------------------------
1 | consume(34 + 3489)
2 | consume(34.489 - 23879)
3 | consume(2478.34 * 2389.489)
4 | consume(2389.243 / 892.24)
5 | consume(4553.243 % 3443)
6 |
7 | ===
8 |
9 | consume(34 + 3489)
10 | consume(34.489 - 23879)
11 | consume(2478.34 * 2389.489)
12 | consume(2389.243 / 892.24)
13 | consume(4553.243 % 3443)
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Require.txt:
--------------------------------------------------------------------------------
1 | require("test_module")
2 |
3 | consume(test_module.calculate(123))
4 |
5 | let moduleInVar = require("test_module")
6 |
7 | consume(moduleInVar.calculate(456))
8 |
9 | ===
10 |
11 | require "test_module"
12 |
13 | consume(test_module.calculate(123))
14 |
15 | local moduleInVar = require "test_module"
16 |
17 | consume(moduleInVar.calculate(456))
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Break.txt:
--------------------------------------------------------------------------------
1 | let x = 1
2 |
3 | while (true) {
4 | x += 5
5 |
6 | if (x > 50) {
7 | break
8 | }
9 |
10 | consume(x)
11 | }
12 |
13 | consume(x)
14 |
15 | ===
16 |
17 | local x = 1
18 |
19 | while true do
20 | x = x + 5
21 |
22 | if x > 50 then
23 | break
24 | end
25 |
26 | consume(x)
27 | end
28 |
29 | consume(x)
30 |
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Logic.txt:
--------------------------------------------------------------------------------
1 | list = [true, false, nil, 0, 1, -1]
2 |
3 | for (x of list) {
4 | for (y of list) {
5 | consume(x && y)
6 | consume(x || y)
7 | }
8 | }
9 |
10 | ===
11 |
12 | list = {true, false, nil, 0, 1, -1}
13 |
14 | for ix, x in ipairs(list) do
15 | for iy, y in ipairs(list) do
16 | consume(x and y)
17 | consume(x or y)
18 | end
19 | end
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/ChainCalls.txt:
--------------------------------------------------------------------------------
1 | let x = {f: () => {g: () => 100}}
2 |
3 | consume(x.f().g())
4 | consume(x.f()['g']())
5 |
6 | x = {f: () => {g: () => {t: 'test'}}}
7 |
8 | consume(x.f()['g']().t)
9 |
10 | ===
11 |
12 | local x = {f = function() return {g = function() return 100 end} end}
13 |
14 | consume(x.f().g())
15 | consume(x.f()['g']())
16 |
17 | local x = {f = function() return {g = function() return {t = 'test'} end} end}
18 |
19 | consume(x.f()['g']().t)
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/ForOf.txt:
--------------------------------------------------------------------------------
1 | x = [33, 3454, 4545]
2 |
3 | consume(v, i)
4 |
5 | for (v of x) {
6 | consume(v)
7 | }
8 |
9 | consume(v, i)
10 |
11 | for (v, i of x) {
12 | consume(v, i)
13 | }
14 |
15 | consume(v, i)
16 |
17 | ===
18 |
19 | x = {33, 3454, 4545}
20 |
21 | consume(v, i)
22 |
23 | for _, v in ipairs(x) do
24 | consume(v)
25 | end
26 |
27 | consume(v, i)
28 |
29 | for i, v in ipairs(x) do
30 | consume(v, i)
31 | end
32 |
33 | consume(v, i)
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Concat.txt:
--------------------------------------------------------------------------------
1 | consume('abc' .. 'def')
2 | consume('abc' .. 1)
3 | consume('abc ' .. 1 .. ' def')
4 | consume('abc ' .. 1 .. ' def' .. [1, 2, 3])
5 | consume('abc ' .. 1 .. ' def' .. {x: 1, y: 2, z: 3})
6 |
7 | ===
8 |
9 | consume('abc' .. 'def')
10 | consume('abc' .. tostring(1))
11 | consume('abc ' .. tostring(1) .. ' def')
12 | consume('abc ' .. tostring(1) .. ' def' .. tostring({1, 2, 3}))
13 | consume('abc ' .. tostring(1) .. ' def' .. tostring({x = 1, y = 2, z = 3}))
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/ForIn.txt:
--------------------------------------------------------------------------------
1 | x = {a: 1, b: 2, c: 3}
2 |
3 | consume(k, v)
4 |
5 | for (k in pairs(x)) {
6 | consume(k)
7 | }
8 |
9 | consume(k, v)
10 |
11 | for (k, v in pairs(x)) {
12 | consume(k, v)
13 | }
14 |
15 | consume(k, v)
16 |
17 | ===
18 |
19 | x = {a = 1, b = 2, c = 3}
20 |
21 | consume(k, v)
22 |
23 | for k in pairs(x) do
24 | consume(k)
25 | end
26 |
27 | consume(k, v)
28 |
29 | for k, v in pairs(x) do
30 | consume(k, v)
31 | end
32 |
33 | consume(k, v)
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Label.txt:
--------------------------------------------------------------------------------
1 | let x = 1
2 |
3 | while (x < 100) {
4 | x += 5
5 |
6 | if (x >= 50) {
7 | consume(-1)
8 | goto label
9 | }
10 |
11 | consume(x)
12 | }
13 |
14 | label:
15 |
16 | consume(x)
17 |
18 | ===
19 |
20 | local x = 1
21 |
22 | while (x < 100) do
23 | x = x + 5
24 |
25 | if (x >= 50) then
26 | consume(-1)
27 | goto label
28 | end
29 |
30 | consume(x)
31 | end
32 |
33 | ::label::
34 |
35 | consume(x)
36 |
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Globals.txt:
--------------------------------------------------------------------------------
1 | x = 13
2 |
3 | consume(x)
4 |
5 | {
6 | y = 11
7 | consume(y)
8 | }
9 |
10 | consume(y)
11 |
12 | a, b = 44, 56
13 |
14 | consume(a, b)
15 |
16 | c, d = 6, 7, 8
17 |
18 | e, f, g = 1, 2
19 | consume(e, f, g)
20 |
21 | ===
22 |
23 | x = 13
24 |
25 | consume(x)
26 |
27 | do
28 | y = 11
29 | consume(y)
30 | end
31 |
32 | consume(y)
33 |
34 | a, b = 44, 56
35 |
36 | consume(a, b)
37 |
38 | c, d = 6, 7, 8
39 |
40 | e, f, g = 1, 2
41 | consume(e, f, g)
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Return.txt:
--------------------------------------------------------------------------------
1 | function f() {
2 | return
3 | }
4 |
5 | function g() {
6 | return 1
7 | }
8 |
9 | function h() {
10 | return 5, 7, 6
11 | }
12 |
13 | consume(f())
14 | consume(g())
15 |
16 | let x, y, z = h()
17 | consume(x, y, z)
18 |
19 | ===
20 |
21 | function f()
22 | return
23 | end
24 |
25 | function g()
26 | return 1
27 | end
28 |
29 | function h()
30 | return 5, 7, 6
31 | end
32 |
33 | consume(f())
34 | consume(g())
35 |
36 | local x, y, z = h()
37 | consume(x, y, z)
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Numbers.txt:
--------------------------------------------------------------------------------
1 | consume(1)
2 | consume(1.0)
3 | consume(1.3443)
4 | consume(1.23e3)
5 | consume(1.23e+3)
6 | consume(1.23e-3)
7 | consume(0xff)
8 | consume(0x34A8)
9 | consume(0x34A8.32)
10 | consume(0x34A8.32p2)
11 | consume(0x34A8.32p+2)
12 | consume(0x34A8.32p-2)
13 |
14 | ===
15 |
16 | consume(1)
17 | consume(1.0)
18 | consume(1.3443)
19 | consume(1.23e3)
20 | consume(1.23e+3)
21 | consume(1.23e-3)
22 | consume(0xff)
23 | consume(0x34A8)
24 | consume(0x34A8.32)
25 | consume(0x34A8.32p2)
26 | consume(0x34A8.32p+2)
27 | consume(0x34A8.32p-2)
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Unary.txt:
--------------------------------------------------------------------------------
1 | for (v of [-20, -1, 0, 1, 239, 34.389]) {
2 | consume(~v)
3 | consume(-v)
4 | }
5 |
6 | for (v of [true, false, nil]) {
7 | consume(!v)
8 | }
9 |
10 | for (v of [[], [1], [1, 2], {[1]: 'x'}]) {
11 | consume(#v)
12 | }
13 |
14 | ===
15 |
16 | for i, v in ipairs({-20, -1, 0, 1, 239, 34.389}) do
17 | consume(bit32.bnot(v))
18 | consume(-v)
19 | end
20 |
21 | for i, v in ipairs({true, false, nil}) do
22 | consume(not v)
23 | end
24 |
25 | for i, v in ipairs({{}, {1}, {1, 2}, {[1] = 'x'}}) do
26 | consume(#v)
27 | end
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Lists.txt:
--------------------------------------------------------------------------------
1 | let a = [1, 2, 3]
2 | let b = ['test', 4.55,]
3 | let c = []
4 | let d = [[b]]
5 |
6 | consume(a)
7 | consume(b)
8 | consume(b[1])
9 | consume(b[2])
10 | consume(b[3])
11 | consume(c)
12 | consume(c[1])
13 | consume(c[2])
14 | consume(d)
15 | consume(d[1])
16 | consume(d[1][1])
17 |
18 | ===
19 |
20 | local a = {1, 2, 3}
21 | local b = {'test', 4.55}
22 | local c = {}
23 | local d = {{b}}
24 |
25 | consume(a)
26 | consume(b)
27 | consume(b[1])
28 | consume(b[2])
29 | consume(b[3])
30 | consume(c)
31 | consume(c[1])
32 | consume(c[2])
33 | consume(d)
34 | consume(d[1])
35 | consume(d[1][1])
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Bitwise.txt:
--------------------------------------------------------------------------------
1 | list = [-100, -23.2323, -1, 0, 1, 443, 2389.34]
2 |
3 | for (x of list) {
4 | for (y of list) {
5 | consume(x & y)
6 | consume(x | y)
7 | consume(x ^ y)
8 | consume(x << y)
9 | consume(x >> y)
10 | }
11 | }
12 |
13 | ===
14 |
15 | list = {-100, -23.2323, -1, 0, 1, 443, 2389.34}
16 |
17 | for ix, x in ipairs(list) do
18 | for iy, y in ipairs(list) do
19 | consume(bit32.band(x, y))
20 | consume(bit32.bor(x, y))
21 | consume(bit32.bxor(x, y))
22 | consume(bit32.lshift(x, y))
23 | consume(bit32.rshift(x, y))
24 | end
25 | end
--------------------------------------------------------------------------------
/src/test/java/me/saharnooby/luajssyntax/util/HashUtilTest.java:
--------------------------------------------------------------------------------
1 | package me.saharnooby.luajssyntax.util;
2 |
3 | import org.junit.jupiter.api.Assertions;
4 | import org.junit.jupiter.api.Test;
5 |
6 | /**
7 | * @author saharNooby
8 | * @since 22:39 23.08.2019
9 | */
10 | class HashUtilTest {
11 |
12 | @Test
13 | void test() {
14 | Assertions.assertEquals("1BC29B36F623BA82AAF6724FD3B16718".toLowerCase(), HashUtil.md5("md5"));
15 | Assertions.assertEquals("D41D8CD98F00B204E9800998ECF8427E".toLowerCase(), HashUtil.md5(""));
16 | }
17 |
18 | @Test
19 | void testPad() {
20 | Assertions.assertEquals("00411460f7c92d2124a67ea0f4cb5f85", HashUtil.md5("363"));
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Comparison.txt:
--------------------------------------------------------------------------------
1 | list = [-100, -23.2323, -1, 0, 1, 443, 2389.34]
2 |
3 | for (x of list) {
4 | for (y of list) {
5 | consume(x > y)
6 | consume(x < y)
7 | consume(x >= y)
8 | consume(x <= y)
9 | consume(x == y)
10 | consume(x != y)
11 | }
12 | }
13 |
14 | ===
15 |
16 | list = {-100, -23.2323, -1, 0, 1, 443, 2389.34}
17 |
18 | for ix, x in ipairs(list) do
19 | for iy, y in ipairs(list) do
20 | consume(x > y)
21 | consume(x < y)
22 | consume(x >= y)
23 | consume(x <= y)
24 | consume(x == y)
25 | consume(x ~= y)
26 | end
27 | end
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/For.txt:
--------------------------------------------------------------------------------
1 | consume(x)
2 |
3 | for (x = 10; x < 100; x += 10) {
4 | consume(x)
5 | }
6 |
7 | consume(x)
8 |
9 | consume(i)
10 |
11 | for (let i = 0; i < 10; i++) {
12 | consume(i)
13 | }
14 |
15 | consume(i)
16 |
17 | for (let i = 0; ; i++) {
18 | if (i >= 10) {
19 | break
20 | }
21 |
22 | consume(i)
23 | }
24 |
25 | ===
26 |
27 | consume(x)
28 |
29 | x = 10
30 | while x < 100 do
31 | consume(x)
32 | x = x + 10
33 | end
34 |
35 | consume(x)
36 |
37 | consume(i)
38 |
39 | for i = 0, 9, 1 do
40 | consume(i)
41 | end
42 |
43 | consume(i)
44 |
45 | for i = 0, 9, 1 do
46 | consume(i)
47 | end
--------------------------------------------------------------------------------
/src/test/java/me/saharnooby/luajssyntax/ErrorTest.java:
--------------------------------------------------------------------------------
1 | package me.saharnooby.luajssyntax;
2 |
3 | import me.saharnooby.luajssyntax.exception.InvalidSyntaxException;
4 | import org.junit.jupiter.api.Assertions;
5 | import org.junit.jupiter.api.Test;
6 |
7 | /**
8 | * @author saharNooby
9 | * @since 14:17 23.08.2019
10 | */
11 | class ErrorTest {
12 |
13 | @Test
14 | void testInvalidCharacters() {
15 | Assertions.assertThrows(InvalidSyntaxException.class, () -> LuaJSToLua.convert("test() \0"));
16 | }
17 |
18 | @Test
19 | void testSyntaxError() {
20 | Assertions.assertThrows(InvalidSyntaxException.class, () -> LuaJSToLua.convert("let x = 1 # 2"));
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/ArrowFunctionLiteral.txt:
--------------------------------------------------------------------------------
1 | f = () => {return 3487943}
2 |
3 | g = (x) => x + 10
4 |
5 | h = (x, y) => {
6 | consume(x)
7 | consume(y)
8 | }
9 |
10 | consume(f())
11 | consume(g(34.34))
12 | h(23, 67)
13 |
14 | single_arg = m => m * 347843
15 |
16 | consume(single_arg(2324))
17 |
18 | ===
19 |
20 | function f()
21 | return 3487943
22 | end
23 |
24 | function g(x)
25 | return x + 10
26 | end
27 |
28 | function h(x, y)
29 | consume(x)
30 | consume(y)
31 | end
32 |
33 | consume(f())
34 | consume(g(34.34))
35 | h(23, 67)
36 |
37 | function single_arg(m)
38 | return m * 347843
39 | end
40 |
41 | consume(single_arg(2324))
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Locals.txt:
--------------------------------------------------------------------------------
1 | let x = 13
2 |
3 | consume(x)
4 |
5 | let y = 23
6 |
7 | {
8 | let y = 11
9 | consume(y)
10 | y = 12
11 | consume(y)
12 | }
13 |
14 | consume(y)
15 |
16 | let a, b = 44, 56
17 |
18 | consume(a, b)
19 |
20 | let c, d = 6, 7, 8
21 |
22 | let e, f, g = 1, 2
23 | consume(e, f, g)
24 |
25 | ===
26 |
27 | local x = 13
28 |
29 | consume(x)
30 |
31 | local y = 23
32 |
33 | do
34 | local y = 11
35 | consume(y)
36 | y = 12
37 | consume(y)
38 | end
39 |
40 | consume(y)
41 |
42 | local a, b = 44, 56
43 |
44 | consume(a, b)
45 |
46 | local c, d = 6, 7, 8
47 |
48 | local e, f, g = 1, 2
49 | consume(e, f, g)
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/TryCatch.txt:
--------------------------------------------------------------------------------
1 | try {
2 |
3 | try {
4 |
5 | let a = {}
6 | let c = a.b
7 |
8 | } catch (eNested) {
9 | consume('nested error!')
10 | }
11 |
12 | let x = {}
13 | x.y()
14 |
15 | } catch (e) {
16 | consume('error!')
17 | }
18 |
19 | ===
20 |
21 | local r, e = pcall(function()
22 |
23 | local rNested, eNested = pcall(function()
24 |
25 | local a = {}
26 | local c = a.b
27 |
28 | end)
29 |
30 | if not rNested then
31 | consume('nested error!')
32 | end
33 |
34 | local x = {}
35 | x.y()
36 |
37 | end)
38 |
39 | if not r then
40 | consume('error!')
41 | end
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/FunctionLiteral.txt:
--------------------------------------------------------------------------------
1 | function f() {
2 | return 3487943
3 | }
4 |
5 | function g(x) {
6 | return x + 10
7 | }
8 |
9 | function h(x, y) {
10 | consume(x)
11 | consume(y)
12 | }
13 |
14 | consume(f())
15 | consume(g(34.34))
16 | h(23, 67)
17 |
18 | let loc = function(x) {
19 | return x * 28923
20 | }
21 |
22 | consume(loc(23))
23 |
24 | ===
25 |
26 | function f()
27 | return 3487943
28 | end
29 |
30 | function g(x)
31 | return x + 10
32 | end
33 |
34 | function h(x, y)
35 | consume(x)
36 | consume(y)
37 | end
38 |
39 | consume(f())
40 | consume(g(34.34))
41 | h(23, 67)
42 |
43 | local function loc(x)
44 | return x * 28923
45 | end
46 |
47 | consume(loc(23))
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Strings.txt:
--------------------------------------------------------------------------------
1 | consume("abc")
2 | consume("'")
3 | consume("юникод")
4 | consume("escapes 1\a\b\f\n\r\t\v\z\"\\ end")
5 | consume("\x01\xFF")
6 | consume("\u042f")
7 | consume("\0\123\255")
8 |
9 | consume('abc')
10 | consume('"')
11 | consume('юникод')
12 | consume('escapes 1\a\b\f\n\r\t\v\z\'\\ end')
13 | consume('\x01\xFF')
14 | consume('\u042f')
15 | consume('\0\123\255')
16 |
17 | ===
18 |
19 | consume("abc")
20 | consume("'")
21 | consume("юникод")
22 | consume("escapes 1\a\b\f\n\r\t\v\z\"\\ end")
23 | consume("\x01\xFF")
24 | consume("Я")
25 | consume("\0\123\255")
26 |
27 | consume('abc')
28 | consume('"')
29 | consume('юникод')
30 | consume('escapes 1\a\b\f\n\r\t\v\z\'\\ end')
31 | consume('\x01\xFF')
32 | consume('Я')
33 | consume('\0\123\255')
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Ternary.txt:
--------------------------------------------------------------------------------
1 | consume(1 > 2 ? 'a' : 'b')
2 | consume(1 < 2 ? 'a' : 'b')
3 |
4 | consume(1 > 2 ? 'a' : 2 > 3 ? 'b' : 'c')
5 | consume(1 < 2 ? 'a' : 2 > 3 ? 'b' : 'c')
6 | consume(1 > 2 ? 'a' : 2 < 3 ? 'b' : 'c')
7 | consume(1 < 2 ? 'a' : 2 < 3 ? 'b' : 'c')
8 |
9 | // Edge case
10 | consume(2 > 1 ? false : true)
11 | consume(2 > 1 ? nil : {})
12 |
13 | ===
14 |
15 | consume(1 > 2 and 'a' or 'b')
16 | consume(1 < 2 and 'a' or 'b')
17 |
18 | consume(1 > 2 and 'a' or (2 > 3 and 'b' or 'c'))
19 | consume(1 < 2 and 'a' or (2 > 3 and 'b' or 'c'))
20 | consume(1 > 2 and 'a' or (2 < 3 and 'b' or 'c'))
21 | consume(1 < 2 and 'a' or (2 < 3 and 'b' or 'c'))
22 |
23 | -- Edge case
24 | consume(true)
25 | consume({})
26 | -- consume(2 > 1 and false or true)
27 | -- consume(2 > 1 and nil or {})
--------------------------------------------------------------------------------
/src/main/java/me/saharnooby/luajssyntax/util/HashUtil.java:
--------------------------------------------------------------------------------
1 | package me.saharnooby.luajssyntax.util;
2 |
3 | import lombok.NonNull;
4 |
5 | import java.math.BigInteger;
6 | import java.nio.charset.StandardCharsets;
7 | import java.security.MessageDigest;
8 | import java.security.NoSuchAlgorithmException;
9 |
10 | /**
11 | * @author saharNooby
12 | * @since 22:14 23.08.2019
13 | */
14 | public final class HashUtil {
15 |
16 | public static String md5(@NonNull String s) {
17 | try {
18 | MessageDigest digest = MessageDigest.getInstance("MD5");
19 | digest.update(s.getBytes(StandardCharsets.UTF_8));
20 | return hashToString(digest.digest());
21 | } catch (NoSuchAlgorithmException e) {
22 | throw new RuntimeException(e);
23 | }
24 | }
25 |
26 | private static String hashToString(byte[] hash) {
27 | StringBuilder builder = new StringBuilder(new BigInteger(1, hash).toString(16));
28 |
29 | while (builder.length() < 32) {
30 | builder.insert(0, '0');
31 | }
32 |
33 | return builder.toString();
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Continue.txt:
--------------------------------------------------------------------------------
1 | for (v of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) {
2 |
3 | consume('loop begin')
4 |
5 |
6 | if (v % 2 != 0) {
7 | continue
8 | }
9 |
10 | for (let i = 0; i <= v; i++) {
11 |
12 | consume('nested begin')
13 |
14 | if (i % 2 == 0) {
15 | continue
16 | }
17 |
18 | consume(i)
19 |
20 | consume('nested end')
21 | }
22 |
23 | consume('loop end')
24 | }
25 |
26 | ===
27 |
28 | for i, v in ipairs({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) do
29 |
30 | consume('loop begin')
31 |
32 |
33 | if (v % 2 ~= 0) then
34 | goto end_1
35 | end
36 |
37 | local i = 0;
38 | while (i <= v) do
39 | consume('nested begin')
40 |
41 | if (i % 2 == 0) then
42 | goto end_2
43 | end
44 |
45 | consume(i)
46 |
47 | consume('nested end')
48 |
49 | ::end_2::
50 |
51 | i = i + 1;
52 | end
53 |
54 | consume('loop end')
55 |
56 | ::end_1::
57 | end
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Tables.txt:
--------------------------------------------------------------------------------
1 | let a = {}
2 | let b = {key: 2389.3489}
3 | let c = {x: 2389, y: 'test', z: 23,}
4 | let d = {[1 + 4.43]: 'value'}
5 | let e = {nested: d}
6 | let f = {moreNested: e}
7 |
8 | consume(a)
9 | consume(b)
10 | consume(b.key)
11 | consume(c)
12 | consume(c.x)
13 | consume(c.y)
14 | consume(c.z)
15 | consume(d)
16 | consume(d[1 + 4.43])
17 | consume(e)
18 | consume(e.nested)
19 | consume(e.nested[1 + 4.43])
20 | consume(f)
21 | consume(f.moreNested)
22 | consume(f.moreNested.nested)
23 | consume(f.moreNested.nested[1 + 4.43])
24 |
25 | ===
26 |
27 | local a = {}
28 | local b = {key = 2389.3489}
29 | local c = {x = 2389, y = 'test', z = 23}
30 | local d = {[1 + 4.43] = 'value'}
31 | local e = {nested = d}
32 | local f = {moreNested = e}
33 |
34 | consume(a)
35 | consume(b)
36 | consume(b.key)
37 | consume(c)
38 | consume(c.x)
39 | consume(c.y)
40 | consume(c.z)
41 | consume(d)
42 | consume(d[1 + 4.43])
43 | consume(e)
44 | consume(e.nested)
45 | consume(e.nested[1 + 4.43])
46 | consume(f)
47 | consume(f.moreNested)
48 | consume(f.moreNested.nested)
49 | consume(f.moreNested.nested[1 + 4.43])
--------------------------------------------------------------------------------
/src/main/java/me/saharnooby/luajssyntax/util/Printer.java:
--------------------------------------------------------------------------------
1 | package me.saharnooby.luajssyntax.util;
2 |
3 | import lombok.NonNull;
4 | import lombok.Setter;
5 |
6 | import java.io.IOException;
7 | import java.io.UncheckedIOException;
8 |
9 | /**
10 | * @author saharNooby
11 | * @since 19:01 21.08.2019
12 | */
13 | public final class Printer {
14 |
15 | private final Appendable destination;
16 |
17 | private int line = 1;
18 | @Setter
19 | private int expectedLine;
20 |
21 | public Printer(@NonNull Appendable destination) {
22 | this.destination = destination;
23 | }
24 |
25 | public void print(String s) {
26 | ensureCorrectLine();
27 | append(s);
28 | }
29 |
30 | public void println(String s) {
31 | if (!s.isEmpty()) {
32 | print(s);
33 | }
34 |
35 | append("\n");
36 |
37 | this.line++;
38 | }
39 |
40 | private void ensureCorrectLine() {
41 | while (this.expectedLine > this.line) {
42 | println("");
43 | }
44 | }
45 |
46 | private void append(String s) {
47 | try {
48 | this.destination.append(s);
49 | } catch (IOException e) {
50 | throw new UncheckedIOException(e);
51 | }
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 saharNooby (https://github.com/saharNooby)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/main/java/me/saharnooby/luajssyntax/Main.java:
--------------------------------------------------------------------------------
1 | package me.saharnooby.luajssyntax;
2 |
3 | import lombok.NonNull;
4 |
5 | import java.io.*;
6 |
7 | /**
8 | * @author saharNooby
9 | * @since 16:29 24.03.2020
10 | */
11 | public final class Main {
12 |
13 | public static void main(String[] args) throws IOException {
14 | StringBuilder src = new StringBuilder();
15 |
16 | try (Reader reader = new InputStreamReader(new BufferedInputStream(args.length > 0 ? new FileInputStream(new File(args[0])) : System.in))) {
17 | readAllChars(reader, src);
18 | }
19 |
20 | StringBuilder dest = new StringBuilder();
21 |
22 | LuaJSToLua.convert(src.toString(), dest);
23 |
24 | if (args.length > 1) {
25 | try (Writer writer = new OutputStreamWriter(new FileOutputStream(new File(args[1])))) {
26 | writer.write(dest.toString());
27 | }
28 | } else {
29 | System.out.println(dest);
30 | }
31 | }
32 |
33 | private static void readAllChars(@NonNull Reader reader, @NonNull StringBuilder out) throws IOException {
34 | char[] buf = new char[8192];
35 | int read;
36 | while ((read = reader.read(buf)) != -1) {
37 | out.append(buf, 0, read);
38 | }
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/If.txt:
--------------------------------------------------------------------------------
1 | let x = 30
2 | let y = 20
3 |
4 | if (x > y) {
5 | consume(1)
6 | }
7 |
8 | if (x > y)
9 | consume(1)
10 |
11 | if (x < y) {
12 | consume(1)
13 | } else {
14 | consume(3)
15 | }
16 |
17 | if (x < y)
18 | consume(1)
19 | else
20 | consume(3)
21 |
22 | let z = 1
23 | while (z < 100) {
24 | if (x < 10) {
25 | consume(4)
26 | } else if (z < 50) {
27 | consume(5)
28 | } else if (z < 30) {
29 | consume(6)
30 | } else {
31 | consume(7)
32 | }
33 |
34 | z++
35 | }
36 |
37 | ===
38 |
39 | local x = 30
40 | local y = 20
41 |
42 | if x > y then
43 | consume(1)
44 | end
45 |
46 | if x > y then
47 | consume(1) end
48 |
49 | if x < y then
50 | consume(1)
51 | else
52 | consume(3)
53 | end
54 |
55 | if (x < y) then
56 | consume(1)
57 | else
58 | consume(3) end
59 |
60 | local z = 1
61 |
62 | while (z < 100) do
63 | if (x < 10) then
64 | consume(4)
65 | elseif (z < 50) then
66 | consume(5)
67 | elseif (z < 30) then
68 | consume(6)
69 | else
70 | consume(7)
71 | end
72 |
73 | z = z + 1
74 | end
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/PrioritiesBitwise.txt:
--------------------------------------------------------------------------------
1 | consume(127 & 31 | 16)
2 | consume(16 | 127 & 31)
3 |
4 | consume(127 & 31 ^ 16)
5 | consume(16 ^ 127 & 31)
6 |
7 | consume(8 << 1 & 16)
8 | consume(8 << 1 | 8)
9 |
10 | consume(8 << 1 >> 1)
11 | consume(8 >> 1 << 1)
12 |
13 | consume(1 << 3 > 1 << 2)
14 | consume(1 << 3 < 1 << 2)
15 | consume(1 << 2 == 1 << 2)
16 |
17 | consume(1 ^ 1 && 1 << 2)
18 | consume(1 | 1 && 1 << 2)
19 |
20 | consume(1 << 2 + 2)
21 | consume(2 + 2 | 1)
22 |
23 | consume('test ' .. 1 << 3)
24 | consume(1 << 3 .. ' test')
25 |
26 | ===
27 |
28 | consume(bit32.bor(bit32.band(127, 31), 16))
29 | consume(bit32.bor(bit32.band(127, 31), 16))
30 |
31 | consume(bit32.bxor(bit32.band(127, 31), 16))
32 | consume(bit32.bxor(bit32.band(127, 31), 16))
33 |
34 | consume(bit32.band(bit32.lshift(8, 1), 16))
35 | consume(bit32.bor(bit32.lshift(8, 1), 8))
36 |
37 | consume(8)
38 | consume(8)
39 |
40 | consume(true)
41 | consume(false)
42 | consume(true)
43 |
44 | consume(bit32.bxor(1, 1) and bit32.lshift(1, 2));
45 | consume(bit32.bor(1, 1) and bit32.lshift(1, 2));
46 |
47 | consume(bit32.lshift(1, 2 + 2))
48 | consume(bit32.bor(2 + 2, 1))
49 |
50 | consume('test 8')
51 | consume('8 test')
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Compound.txt:
--------------------------------------------------------------------------------
1 | let x = 2389
2 | x += 278
3 | consume(x)
4 |
5 | x = 2389
6 | x -= 278
7 | consume(x)
8 |
9 | x = 2389
10 | x *= 278
11 | consume(x)
12 |
13 | x = 2389
14 | x /= 278
15 | consume(x)
16 |
17 | x = 2389
18 | x %= 278
19 | consume(x)
20 |
21 | x = 2389
22 | x &= 278
23 | consume(x)
24 |
25 | x = 2389
26 | x |= 278
27 | consume(x)
28 |
29 | x = 2389
30 | x ^= 278
31 | consume(x)
32 |
33 | x = 2389
34 | x >>= 3
35 | consume(x)
36 |
37 | x = 2389
38 | x <<= 3
39 | consume(x)
40 |
41 | let y = 'abc'
42 | y ..= '123'
43 | consume(y)
44 |
45 | x = 23
46 | x **= 5
47 | consume(x)
48 |
49 | ===
50 |
51 | local x = 2389
52 | x = x + 278
53 | consume(x)
54 |
55 | x = 2389
56 | x = x - 278
57 | consume(x)
58 |
59 | x = 2389
60 | x = x * 278
61 | consume(x)
62 |
63 | x = 2389
64 | x = x / 278
65 | consume(x)
66 |
67 | x = 2389
68 | x = x % 278
69 | consume(x)
70 |
71 | x = 2389
72 | x = bit32.band(x, 278)
73 | consume(x)
74 |
75 | x = 2389
76 | x = bit32.bor(x, 278)
77 | consume(x)
78 |
79 | x = 2389
80 | x = bit32.bxor(x, 278)
81 | consume(x)
82 |
83 | x = 2389
84 | x = bit32.rshift(x, 3)
85 | consume(x)
86 |
87 | x = 2389
88 | x = bit32.lshift(x, 3)
89 | consume(x)
90 |
91 | local y = 'abc'
92 | y = y..'123'
93 | consume(y)
94 |
95 | x = 23
96 | x = x ^ 5
97 | consume(x)
--------------------------------------------------------------------------------
/src/main/java/me/saharnooby/luajssyntax/exception/InvalidSyntaxException.java:
--------------------------------------------------------------------------------
1 | package me.saharnooby.luajssyntax.exception;
2 |
3 | import lombok.Getter;
4 | import lombok.NonNull;
5 | import org.antlr.v4.runtime.RecognitionException;
6 |
7 | /**
8 | * Thrown when LuaJS syntax is invalid.
9 | * It can have a {@link RecognitionException} as a cause, or null.
10 | * @author saharNooby
11 | * @since 14:22 23.08.2019
12 | */
13 | @Getter
14 | public final class InvalidSyntaxException extends RuntimeException {
15 |
16 | private static final long serialVersionUID = 3565251758944402880L;
17 |
18 | /**
19 | * Line number with offending construction or character.
20 | * Line numbers start from 1.
21 | */
22 | private final int line;
23 | /**
24 | * The position of the first char of the offending construction.
25 | * Char positions start from 0.
26 | */
27 | private final int charPosition;
28 | /**
29 | * Some message from ANTLR, specifying what's wrong.
30 | */
31 | private final String originalMessage;
32 |
33 | public InvalidSyntaxException(int line, int charPosition, @NonNull String message, RecognitionException cause) {
34 | super("line " + line + ":" + charPosition + " " + message, cause);
35 | this.originalMessage = message;
36 | this.line = line;
37 | this.charPosition = charPosition;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/test/java/me/saharnooby/luajssyntax/OptimizationTest.java:
--------------------------------------------------------------------------------
1 | package me.saharnooby.luajssyntax;
2 |
3 | import org.junit.jupiter.api.Assertions;
4 | import org.junit.jupiter.api.Test;
5 |
6 | /**
7 | * @author saharNooby
8 | * @since 20:57 21.08.2019
9 | */
10 | class OptimizationTest {
11 |
12 | @Test
13 | void testForwardLoop() {
14 | String code = "for (let i = 0; i <= 10; i++) {\n" +
15 | " consume(i)\n" +
16 | "}";
17 |
18 | String converted = LuaJSToLua.convert(code);
19 |
20 | Assertions.assertFalse(converted.contains("while"));
21 | }
22 |
23 | @Test
24 | void testReversedLoop() {
25 | String code = "for (let i = 10; i >= 0; i--) {\n" +
26 | " consume(i)\n" +
27 | "}";
28 |
29 | String converted = LuaJSToLua.convert(code);
30 |
31 | Assertions.assertFalse(converted.contains("while"));
32 | }
33 |
34 | @Test
35 | void testForwardLoopCustomStep() {
36 | String code = "for (let i = 0; i <= 10; i += 2) {\n" +
37 | " consume(i)\n" +
38 | "}";
39 |
40 | String converted = LuaJSToLua.convert(code);
41 |
42 | Assertions.assertFalse(converted.contains("while"));
43 | }
44 |
45 | @Test
46 | void testReversedLoopCustomStep() {
47 | String code = "for (let i = 10; i >= 0; i -= 2) {\n" +
48 | " consume(i)\n" +
49 | "}";
50 |
51 | String converted = LuaJSToLua.convert(code);
52 |
53 | Assertions.assertFalse(converted.contains("while"));
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/OOP.txt:
--------------------------------------------------------------------------------
1 | Dog = {}
2 |
3 | function Dog::new() {
4 | newObj = {sound: 'woof'}
5 | self.__index = self
6 | return setmetatable(newObj, self)
7 | }
8 |
9 | function Dog::makeSound() {
10 | return 'I say ' .. self.sound
11 | }
12 |
13 | mrDog = Dog::new()
14 | consume(mrDog::makeSound())
15 |
16 | //--------------------------------------------------
17 |
18 | LoudDog = Dog::new()
19 |
20 | function LoudDog::makeSound() {
21 | s = self.sound .. ' '
22 | return s .. s .. s
23 | }
24 |
25 | seymour = LoudDog::new()
26 | consume(seymour::makeSound())
27 |
28 | function LoudDog::new() {
29 | newObj = {}
30 | self.__index = self
31 | return setmetatable(newObj, self)
32 | }
33 |
34 | ===
35 |
36 | Dog = {}
37 |
38 | function Dog:new()
39 | newObj = {sound = 'woof'}
40 | self.__index = self
41 | return setmetatable(newObj, self)
42 | end
43 |
44 | function Dog:makeSound()
45 | return 'I say ' .. self.sound
46 | end
47 |
48 | mrDog = Dog:new()
49 | consume(mrDog:makeSound())
50 |
51 | ----------------------------------------------------
52 |
53 | LoudDog = Dog:new()
54 |
55 | function LoudDog:makeSound()
56 | s = self.sound .. ' '
57 | return s .. s .. s
58 | end
59 |
60 | seymour = LoudDog:new()
61 | consume(seymour:makeSound())
62 |
63 | function LoudDog:new()
64 | newObj = {}
65 | -- set up newObj
66 | self.__index = self
67 | return setmetatable(newObj, self)
68 | end
69 |
70 |
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/ForOptimized.txt:
--------------------------------------------------------------------------------
1 | for (let i = 0; i < 10; i++) {
2 | consume(i)
3 | }
4 |
5 | for (let i = 10; i > 0; i--) {
6 | consume(i)
7 | }
8 |
9 | for (let i = 0; i <= 10; i++) {
10 | consume(i)
11 | }
12 |
13 | for (let i = 10; i >= 0; i--) {
14 | consume(i)
15 | }
16 |
17 | for (let i = 0; i < 10; i += 2) {
18 | consume(i)
19 | }
20 |
21 | for (let i = 10; i > 0; i -= 2) {
22 | consume(i)
23 | }
24 |
25 | for (let i = 0; i <= 10; i += 2) {
26 | consume(i)
27 | }
28 |
29 | for (let i = 10; i >= 0; i -= 2) {
30 | consume(i)
31 | }
32 |
33 | for (let i = 0.23839; i < 5.32892; i += 0.032234) {
34 | consume(i)
35 | }
36 |
37 | consume('check')
38 |
39 | for (let i = 0.23839; i <= 5.32892; i += 0.032234) {
40 | consume(i)
41 | }
42 |
43 | ===
44 |
45 | for i = 0, 9, 1 do
46 | consume(i)
47 | end
48 |
49 | for i = 10, 1, -1 do
50 | consume(i)
51 | end
52 |
53 | for i = 0, 10, 1 do
54 | consume(i)
55 | end
56 |
57 | for i = 10, 0, -1 do
58 | consume(i)
59 | end
60 |
61 | for i = 0, 9, 2 do
62 | consume(i)
63 | end
64 |
65 | for i = 10, 1, -2 do
66 | consume(i)
67 | end
68 |
69 | for i = 0, 10, 2 do
70 | consume(i)
71 | end
72 |
73 | for i = 10, 0, -2 do
74 | consume(i)
75 | end
76 |
77 | for i = 0.23839, 5.32891, 0.032234 do
78 | consume(i)
79 | end
80 |
81 | consume('check')
82 |
83 | for i = 0.23839, 5.32892, 0.032234 do
84 | consume(i)
85 | end
--------------------------------------------------------------------------------
/src/main/java/me/saharnooby/luajssyntax/LuaJSToLua.java:
--------------------------------------------------------------------------------
1 | package me.saharnooby.luajssyntax;
2 |
3 | import lombok.NonNull;
4 | import me.saharnooby.luajssyntax.exception.InvalidSyntaxException;
5 | import me.saharnooby.luajssyntax.util.HashUtil;
6 | import me.saharnooby.luajssyntax.util.Printer;
7 | import org.antlr.v4.runtime.*;
8 |
9 | /**
10 | * This class provides a method to convert LuaJS source code to Lua code.
11 | * @author saharNooby
12 | * @since 19:06 21.08.2019
13 | */
14 | public final class LuaJSToLua {
15 |
16 | private static final BaseErrorListener THROWING_LISTENER = new BaseErrorListener() {
17 |
18 | @Override
19 | public void syntaxError(Recognizer, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
20 | throw new InvalidSyntaxException(line, charPositionInLine, msg, e);
21 | }
22 |
23 | };
24 |
25 | /**
26 | * Converts LuaJS source code to Lua, preserving line numbers.
27 | * @param source LuaJS source code, must be not null.
28 | * @return Lua source code, will be not null.
29 | * @throws InvalidSyntaxException When provided source is invalid.
30 | */
31 | public static String convert(@NonNull String source) {
32 | StringBuilder sb = new StringBuilder();
33 | convert(source, sb);
34 | return sb.toString();
35 | }
36 |
37 | /**
38 | * Converts LuaJS source code to Lua, preserving line numbers. Resulting code will be appended to the specified Appendable.
39 | * @param source LuaJS source code, must be not null.
40 | * @param out Destination for writing the result code, must be not null.
41 | * @throws InvalidSyntaxException When provided source is invalid.
42 | * @throws java.io.UncheckedIOException When out throws an IOException.
43 | */
44 | public static void convert(@NonNull String source, @NonNull Appendable out) {
45 | convert(CharStreams.fromString(source), HashUtil.md5(source), out);
46 | }
47 |
48 | private static void convert(@NonNull CharStream in, @NonNull String sourceHash, @NonNull Appendable out) {
49 | LuaJSSyntaxLexer lexer = new LuaJSSyntaxLexer(in);
50 |
51 | lexer.removeErrorListeners();
52 | lexer.addErrorListener(THROWING_LISTENER);
53 |
54 | CommonTokenStream tokens = new CommonTokenStream(lexer);
55 |
56 | LuaJSSyntaxParser parser = new LuaJSSyntaxParser(tokens);
57 |
58 | parser.removeErrorListeners();
59 | parser.addErrorListener(THROWING_LISTENER);
60 |
61 | LuaJSSyntaxParser.ProgramContext program = parser.program();
62 |
63 | new LuaJSToLuaConverter(new Printer(out), sourceHash).print(program);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/PrioritiesUnary.txt:
--------------------------------------------------------------------------------
1 | consume(- 82.50 + 76.89)
2 | consume(95.57 + - 34.37)
3 | consume(~ 85.53 + 39.26)
4 | consume(72.65 + ~ 37.49)
5 |
6 | consume(- 20.85 - 54.16)
7 | consume(22.37 - - 36.50)
8 | consume(~ 78.53 - 8.92)
9 | consume(21.44 - ~ 61.72)
10 |
11 | consume(- 30.33 * 52.75)
12 | consume(53.34 * - 35.86)
13 | consume(~ 48.42 * 43.50)
14 | consume(14.36 * ~ 43.50)
15 |
16 | consume(- 68.90 / 6.14)
17 | consume(50.54 / - 33.21)
18 | consume(~ 72.98 / 51.17)
19 | consume(39.43 / ~ 29.0)
20 |
21 | consume(- 97.98 % 18.27)
22 | consume(20.90 % - 88.49)
23 | consume(~ 14.75 % 26.93)
24 | consume(65.76 % ~ 87.50)
25 |
26 | consume(- 45.5 < 95.89)
27 | consume(89.83 < - 72.26)
28 | consume(~ 31.84 < 55.24)
29 | consume(1.56 < ~ 53.5)
30 |
31 | consume(- 37.99 > 71.89)
32 | consume(20.10 > - 58.60)
33 | consume(~ 27.27 > 0.36)
34 | consume(82.44 > ~ 20.50)
35 |
36 | consume(- 26.4 <= 76.88)
37 | consume(15.43 <= - 94.52)
38 | consume(~ 19.21 <= 32.47)
39 | consume(55.81 <= ~ 77.76)
40 |
41 | consume(- 35.58 >= 18.86)
42 | consume(36.33 >= - 41.21)
43 | consume(~ 95.36 >= 49.2)
44 | consume(13.89 >= ~ 68.41)
45 |
46 | consume(- 79.81 == 6.32)
47 | consume(19.3 == - 7.74)
48 | consume(~ 32.99 == 87.17)
49 | consume(80.51 == ~ 49.9)
50 |
51 | consume(- 36.13 != 51.49)
52 | consume(21.61 != - 26.37)
53 | consume(~ 2.37 != 74.11)
54 | consume(53.91 != ~ 41.69)
55 |
56 | consume(! 24.7 && 92.11)
57 | consume(14.2 && ! 59.53)
58 | consume(- 19.24 && 67.47)
59 | consume(64.69 && - 1.4)
60 | consume(~ 79.79 && 59.47)
61 | consume(99.39 && ~ 14.88)
62 |
63 | consume(! 49.91 || 87.76)
64 | consume(7.17 || ! 84.76)
65 | consume(- 86.97 || 30.95)
66 | consume(67.57 || - 70.37)
67 | consume(~ 34.22 || 29.35)
68 | consume(17.77 || ~ 33.29)
69 |
70 | consume(- 80.31 ** 61.22)
71 | consume(45.41 ** - 36.58)
72 | consume(~ 78.76 ** 31.60)
73 | consume(87.72 ** ~ 61.91)
74 |
75 |
76 |
77 | ===
78 |
79 |
80 | consume(- 82.50 + 76.89)
81 | consume(95.57 + - 34.37)
82 | consume(bit32.bnot( 85.53) + 39.26)
83 | consume(72.65 + bit32.bnot( 37.49))
84 |
85 | consume(- 20.85 - 54.16)
86 | consume(22.37 - - 36.50)
87 | consume(bit32.bnot( 78.53) - 8.92)
88 | consume(21.44 - bit32.bnot( 61.72))
89 |
90 | consume(- 30.33 * 52.75)
91 | consume(53.34 * - 35.86)
92 | consume(bit32.bnot( 48.42) * 43.50)
93 | consume(14.36 * bit32.bnot( 43.50))
94 |
95 | consume(- 68.90 / 6.14)
96 | consume(50.54 / - 33.21)
97 | consume(bit32.bnot( 72.98) / 51.17)
98 | consume(39.43 / bit32.bnot( 29.0))
99 |
100 | consume(- 97.98 % 18.27)
101 | consume(20.90 % - 88.49)
102 | consume(bit32.bnot( 14.75) % 26.93)
103 | consume(65.76 % bit32.bnot( 87.50))
104 |
105 | consume(- 45.5 < 95.89)
106 | consume(89.83 < - 72.26)
107 | consume(bit32.bnot( 31.84) < 55.24)
108 | consume(1.56 < bit32.bnot( 53.5))
109 |
110 | consume(- 37.99 > 71.89)
111 | consume(20.10 > - 58.60)
112 | consume(bit32.bnot( 27.27) > 0.36)
113 | consume(82.44 > bit32.bnot( 20.50))
114 |
115 | consume(- 26.4 <= 76.88)
116 | consume(15.43 <= - 94.52)
117 | consume(bit32.bnot( 19.21) <= 32.47)
118 | consume(55.81 <= bit32.bnot( 77.76))
119 |
120 | consume(- 35.58 >= 18.86)
121 | consume(36.33 >= - 41.21)
122 | consume(bit32.bnot( 95.36) >= 49.2)
123 | consume(13.89 >= bit32.bnot( 68.41))
124 |
125 | consume(- 79.81 == 6.32)
126 | consume(19.3 == - 7.74)
127 | consume(bit32.bnot( 32.99) == 87.17)
128 | consume(80.51 == bit32.bnot( 49.9))
129 |
130 | consume(- 36.13 ~= 51.49)
131 | consume(21.61 ~= - 26.37)
132 | consume(bit32.bnot( 2.37) ~= 74.11)
133 | consume(53.91 ~= bit32.bnot( 41.69))
134 |
135 | consume(not 24.7 and 92.11)
136 | consume(14.2 and not 59.53)
137 | consume(- 19.24 and 67.47)
138 | consume(64.69 and - 1.4)
139 | consume(bit32.bnot( 79.79) and 59.47)
140 | consume(99.39 and bit32.bnot( 14.88))
141 |
142 | consume(not 49.91 or 87.76)
143 | consume(7.17 or not 84.76)
144 | consume(- 86.97 or 30.95)
145 | consume(67.57 or - 70.37)
146 | consume(bit32.bnot( 34.22) or 29.35)
147 | consume(17.77 or bit32.bnot( 33.29))
148 |
149 | consume(- 80.31 ^ 61.22)
150 | consume(45.41 ^ - 36.58)
151 | consume(bit32.bnot( 78.76) ^ 31.60)
152 | consume(87.72 ^ bit32.bnot( 61.91))
153 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # lua-js-syntax
2 |
3 | This is a [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler) from an alternative JS-inspired syntax for Lua to vanilla Lua.
4 |
5 | ### Advantages:
6 | - This is **not a Lua VM fork**, so you can use it with any VM implementation written in any language (like LuaJ for Java).
7 | - Has syntax sugar that Lua is missing: continue, try-catch, throw, bitwise operators, compound operators, increments, decrements, arrow functions.
8 | - You can use JS syntax highlighter to develop (given that you don't use Lua's OOP or # operator, which are invalid in normal JS)
9 | - Converter can be run as a console app, optionally reading and writing to files.
10 | - Line numbers are preserved during the conversion, so stacktraces will be accurate.
11 |
12 | ### Disadvantages:
13 | - To run the converter from non-JVM language, you need to run it as a console app.
14 | - To run LuaJS code, you need to convert it to Lua first. No runtime support like in Moonscript.
15 | - LuaJS is not a strict ECMAScript subset since it has Lua-like OOP, `#` and `..` operators.
16 |
17 | ### Alternative projects
18 |
19 | - [Moonscript](https://github.com/leafo/moonscript): a language compiled to Lua, with completely new syntax. The project itself provides a transpiler and runtime support for any Lua VM.
20 | - [ljs](https://github.com/mingodad/ljs): C Lua VM fork with JS-like syntax.
21 | - [jual](https://github.com/sajonoso/jual): C Lua VM fork with JS-like syntax that is a ECMAScript subset.
22 | - [Killa](https://github.com/ex/Killa): C Lua VM fork with JS-like syntax.
23 |
24 | ## Comparison with Lua
25 |
26 |
| LuaJS | Lua |
27 |
28 | |
29 |
30 | ```javascript
31 | /* A simple division function. */
32 | let divide = (x, y) => {
33 | if (y == 0) {
34 | throw "Divisor is zero"
35 | }
36 | return x / y
37 | }
38 |
39 | try {
40 | print('Result is ' .. divide(10, 0))
41 | } catch (e) {
42 | print('Error: ' .. e)
43 | }
44 |
45 | ```
46 |
47 | |
48 |
49 |
50 | ```lua
51 | --[[ A simple division function. ]]--
52 | local divide = function(x, y)
53 | if (y == 0) then
54 | error("Divisor is zero")
55 | end
56 | return x / y
57 | end
58 |
59 | local res, e = pcall(function()
60 | print('Result is ' .. tostring(divide(10, 0)))
61 | end)
62 | if not res then
63 | print('Error: ' .. tostring(e))
64 | end
65 | ```
66 |
67 | |
68 |
69 |
70 |
71 | See [COMPARISON.md](https://github.com/saharNooby/lua-js-syntax/blob/master/COMPARISON.md) for full comparison.
72 |
73 | ## Building
74 |
75 | To build, you need:
76 | - git
77 | - [JDK 8 or higher](https://adoptopenjdk.net/)
78 | - [Maven](http://maven.apache.org/)
79 |
80 | This will put JAR file to `target` dir and install it into local Maven repository:
81 |
82 | ```shell script
83 | git clone https://github.com/saharNooby/lua-js-syntax.git
84 | cd lua-js-syntax
85 | mvn clean install
86 | ```
87 |
88 | ## Running
89 |
90 | After build, you can either add this converter as a Maven dependency and use it from JVM-based language (Java, Kotlin, Scala etc.), or run it from console.
91 |
92 | ### Add as a dependency
93 |
94 | Maven dependency:
95 |
96 | ```xml
97 |
98 | me.saharnooby
99 | lua-js-syntax
100 | 1.0-SNAPSHOT
101 |
102 | ```
103 |
104 | Alternatively, you can just add the shaded JAR as a dependency directly to your build system.
105 |
106 | Then you can use method `me.saharnooby.luajssyntax.LuaJSToLua.convert(java.lang.String)` or `me.saharnooby.luajssyntax.LuaJSToLua.convert(java.lang.String, java.lang.Appendable)`. JavaDoc is available.
107 |
108 | ### Run from console
109 |
110 | - `cd` into `target`
111 | - Run `java -jar lua-js-syntax-1.0-SNAPSHOT-shaded.jar [source file] [destination file]`
112 |
113 | If the source file was not specified, source code will be read from `stdin`.
114 |
115 | If the destination file was not specified, resulting code will be written to `stdout`.
116 |
117 | Any errors will result in non-zero exit code and stacktraces printed to `stderr`.
118 |
119 | ## Testing
120 |
121 | The project has a list of unit tests comparing LuaJS code behavior to the behavior of manually written equivalent Lua code.
--------------------------------------------------------------------------------
/src/test/java/me/saharnooby/luajssyntax/TestGenerator.java:
--------------------------------------------------------------------------------
1 | package me.saharnooby.luajssyntax;
2 |
3 | import java.util.*;
4 |
5 | /**
6 | * Used to generate random test cases for validating operator priority.
7 | * @author saharNooby
8 | * @since 12:33 23.08.2019
9 | */
10 | public final class TestGenerator {
11 |
12 | private static final String[] OPS = new String[]{
13 | "+",
14 | "-",
15 | "*",
16 | "/",
17 | "%",
18 | "<",
19 | ">",
20 | "<=",
21 | ">=",
22 | "==",
23 | "!=",
24 | "&&",
25 | "||",
26 | "**",
27 | };
28 |
29 | private static final String[] UNARY = new String[]{"!", "-", "~", "#"};
30 |
31 | private static final Set COMPARISON = new HashSet<>(Arrays.asList("<", ">", "<=", ">=", "==", "!="));
32 |
33 | private static final Set ARITHMETIC = new HashSet<>(Arrays.asList("+", "-", "*", "/", "%", "**"));
34 |
35 | private static final Map OP_TO_LUA = new HashMap<>();
36 |
37 | static {
38 | OP_TO_LUA.put("!=", "~=");
39 | OP_TO_LUA.put("&&", "and");
40 | OP_TO_LUA.put("||", "or");
41 | OP_TO_LUA.put("**", "^");
42 | OP_TO_LUA.put("!", "not ");
43 | OP_TO_LUA.put("~", "bit32.bnot");
44 | }
45 |
46 | public static void main(String[] args) {
47 | generatePrioritiesWithUnary();
48 | }
49 |
50 | private static void generatePriorities() {
51 | Random r = new Random(123);
52 |
53 | StringBuilder builder = new StringBuilder();
54 | StringBuilder lua = new StringBuilder();
55 |
56 | for (String op1 : OPS) {
57 | for (String op2 : OPS) {
58 | if (COMPARISON.contains(op1) && COMPARISON.contains(op2)) {
59 | continue;
60 | }
61 |
62 | String num1 = num(r);
63 | String num2 = num(r);
64 | String num3 = num(r);
65 |
66 | builder.append("consume(")
67 | .append(num1)
68 | .append(" ")
69 | .append(op1)
70 | .append(" ")
71 | .append(num2)
72 | .append(" ")
73 | .append(op2)
74 | .append(" ")
75 | .append(num3)
76 | .append(")\n");
77 |
78 | lua.append("consume(")
79 | .append(num1)
80 | .append(" ")
81 | .append(OP_TO_LUA.getOrDefault(op1, op1))
82 | .append(" ")
83 | .append(num2)
84 | .append(" ")
85 | .append(OP_TO_LUA.getOrDefault(op2, op2))
86 | .append(" ")
87 | .append(num3)
88 | .append(")\n");
89 | }
90 |
91 | builder.append("\n");
92 | lua.append("\n");
93 | }
94 |
95 | System.out.println(builder);
96 | System.out.println("\n===\n\n");
97 | System.out.println(lua);
98 | }
99 |
100 | private static void generatePrioritiesWithUnary() {
101 | Random r = new Random(123);
102 |
103 | StringBuilder builder = new StringBuilder();
104 | StringBuilder lua = new StringBuilder();
105 |
106 | for (String op1 : OPS) {
107 | for (String op2 : UNARY) {
108 | if (op2.equals("#")) {
109 | continue;
110 | }
111 |
112 | if (op2.equals("!") && (ARITHMETIC.contains(op1) || COMPARISON.contains(op1))) {
113 | continue;
114 | }
115 |
116 | String num1 = num(r);
117 | String num2 = num(r);
118 | String num3 = num(r);
119 | String num4 = num(r);
120 |
121 | builder.append("consume(")
122 | .append(op2)
123 | .append(" ")
124 | .append(num1)
125 | .append(" ")
126 | .append(op1)
127 | .append(" ")
128 | .append(num2)
129 | .append(")\n");
130 |
131 | builder.append("consume(")
132 | .append(num3)
133 | .append(" ")
134 | .append(op1)
135 | .append(" ")
136 | .append(op2)
137 | .append(" ")
138 | .append(num4)
139 | .append(")\n");
140 |
141 | // ---
142 |
143 | lua.append("consume(");
144 | lua.append(OP_TO_LUA.getOrDefault(op2, op2));
145 | if (op2.equals("~")) {
146 | lua.append("(");
147 | }
148 | lua.append(" ");
149 | lua.append(num1);
150 | if (op2.equals("~")) {
151 | lua.append(")");
152 | }
153 | lua.append(" ");
154 | lua.append(OP_TO_LUA.getOrDefault(op1, op1));
155 | lua.append(" ");
156 | lua.append(num2);
157 | lua.append(")\n");
158 |
159 | lua.append("consume(");
160 | lua.append(num3);
161 | lua.append(" ");
162 | lua.append(OP_TO_LUA.getOrDefault(op1, op1));
163 | lua.append(" ");
164 | lua.append(OP_TO_LUA.getOrDefault(op2, op2));
165 | if (op2.equals("~")) {
166 | lua.append("(");
167 | }
168 | lua.append(" ");
169 | lua.append(num4);
170 | if (op2.equals("~")) {
171 | lua.append(")");
172 | }
173 | lua.append(")\n");
174 | }
175 |
176 | builder.append("\n");
177 | lua.append("\n");
178 | }
179 |
180 |
181 | System.out.println(builder);
182 | System.out.println("\n===\n\n");
183 | System.out.println(lua);
184 | }
185 |
186 | private static String num(Random r) {
187 | return r.nextInt(100) + "." + r.nextInt(100);
188 | }
189 |
190 | }
191 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | me.saharnooby
8 | lua-js-syntax
9 | 1.0.1
10 |
11 |
12 | UTF-8
13 |
14 | 1.8
15 | 1.8
16 |
17 |
18 |
19 | clean install
20 |
21 |
22 |
23 | maven-surefire-plugin
24 | 2.22.2
25 |
26 | false
27 |
28 |
29 |
30 |
31 | org.antlr
32 | antlr4-maven-plugin
33 | 4.8
34 |
35 |
36 | -package
37 | me.saharnooby.luajssyntax
38 |
39 | false
40 | false
41 |
42 |
43 |
44 |
45 | antlr4
46 |
47 |
48 |
49 |
50 |
51 |
52 | org.apache.maven.plugins
53 | maven-shade-plugin
54 | 3.2.2
55 |
56 |
57 |
58 | me.saharnooby.luajssyntax.Main
59 |
60 |
61 | true
62 |
63 |
64 |
65 | package
66 |
67 | shade
68 |
69 |
70 |
71 |
72 |
73 |
74 | org.apache.maven.plugins
75 | maven-javadoc-plugin
76 | 3.2.0
77 |
78 |
79 | attach-javadocs
80 |
81 | jar
82 |
83 |
84 |
85 |
86 |
87 |
88 | org.apache.maven.plugins
89 | maven-source-plugin
90 | 3.2.1
91 |
92 |
93 | attach-sources
94 |
95 | jar
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | org.antlr
106 | antlr4-runtime
107 | 4.8
108 |
109 |
110 |
111 | org.projectlombok
112 | lombok
113 | 1.18.12
114 | provided
115 |
116 |
117 |
118 | org.luaj
119 | luaj-jse
120 | 3.0.2
121 | test
122 |
123 |
124 |
125 | org.apache.bcel
126 | bcel
127 | 6.3.1
128 | test
129 |
130 |
131 |
132 | org.junit.jupiter
133 | junit-jupiter-api
134 | 5.0.0
135 | test
136 |
137 |
138 |
139 | org.junit.jupiter
140 | junit-jupiter-engine
141 | 5.0.0
142 | test
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/src/test/java/me/saharnooby/luajssyntax/ConverterTest.java:
--------------------------------------------------------------------------------
1 | package me.saharnooby.luajssyntax;
2 |
3 | import lombok.NonNull;
4 | import org.junit.jupiter.api.Assertions;
5 | import org.junit.jupiter.api.Test;
6 | import org.luaj.vm2.Globals;
7 | import org.luaj.vm2.LuaTable;
8 | import org.luaj.vm2.LuaValue;
9 | import org.luaj.vm2.Varargs;
10 | import org.luaj.vm2.compiler.LuaC;
11 | import org.luaj.vm2.lib.*;
12 | import org.luaj.vm2.lib.jse.JseBaseLib;
13 | import org.luaj.vm2.lib.jse.JseMathLib;
14 | import org.opentest4j.AssertionFailedError;
15 |
16 | import java.io.BufferedReader;
17 | import java.io.IOException;
18 | import java.io.InputStreamReader;
19 | import java.nio.charset.StandardCharsets;
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | /**
24 | * @author saharNooby
25 | * @since 20:25 21.08.2019
26 | */
27 | class ConverterTest {
28 |
29 | @Test
30 | void testLocals() {
31 | test();
32 | }
33 |
34 | @Test
35 | void testGlobals() {
36 | test();
37 | }
38 |
39 | @Test
40 | void testCompound() {
41 | test();
42 | }
43 |
44 | @Test
45 | void testBreak() {
46 | test();
47 | }
48 |
49 | @Test
50 | void testLabel() {
51 | test();
52 | }
53 |
54 | @Test
55 | void testReturn() {
56 | test();
57 | }
58 |
59 | @Test
60 | void testIf() {
61 | test();
62 | }
63 |
64 | @Test
65 | void testDoWhile() {
66 | test();
67 | }
68 |
69 | @Test
70 | void testFor() {
71 | test();
72 | }
73 |
74 | @Test
75 | void testForOptimized() {
76 | test();
77 | }
78 |
79 | @Test
80 | void testForIn() {
81 | test();
82 | }
83 |
84 | @Test
85 | void testForOf() {
86 | test();
87 | }
88 |
89 | @Test
90 | void testIncrement() {
91 | test();
92 | }
93 |
94 | @Test
95 | void testParenthesis() {
96 | test();
97 | }
98 |
99 | @Test
100 | void testLiterals() {
101 | test();
102 | }
103 |
104 | @Test
105 | void testNumbers() {
106 | test();
107 | }
108 |
109 | @Test
110 | void testStrings() {
111 | test();
112 | }
113 |
114 | @Test
115 | void testTables() {
116 | test();
117 | }
118 |
119 | @Test
120 | void testLists() {
121 | test();
122 | }
123 |
124 | @Test
125 | void testFunctionLiteral() {
126 | test();
127 | }
128 |
129 | @Test
130 | void testArrowFunctionLiteral() {
131 | test();
132 | }
133 |
134 | @Test
135 | void testUnary() {
136 | test();
137 | }
138 |
139 | @Test
140 | void testPower() {
141 | test();
142 | }
143 |
144 | @Test
145 | void testMath() {
146 | test();
147 | }
148 |
149 | @Test
150 | void testConcat() {
151 | test();
152 | }
153 |
154 | @Test
155 | void testComparison() {
156 | test();
157 | }
158 |
159 | @Test
160 | void testLogic() {
161 | test();
162 | }
163 |
164 | @Test
165 | void testBitwise() {
166 | test();
167 | }
168 |
169 | @Test
170 | void testPriorities() {
171 | test();
172 | }
173 |
174 | @Test
175 | void testPrioritiesUnary() {
176 | test();
177 | }
178 |
179 | @Test
180 | void testPrioritiesBitwise() {
181 | test();
182 | }
183 |
184 | @Test
185 | void testChainCalls() {
186 | test();
187 | }
188 |
189 | @Test
190 | void testTernary() {
191 | test();
192 | }
193 |
194 | @Test
195 | void testOOP() {
196 | test();
197 | }
198 |
199 | @Test
200 | void testContinue() {
201 | test();
202 | }
203 |
204 | @Test
205 | void testTryCatch() {
206 | test();
207 | }
208 |
209 | @Test
210 | void testThrow() {
211 | test();
212 | }
213 |
214 | @Test
215 | void testRequire() {
216 | test();
217 | }
218 |
219 | // The behavior of this method is caller dependent.
220 | private void test() {
221 | String testName = new Exception().getStackTrace()[1].getMethodName().substring(4);
222 |
223 | StringBuilder jsCode = new StringBuilder();
224 | StringBuilder luaCode = new StringBuilder();
225 |
226 | StringBuilder current = jsCode;
227 |
228 | try (BufferedReader reader = new BufferedReader(new InputStreamReader(ConverterTest.class.getResourceAsStream(testName + ".txt"), StandardCharsets.UTF_8))) {
229 | String line;
230 | while ((line = reader.readLine()) != null) {
231 | if (line.equals("===")) {
232 | current = luaCode;
233 | continue;
234 | }
235 |
236 | current.append(line).append("\n");
237 | }
238 | } catch (IOException e) {
239 | throw new RuntimeException(e);
240 | }
241 |
242 | String convertedCode = LuaJSToLua.convert(jsCode.toString());
243 |
244 | List real;
245 |
246 | try {
247 | real = runScript(convertedCode);
248 | } catch (RuntimeException e) {
249 | System.err.println("Converted code");
250 | System.err.println(convertedCode);
251 |
252 | throw e;
253 | }
254 |
255 | List expected;
256 |
257 | try {
258 | expected = runScript(luaCode.toString());
259 | } catch (RuntimeException e) {
260 | System.err.println("Lua check code");
261 | System.err.println(luaCode);
262 |
263 | throw e;
264 | }
265 |
266 | try {
267 | for (int i = 0; i < Math.min(real.size(), expected.size()); i++) {
268 | assertLuaValuesEquals(expected.get(i), real.get(i), "#" + i);
269 | }
270 |
271 | Assertions.assertEquals(expected.size(), real.size(), "call count mismatch");
272 | } catch (AssertionFailedError e) {
273 | System.err.println("Converted code");
274 | System.err.println(convertedCode);
275 |
276 | throw e;
277 | }
278 | }
279 |
280 | private List runScript(@NonNull String script) {
281 | Globals globals = new Globals();
282 |
283 | globals.load(new JseBaseLib());
284 | globals.load(new PackageLib());
285 | globals.load(new Bit32Lib());
286 | globals.load(new TableLib());
287 | globals.load(new StringLib());
288 | globals.load(new JseMathLib());
289 |
290 | LuaC.install(globals);
291 |
292 | // Required for module loading
293 | globals.undumper = (stream, chunkname) -> null;
294 |
295 | globals.set("tostring", new LibFunction() {
296 |
297 | public LuaValue call(LuaValue arg) {
298 | LuaValue meta = arg.metatag(TOSTRING);
299 |
300 | if (!meta.isnil()) {
301 | return meta.call(arg);
302 | }
303 |
304 | if (arg.istable()) {
305 | return valueOf("table");
306 | }
307 |
308 | LuaValue luaString = arg.tostring();
309 |
310 | if (!luaString.isnil()) {
311 | return luaString;
312 | }
313 |
314 | return valueOf(arg.tojstring());
315 | }
316 |
317 | });
318 |
319 | List list = new ArrayList<>();
320 |
321 | globals.set("consume", new VarArgFunction() {
322 |
323 | @Override
324 | public Varargs invoke(Varargs varargs) {
325 | for (int i = 1; i <= varargs.narg(); i++) {
326 | list.add(varargs.arg(i));
327 | }
328 |
329 | return NONE;
330 | }
331 | });
332 |
333 | globals.load(script, "main", globals).call();
334 |
335 | return list;
336 | }
337 |
338 | private static void assertTableEquals(LuaTable x, LuaTable y, String message) {
339 | Assertions.assertEquals(x.keyCount(), y.keyCount());
340 |
341 | for (int i = 0; i < x.keyCount(); i++) {
342 | LuaValue kx = x.keys()[i];
343 | LuaValue ky = y.keys()[i];
344 |
345 | assertLuaValuesEquals(kx, ky, message);
346 | assertLuaValuesEquals(x.get(kx), y.get(ky), message);
347 | }
348 | }
349 |
350 | private static void assertLuaValuesEquals(LuaValue kx, LuaValue ky, String message) {
351 | if ((kx instanceof LuaTable) != (ky instanceof LuaTable)) {
352 | throw new AssertionError(kx + ", " + ky);
353 | }
354 |
355 | if (kx instanceof LuaTable) {
356 | assertTableEquals((LuaTable) kx, (LuaTable) ky, message);
357 | } else {
358 | Assertions.assertEquals(kx, ky, message);
359 | }
360 | }
361 |
362 | }
363 |
--------------------------------------------------------------------------------
/src/main/antlr4/me/saharnooby/luajssyntax/LuaJSSyntax.g4:
--------------------------------------------------------------------------------
1 | grammar LuaJSSyntax;
2 |
3 | program
4 | : statement* EOF
5 | ;
6 |
7 | block
8 | : '{' statement* '}'
9 | ;
10 |
11 | statement
12 | : ';' # Semicolon
13 | | block # BlockStatement
14 | | 'let' namelist ('=' explist)? # LocalVariableDeclaration
15 | | varlist '=' explist # GlobalVariableDeclaration
16 | | var assignmentOperator exp # AssginmentOperator
17 | | var nameAndArgs # FunctionCall
18 | | NAME ':' # LabelDeclaration
19 | | 'break' # Break
20 | | 'continue' # Continue
21 | | 'goto' NAME # Goto
22 | | 'return' explist? # Return
23 | | 'if' '(' exp ')' statement ('else' statement)? # If
24 | | 'while' '(' exp ')' statement # While
25 | | 'do' statement 'while' '(' exp ')' # DoWhile
26 | | 'for' '(' init=statement? ';' exp? ';' after=statement? ')' body=statement # For
27 | | 'for' '(' namelist 'in' exp ')' statement # ForIn
28 | | 'for' '(' NAME (',' NAME)? 'of' exp ')' statement # ForOf
29 | | 'function' funcname '(' namelist? ')' block # FunctionDeclaration
30 | | 'try' block 'catch' '(' NAME ')' block # TryCatch
31 | | 'throw' exp # Throw
32 | | var '++' # Increment
33 | | var '--' # Decrement
34 | ;
35 |
36 | exp
37 | : '(' exp ')' # ParenthesisExpression
38 | | ('nil' | 'true' | 'false') # Literal
39 | | number # NumberLiteral
40 | | string # StringLiteral
41 | | var # VarExpression
42 | | var nameAndArgs # FunctionCallExpression
43 | | table # TableExpression
44 | | list # ListExpression
45 | | 'function' '(' namelist? ')' block # FunctionLiteral
46 | | ('(' namelist? ')' | NAME) '=>' (exp | block) # ArrowFunctionLiteral
47 | | op=('!' | '-' | '~' | '#') exp # UnaryOperator
48 | | exp op='**' exp # PowerOperator
49 | | exp op=('*' | '/' | '%') exp # MulDivModOperator
50 | | exp op=('+' | '-') exp # AddSubOperator
51 | | exp op=('<<' | '>>') exp # BitwiseShift
52 | | exp op='&' exp # BitwiseAnd
53 | | exp op='^' exp # BitwiseXor
54 | | exp op='|' exp # BitwiseOr
55 | | exp op='..' exp # ConcatOperator
56 | | exp op=('<' | '>' | '<=' | '>=' | '!=' | '==') exp # ComparisonOperator
57 | | exp op='&&' exp # AndOperator
58 | | exp op='||' exp # OrOperator
59 | | exp '?' exp ':' exp # TernaryOperator
60 | ;
61 |
62 | table
63 | : '{' entries? '}'
64 | ;
65 |
66 | list
67 | : '[' elements? ']'
68 | ;
69 |
70 | assignmentOperator
71 | : '*='
72 | | '/='
73 | | '%='
74 | | '+='
75 | | '-='
76 | | '&='
77 | | '|='
78 | | '^='
79 | | '<<='
80 | | '>>='
81 | | '..='
82 | | '**='
83 | ;
84 |
85 | funcname
86 | : (NAME '::')? NAME
87 | ;
88 |
89 | namelist
90 | : NAME (',' NAME)*
91 | ;
92 |
93 | explist
94 | : exp (',' exp)*
95 | ;
96 |
97 | entries
98 | : entry (',' entry)* ','?
99 | ;
100 |
101 | entry
102 | : (NAME | key_expr) ':' exp
103 | ;
104 |
105 | key_expr
106 | : '[' exp ']'
107 | ;
108 |
109 | elements
110 | : exp (',' exp)* ','?
111 | ;
112 |
113 | var
114 | : (NAME | '(' exp ')' varSuffix) varSuffix*
115 | ;
116 |
117 | varSuffix
118 | : nameAndArgs* ('[' exp ']' | '.' NAME)
119 | ;
120 |
121 | nameAndArgs
122 | : ('::' NAME)? args
123 | ;
124 |
125 | args
126 | : '(' explist? ')'
127 | ;
128 |
129 | varlist
130 | : var (',' var)*
131 | ;
132 |
133 | number
134 | : INT | HEX | FLOAT | HEX_FLOAT
135 | ;
136 |
137 | string
138 | : NORMALSTRING | CHARSTRING
139 | ;
140 |
141 | NAME
142 | : [a-zA-Z_][a-zA-Z_0-9]*
143 | ;
144 |
145 | INT
146 | : Digit+
147 | ;
148 |
149 | HEX
150 | : '0' [xX] HexDigit+
151 | ;
152 |
153 | FLOAT
154 | : Digit+ '.' Digit* ExponentPart?
155 | | '.' Digit+ ExponentPart?
156 | | Digit+ ExponentPart
157 | ;
158 |
159 | HEX_FLOAT
160 | : '0' [xX] HexDigit+ '.' HexDigit* HexExponentPart?
161 | | '0' [xX] '.' HexDigit+ HexExponentPart?
162 | | '0' [xX] HexDigit+ HexExponentPart
163 | ;
164 |
165 | fragment
166 | Digit
167 | : [0-9]
168 | ;
169 |
170 | fragment
171 | HexDigit
172 | : [0-9a-fA-F]
173 | ;
174 |
175 | fragment
176 | ExponentPart
177 | : [eE] [+-]? Digit+
178 | ;
179 |
180 | fragment
181 | HexExponentPart
182 | : [pP] [+-]? Digit+
183 | ;
184 |
185 | NORMALSTRING
186 | : '"' ( EscapeSequence | ~('\\'|'"') )* '"'
187 | ;
188 |
189 | CHARSTRING
190 | : '\'' ( EscapeSequence | ~('\''|'\\') )* '\''
191 | ;
192 |
193 | fragment
194 | EscapeSequence
195 | : '\\' [abfnrtvz"'\\]
196 | | '\\' '\r'? '\n'
197 | | DecimalEscape
198 | | HexEscape
199 | | UtfEscape
200 | ;
201 |
202 | fragment
203 | DecimalEscape
204 | : '\\' Digit
205 | | '\\' Digit Digit
206 | | '\\' [0-2] Digit Digit
207 | ;
208 |
209 | fragment
210 | HexEscape
211 | : '\\' 'x' HexDigit HexDigit
212 | ;
213 |
214 | fragment
215 | UtfEscape
216 | : '\\' 'u' HexDigit HexDigit HexDigit HexDigit
217 | ;
218 |
219 | COMMENT
220 | : '/*' .*? '*/' -> channel(HIDDEN)
221 | ;
222 |
223 | LINE_COMMENT
224 | : '//'
225 | (
226 | | ~('\r'|'\n') ~('\r'|'\n')*
227 | ) ('\r\n'|'\r'|'\n'|EOF)
228 | -> channel(HIDDEN)
229 | ;
230 |
231 | WS
232 | : [ \t\u000C\r\n]+ -> skip
233 | ;
--------------------------------------------------------------------------------
/COMPARISON.md:
--------------------------------------------------------------------------------
1 | # Comparison with vanilla Lua
2 |
3 | Note that comments and indents are not preserved during the conversion, they were added to
4 | the Lua code manually.
5 |
6 | | LuaJS | Lua (converted and formatted) |
7 |
8 | |
9 |
10 | ```javascript
11 | // One-line comment
12 | /* Multi-line
13 | comment */
14 |
15 | // Semicolons are optional
16 | print('semicolon');
17 | print('no semicolon')
18 |
19 | // Global variables
20 | gx, gy = 1, 2
21 | gz = 3
22 |
23 | // Local variables
24 | let lx, ly = 4, 5
25 |
26 | // Boolean literals and nil literal
27 | let literals = [nil, true, false]
28 |
29 | // String literals
30 | let sx = "string with escaped characters:\r\n \u0123 \x01 \0"
31 | let sy = 'single quotes\r\n'
32 |
33 | // String concatenation
34 | // Non-string values are automatically wrapped into tostring
35 | let concatResult = 'values are: (' .. [1, 2, 3] .. ', ' .. 123 .. ')'
36 |
37 | // Lists
38 | let list = [1, 2, ['nested list', 3, 4]]
39 |
40 | // Tables
41 | let table = {key: 'value', nested: {x: 1, y: 2}, ['expression' .. ' as a key']: 3}
42 | ```
43 |
44 | |
45 |
46 |
47 | ```lua
48 | -- One-line comment
49 | --[[ Multi-line
50 | comment ]]--
51 |
52 | -- Semicolons are optional
53 | print('semicolon');
54 | print('no semicolon')
55 |
56 | -- Global variables
57 | gx, gy = 1, 2
58 | gz = 3
59 |
60 | -- Local variables
61 | local lx, ly = 4, 5
62 |
63 | -- Boolean literals and nil literal
64 | local literals = {nil, true, false}
65 |
66 | -- String literals
67 | local sx = "string with escaped characters:\r\n ģ \x01 \0"
68 | local sy = 'single quotes\r\n'
69 |
70 | -- String concatenation
71 | -- Non-string values are automatically wrapped into tostring
72 | local concatResult = 'values are: (' .. tostring({1, 2, 3}) .. ', ' .. tostring(123) .. ')'
73 |
74 | -- Lists
75 | local list = {1, 2, {'nested list', 3, 4}}
76 |
77 | -- Tables
78 | local table = {key='value', nested={x=1, y=2}, ['expression' .. ' as a key']=3}
79 | ```
80 |
81 | |
82 |
83 |
84 |
85 | ## Functions
86 |
87 | | LuaJS | Lua (converted and formatted) |
88 |
89 | |
90 |
91 | ```javascript
92 | function literalFunction() {
93 | return 1
94 | }
95 |
96 | function literalFunctionWithArgs(x, y) {
97 | return x + y
98 | }
99 |
100 | // Arrow functions
101 | let f = () => 1
102 |
103 | let fWithArg = x => x * 10
104 |
105 | let fBlock = x => {
106 | return x * 10
107 | }
108 |
109 | let fWithTwoArgs = (x, y) => x + y
110 | ```
111 |
112 | |
113 |
114 |
115 | ```lua
116 | function literalFunction()
117 | return 1
118 | end
119 |
120 | function literalFunctionWithArgs(x, y)
121 | return x + y
122 | end
123 |
124 | -- Arrow functions
125 | local f = function() return 1 end
126 |
127 | local fWithArg = function(x) return x * 10 end
128 |
129 | local fBlock = function(x)
130 | return x * 10
131 | end
132 |
133 | local fWithTwoArgs = function(x, y) return x + y end
134 | ```
135 |
136 | |
137 |
138 |
139 |
140 | ## Conditions and loops
141 |
142 | | LuaJS | Lua (converted and formatted) |
143 |
144 | |
145 |
146 | ```javascript
147 | // if statement, while loop and break statement
148 | let counter = 10
149 | while (true) {
150 | print(counter)
151 |
152 | counter--
153 |
154 | if (counter == 0) {
155 | break
156 | }
157 | }
158 |
159 | // do-while loop
160 | counter = 10
161 | do {
162 | print(counter)
163 |
164 | counter--
165 | } while(counter > 1)
166 |
167 | // continue statement and for loop (initialization; condition; action after iteration)
168 | for (let i = 0; i < 10; i++) {
169 | print('i is ' .. i)
170 |
171 | if (i % 2 != 0) {
172 | continue
173 | }
174 |
175 | print('i is even')
176 | }
177 |
178 |
179 |
180 |
181 | // for-in loop
182 | let table = {a: 1, b: 2, c: 3}
183 |
184 | for (k in pairs(table)) {
185 | print('key only: ' .. k)
186 | }
187 |
188 | for (k, v in pairs(table)) {
189 | print('key and value: ' .. k .. ', ' .. v)
190 | }
191 |
192 | // for-of loop, iterates over ipairs
193 | let list = [1, 2, 3]
194 |
195 | for (v of list) {
196 | print('element is ' .. v)
197 | }
198 |
199 | for (v, i of list) {
200 | print('element is ' .. v .. ', index is ' .. i)
201 | }
202 |
203 | // Labels and goto
204 | let result = 10
205 | while (true) {
206 | if (result == 1) {
207 | goto someLabel
208 | }
209 |
210 | result--
211 | }
212 |
213 | someLabel: print(result)
214 | ```
215 |
216 | |
217 |
218 |
219 | ```lua
220 | -- if statement, while loop and break statement
221 | local counter = 10
222 | while (true) do
223 | print(counter)
224 |
225 | counter = counter - 1
226 |
227 | if (counter == 0) then
228 | break
229 | end
230 | end
231 |
232 | -- do-while loop
233 | counter = 10
234 | repeat
235 | print(counter)
236 |
237 | counter = counter - 1
238 | until (not (counter > 1))
239 |
240 | -- continue statement and for loop (initialization; condition; action after iteration)
241 | do
242 | local i = 0;
243 | while (i < 10) do
244 | print('i is ' .. tostring(i))
245 | if (i % 2 ~= 0) then
246 | goto continueLabel
247 | end
248 | print('i is even')
249 | ::continueLabel::
250 | i = i + 1
251 | end
252 | end
253 |
254 | -- for-in loop
255 | local table = {a=1, b=2, c=3}
256 |
257 | for k in pairs(table) do
258 | print('key only: ' .. tostring(k))
259 | end
260 |
261 | for k, v in pairs(table) do
262 | print('key and value: ' .. tostring(k) .. ', ' .. tostring(v))
263 | end
264 |
265 | -- for-of loop, iterates over ipairs
266 | local list = {1, 2, 3}
267 |
268 | for _, v in ipairs(list) do
269 | print('element is ' .. tostring(v))
270 | end
271 |
272 | for i, v in ipairs(list) do
273 | print('element is ' .. tostring(v) .. ', index is ' .. tostring(i))
274 | end
275 |
276 | -- Labels and goto
277 | local result = 10
278 | while (true) do
279 | if (result == 1) then
280 | goto someLabel
281 | end
282 | result = result - 1
283 | end
284 |
285 | ::someLabel::
286 | print(result)
287 | ```
288 |
289 | |
290 |
291 |
292 |
293 | ## Exceptions
294 |
295 | | LuaJS | Lua (converted and formatted) |
296 |
297 | |
298 |
299 | ```javascript
300 | try {
301 | if (1 > 10) {
302 | throw 'unexpected math behavior!'
303 | }
304 | } catch (e) {
305 | print('some error has occurred: ' .. e)
306 | }
307 |
308 |
309 |
310 |
311 | ```
312 |
313 | |
314 |
315 |
316 | ```lua
317 | do
318 | local res_c3409912_0, e_c3409912_0 = pcall(function()
319 | if (1 > 10) then
320 | error('unexpected math behavior!')
321 | end
322 | end)
323 | if not res_c3409912_0 then
324 | local e = e_c3409912_0
325 | print('some error has occurred: ' .. tostring(e))
326 | end
327 | end
328 | ```
329 |
330 | |
331 |
332 |
333 |
334 | ## Operators
335 |
336 | | LuaJS | Lua (converted and formatted) |
337 |
338 | |
339 |
340 | ```javascript
341 | // Math operators: +, -, *, /, %, ** (power operator)
342 | let mathResult = 100 + 3 ** 2
343 |
344 | // Logical operators: &&, ||
345 | let conditionA = 10 > 1
346 | let conditionB = 1 != 3
347 | if (conditionA && conditionB) {
348 | print('all ok')
349 | }
350 |
351 | // Comparison operators: >, <, >=, <=, ==, !=
352 | if (1 != 10) {
353 | print('all ok')
354 | }
355 |
356 | // Bitwise operators: & (and), | (or), ^ (xor), << (shift to left), >> (shift to right)
357 | // This evaluates to 5:
358 | let bitwiseResult = 1 & 2 | 4
359 |
360 | // Unary operators: - (negation), ! (logical negation), ~ (bitwise not), # (length operator)
361 | let notResult = ~4
362 | let length = #[1, 2, 3]
363 |
364 | // Compound assignment statements (works with all operators)
365 | let compound = 100
366 | compound *= 10
367 | compound += 5
368 |
369 | // Increment and decrement statements
370 | let incremented = 1
371 | incremented++
372 |
373 | // Ternary operator
374 | let ternaryResult = 2 > 1 ? 'two is more than one' : 'something is wrong'
375 | ```
376 |
377 | |
378 |
379 |
380 | ```lua
381 | -- Math operators: +, -, *, /, %, ** (power operator)
382 | local mathResult = 100 + 3 ^ 2
383 |
384 | -- Logical operators: &&, ||
385 | local conditionA = 10 > 1
386 | local conditionB = 1 ~= 3
387 | if (conditionA and conditionB) then
388 | print('all ok')
389 | end
390 |
391 | -- Comparison operators: >, <, >=, <=, ==, !=
392 | if (1 ~= 10) then
393 | print('all ok')
394 | end
395 |
396 | -- Bitwise operators: & (and), | (or), ^ (xor), << (shift to left), >> (shift to right)
397 | -- This evaluates to 5:
398 | local bitwiseResult = bit32.bor(bit32.band(1, 2), 4)
399 |
400 | -- Unary operators: - (negation), ! (logical negation), ~ (bitwise not), # (length operator)
401 | local notResult = bit32.bnot(4)
402 | local length = #{1, 2, 3}
403 |
404 | -- Compound assignment statements (works with all operators)
405 | local compound = 100
406 | compound = compound * 10
407 | compound = compound + 5
408 |
409 | -- Increment and decrement statements
410 | local incremented = 1
411 | incremented = incremented + 1
412 |
413 | -- Ternary operator
414 | local ternaryResult = (2 > 1) and ('two is more than one') or ('something is wrong')
415 | ```
416 |
417 | |
418 |
419 |
420 |
421 | ## OOP
422 |
423 | | LuaJS | Lua (converted and formatted) |
424 |
425 | |
426 |
427 | ```javascript
428 | SomeClass = {}
429 |
430 | function SomeClass::new() {
431 | object = {}
432 | self.__index = self
433 | return setmetatable(object, self)
434 | }
435 |
436 | function SomeClass::printSomething() {
437 | print('something')
438 | }
439 |
440 | let someObject = SomeClass::new()
441 | someObject::printSomething()
442 | ```
443 |
444 | |
445 |
446 |
447 | ```lua
448 | SomeClass = {}
449 |
450 | function SomeClass:new()
451 | object = {}
452 | self.__index = self
453 | return setmetatable(object, self)
454 | end
455 |
456 | function SomeClass:printSomething()
457 | print('something')
458 | end
459 |
460 | local someObject = SomeClass:new()
461 | someObject:printSomething()
462 | ```
463 |
464 | |
465 |
466 |
--------------------------------------------------------------------------------
/src/test/resources/me/saharnooby/luajssyntax/Priorities.txt:
--------------------------------------------------------------------------------
1 | consume(82.50 + 76.89 + 95.57)
2 | consume(34.37 + 85.53 - 39.26)
3 | consume(72.65 + 37.49 * 20.85)
4 | consume(54.16 + 22.37 / 36.50)
5 | consume(78.53 + 8.92 % 21.44)
6 | consume(61.72 + 30.33 < 52.75)
7 | consume(53.34 + 35.86 > 48.42)
8 | consume(43.50 + 14.36 <= 43.50)
9 | consume(68.90 + 6.14 >= 50.54)
10 | consume(33.21 + 72.98 == 51.17)
11 | consume(39.43 + 29.0 != 97.98)
12 | consume(18.27 + 20.90 && 88.49)
13 | consume(14.75 + 26.93 || 65.76)
14 | consume(87.50 + 45.5 ** 95.89)
15 |
16 | consume(89.83 - 72.26 + 31.84)
17 | consume(55.24 - 1.56 - 53.5)
18 | consume(37.99 - 71.89 * 20.10)
19 | consume(58.60 - 27.27 / 0.36)
20 | consume(82.44 - 20.50 % 26.4)
21 | consume(76.88 - 15.43 < 94.52)
22 | consume(19.21 - 32.47 > 55.81)
23 | consume(77.76 - 35.58 <= 18.86)
24 | consume(36.33 - 41.21 >= 95.36)
25 | consume(49.2 - 13.89 == 68.41)
26 | consume(79.81 - 6.32 != 19.3)
27 | consume(7.74 - 32.99 && 87.17)
28 | consume(80.51 - 49.9 || 36.13)
29 | consume(51.49 - 21.61 ** 26.37)
30 |
31 | consume(2.37 * 74.11 + 53.91)
32 | consume(41.69 * 24.7 - 92.11)
33 | consume(14.2 * 59.53 * 19.24)
34 | consume(67.47 * 64.69 / 1.4)
35 | consume(79.79 * 59.47 % 99.39)
36 | consume(14.88 * 49.91 < 87.76)
37 | consume(7.17 * 84.76 > 86.97)
38 | consume(30.95 * 67.57 <= 70.37)
39 | consume(34.22 * 29.35 >= 17.77)
40 | consume(33.29 * 80.31 == 61.22)
41 | consume(45.41 * 36.58 != 78.76)
42 | consume(31.60 * 87.72 && 61.91)
43 | consume(15.89 * 53.64 || 0.51)
44 | consume(8.45 * 43.7 ** 0.60)
45 |
46 | consume(37.59 / 33.23 + 47.31)
47 | consume(37.24 / 61.55 - 55.31)
48 | consume(15.69 / 14.55 * 0.59)
49 | consume(17.6 / 5.18 / 96.40)
50 | consume(35.50 / 72.11 % 57.53)
51 | consume(60.22 / 96.52 < 56.20)
52 | consume(64.26 / 96.12 > 32.72)
53 | consume(51.38 / 91.50 <= 13.53)
54 | consume(43.47 / 22.81 >= 47.67)
55 | consume(0.61 / 32.22 == 96.45)
56 | consume(60.90 / 98.73 != 80.87)
57 | consume(36.30 / 52.71 && 70.31)
58 | consume(81.61 / 23.4 || 58.75)
59 | consume(87.47 / 16.91 ** 8.99)
60 |
61 | consume(45.62 % 32.42 + 88.84)
62 | consume(87.72 % 36.21 - 65.18)
63 | consume(59.37 % 39.73 * 73.84)
64 | consume(45.79 % 38.53 / 21.61)
65 | consume(44.36 % 12.20 % 2.55)
66 | consume(17.49 % 51.78 < 24.75)
67 | consume(79.76 % 16.35 > 61.82)
68 | consume(78.76 % 57.30 <= 82.23)
69 | consume(65.96 % 88.47 >= 75.21)
70 | consume(51.64 % 34.45 == 81.8)
71 | consume(86.97 % 52.3 != 45.7)
72 | consume(37.25 % 93.97 && 48.16)
73 | consume(76.36 % 88.84 || 91.41)
74 | consume(69.74 % 23.43 ** 92.20)
75 |
76 | consume(50.8 < 14.67 + 42.87)
77 | consume(77.72 < 52.42 - 1.25)
78 | consume(84.77 < 99.11 * 29.91)
79 | consume(88.77 < 99.73 / 92.96)
80 | consume(77.90 < 92.43 % 67.21)
81 | consume(27.47 < 60.3 && 62.92)
82 | consume(22.8 < 49.66 || 39.41)
83 | consume(91.22 < 54.36 ** 72.37)
84 |
85 | consume(35.59 > 98.19 + 24.24)
86 | consume(1.34 > 47.70 - 67.38)
87 | consume(81.62 > 4.97 * 16.69)
88 | consume(80.72 > 65.41 / 16.45)
89 | consume(40.44 > 32.35 % 33.92)
90 | consume(26.0 > 5.21 && 23.66)
91 | consume(82.37 > 27.90 || 20.25)
92 | consume(22.7 > 21.30 ** 40.62)
93 |
94 | consume(64.59 <= 2.87 + 59.23)
95 | consume(83.34 <= 22.15 - 34.13)
96 | consume(64.9 <= 1.7 * 49.84)
97 | consume(79.54 <= 97.32 / 91.98)
98 | consume(17.10 <= 21.57 % 92.33)
99 | consume(10.96 <= 89.52 && 44.24)
100 | consume(84.80 <= 77.59 || 35.83)
101 | consume(62.65 <= 31.11 ** 84.6)
102 |
103 | consume(56.97 >= 9.58 + 93.44)
104 | consume(24.4 >= 54.14 - 88.9)
105 | consume(49.19 >= 15.17 * 55.13)
106 | consume(28.12 >= 44.61 / 42.50)
107 | consume(1.43 >= 24.34 % 6.50)
108 | consume(15.49 >= 61.83 && 47.71)
109 | consume(27.59 >= 42.23 || 62.48)
110 | consume(74.7 >= 67.76 ** 14.44)
111 |
112 | consume(85.66 == 53.3 + 48.11)
113 | consume(67.26 == 8.36 - 92.6)
114 | consume(86.14 == 7.93 * 45.63)
115 | consume(0.61 == 17.88 / 98.43)
116 | consume(94.53 == 25.83 % 40.16)
117 | consume(59.17 == 72.14 && 75.73)
118 | consume(58.68 == 51.68 || 5.50)
119 | consume(42.67 == 13.79 ** 43.45)
120 |
121 | consume(24.64 != 87.44 + 17.31)
122 | consume(11.49 != 9.76 - 83.13)
123 | consume(35.71 != 51.81 * 92.57)
124 | consume(41.10 != 76.38 / 74.30)
125 | consume(16.56 != 50.34 % 77.73)
126 | consume(51.53 != 21.63 && 62.28)
127 | consume(18.76 != 30.52 || 36.58)
128 | consume(90.80 != 41.61 ** 45.22)
129 |
130 | consume(32.56 && 61.29 + 41.35)
131 | consume(45.79 && 73.35 - 44.42)
132 | consume(49.84 && 96.73 * 66.67)
133 | consume(7.20 && 60.95 / 26.8)
134 | consume(19.98 && 32.37 % 60.38)
135 | consume(22.51 && 17.99 < 45.24)
136 | consume(25.25 && 52.71 > 11.10)
137 | consume(16.98 && 57.60 <= 50.2)
138 | consume(72.85 && 96.17 >= 51.28)
139 | consume(64.5 && 98.77 == 90.60)
140 | consume(50.43 && 69.97 != 30.9)
141 | consume(30.49 && 81.15 && 93.19)
142 | consume(3.77 && 85.85 || 85.74)
143 | consume(15.63 && 78.24 ** 71.43)
144 |
145 | consume(72.88 || 87.12 + 56.51)
146 | consume(12.69 || 62.38 - 75.54)
147 | consume(60.15 || 12.76 * 51.40)
148 | consume(15.22 || 36.69 / 73.60)
149 | consume(18.32 || 9.33 % 26.81)
150 | consume(65.29 || 69.93 < 19.68)
151 | consume(70.18 || 10.83 > 20.4)
152 | consume(22.21 || 31.4 <= 87.47)
153 | consume(17.74 || 71.20 >= 71.34)
154 | consume(38.19 || 54.19 == 36.2)
155 | consume(92.76 || 70.37 != 36.92)
156 | consume(97.21 || 67.89 && 68.40)
157 | consume(60.21 || 13.62 || 87.33)
158 | consume(75.36 || 57.56 ** 99.33)
159 |
160 | consume(20.91 ** 9.70 + 75.64)
161 | consume(39.84 ** 82.44 - 30.81)
162 | consume(48.73 ** 24.16 * 32.42)
163 | consume(30.42 ** 38.54 / 77.53)
164 | consume(43.37 ** 60.20 % 57.49)
165 | consume(11.86 ** 82.53 < 39.76)
166 | consume(16.97 ** 98.10 > 2.57)
167 | consume(37.90 ** 9.24 <= 25.24)
168 | consume(37.77 ** 47.85 >= 26.65)
169 | consume(60.43 ** 88.89 == 34.55)
170 | consume(76.47 ** 41.22 != 11.23)
171 | consume(94.66 ** 8.43 && 66.69)
172 | consume(36.88 ** 6.64 || 75.66)
173 | consume(95.17 ** 94.7 ** 57.63)
174 |
175 |
176 |
177 | ===
178 |
179 |
180 | consume(82.50 + 76.89 + 95.57)
181 | consume(34.37 + 85.53 - 39.26)
182 | consume(72.65 + 37.49 * 20.85)
183 | consume(54.16 + 22.37 / 36.50)
184 | consume(78.53 + 8.92 % 21.44)
185 | consume(61.72 + 30.33 < 52.75)
186 | consume(53.34 + 35.86 > 48.42)
187 | consume(43.50 + 14.36 <= 43.50)
188 | consume(68.90 + 6.14 >= 50.54)
189 | consume(33.21 + 72.98 == 51.17)
190 | consume(39.43 + 29.0 ~= 97.98)
191 | consume(18.27 + 20.90 and 88.49)
192 | consume(14.75 + 26.93 or 65.76)
193 | consume(87.50 + 45.5 ^ 95.89)
194 |
195 | consume(89.83 - 72.26 + 31.84)
196 | consume(55.24 - 1.56 - 53.5)
197 | consume(37.99 - 71.89 * 20.10)
198 | consume(58.60 - 27.27 / 0.36)
199 | consume(82.44 - 20.50 % 26.4)
200 | consume(76.88 - 15.43 < 94.52)
201 | consume(19.21 - 32.47 > 55.81)
202 | consume(77.76 - 35.58 <= 18.86)
203 | consume(36.33 - 41.21 >= 95.36)
204 | consume(49.2 - 13.89 == 68.41)
205 | consume(79.81 - 6.32 ~= 19.3)
206 | consume(7.74 - 32.99 and 87.17)
207 | consume(80.51 - 49.9 or 36.13)
208 | consume(51.49 - 21.61 ^ 26.37)
209 |
210 | consume(2.37 * 74.11 + 53.91)
211 | consume(41.69 * 24.7 - 92.11)
212 | consume(14.2 * 59.53 * 19.24)
213 | consume(67.47 * 64.69 / 1.4)
214 | consume(79.79 * 59.47 % 99.39)
215 | consume(14.88 * 49.91 < 87.76)
216 | consume(7.17 * 84.76 > 86.97)
217 | consume(30.95 * 67.57 <= 70.37)
218 | consume(34.22 * 29.35 >= 17.77)
219 | consume(33.29 * 80.31 == 61.22)
220 | consume(45.41 * 36.58 ~= 78.76)
221 | consume(31.60 * 87.72 and 61.91)
222 | consume(15.89 * 53.64 or 0.51)
223 | consume(8.45 * 43.7 ^ 0.60)
224 |
225 | consume(37.59 / 33.23 + 47.31)
226 | consume(37.24 / 61.55 - 55.31)
227 | consume(15.69 / 14.55 * 0.59)
228 | consume(17.6 / 5.18 / 96.40)
229 | consume(35.50 / 72.11 % 57.53)
230 | consume(60.22 / 96.52 < 56.20)
231 | consume(64.26 / 96.12 > 32.72)
232 | consume(51.38 / 91.50 <= 13.53)
233 | consume(43.47 / 22.81 >= 47.67)
234 | consume(0.61 / 32.22 == 96.45)
235 | consume(60.90 / 98.73 ~= 80.87)
236 | consume(36.30 / 52.71 and 70.31)
237 | consume(81.61 / 23.4 or 58.75)
238 | consume(87.47 / 16.91 ^ 8.99)
239 |
240 | consume(45.62 % 32.42 + 88.84)
241 | consume(87.72 % 36.21 - 65.18)
242 | consume(59.37 % 39.73 * 73.84)
243 | consume(45.79 % 38.53 / 21.61)
244 | consume(44.36 % 12.20 % 2.55)
245 | consume(17.49 % 51.78 < 24.75)
246 | consume(79.76 % 16.35 > 61.82)
247 | consume(78.76 % 57.30 <= 82.23)
248 | consume(65.96 % 88.47 >= 75.21)
249 | consume(51.64 % 34.45 == 81.8)
250 | consume(86.97 % 52.3 ~= 45.7)
251 | consume(37.25 % 93.97 and 48.16)
252 | consume(76.36 % 88.84 or 91.41)
253 | consume(69.74 % 23.43 ^ 92.20)
254 |
255 | consume(50.8 < 14.67 + 42.87)
256 | consume(77.72 < 52.42 - 1.25)
257 | consume(84.77 < 99.11 * 29.91)
258 | consume(88.77 < 99.73 / 92.96)
259 | consume(77.90 < 92.43 % 67.21)
260 | consume(27.47 < 60.3 and 62.92)
261 | consume(22.8 < 49.66 or 39.41)
262 | consume(91.22 < 54.36 ^ 72.37)
263 |
264 | consume(35.59 > 98.19 + 24.24)
265 | consume(1.34 > 47.70 - 67.38)
266 | consume(81.62 > 4.97 * 16.69)
267 | consume(80.72 > 65.41 / 16.45)
268 | consume(40.44 > 32.35 % 33.92)
269 | consume(26.0 > 5.21 and 23.66)
270 | consume(82.37 > 27.90 or 20.25)
271 | consume(22.7 > 21.30 ^ 40.62)
272 |
273 | consume(64.59 <= 2.87 + 59.23)
274 | consume(83.34 <= 22.15 - 34.13)
275 | consume(64.9 <= 1.7 * 49.84)
276 | consume(79.54 <= 97.32 / 91.98)
277 | consume(17.10 <= 21.57 % 92.33)
278 | consume(10.96 <= 89.52 and 44.24)
279 | consume(84.80 <= 77.59 or 35.83)
280 | consume(62.65 <= 31.11 ^ 84.6)
281 |
282 | consume(56.97 >= 9.58 + 93.44)
283 | consume(24.4 >= 54.14 - 88.9)
284 | consume(49.19 >= 15.17 * 55.13)
285 | consume(28.12 >= 44.61 / 42.50)
286 | consume(1.43 >= 24.34 % 6.50)
287 | consume(15.49 >= 61.83 and 47.71)
288 | consume(27.59 >= 42.23 or 62.48)
289 | consume(74.7 >= 67.76 ^ 14.44)
290 |
291 | consume(85.66 == 53.3 + 48.11)
292 | consume(67.26 == 8.36 - 92.6)
293 | consume(86.14 == 7.93 * 45.63)
294 | consume(0.61 == 17.88 / 98.43)
295 | consume(94.53 == 25.83 % 40.16)
296 | consume(59.17 == 72.14 and 75.73)
297 | consume(58.68 == 51.68 or 5.50)
298 | consume(42.67 == 13.79 ^ 43.45)
299 |
300 | consume(24.64 ~= 87.44 + 17.31)
301 | consume(11.49 ~= 9.76 - 83.13)
302 | consume(35.71 ~= 51.81 * 92.57)
303 | consume(41.10 ~= 76.38 / 74.30)
304 | consume(16.56 ~= 50.34 % 77.73)
305 | consume(51.53 ~= 21.63 and 62.28)
306 | consume(18.76 ~= 30.52 or 36.58)
307 | consume(90.80 ~= 41.61 ^ 45.22)
308 |
309 | consume(32.56 and 61.29 + 41.35)
310 | consume(45.79 and 73.35 - 44.42)
311 | consume(49.84 and 96.73 * 66.67)
312 | consume(7.20 and 60.95 / 26.8)
313 | consume(19.98 and 32.37 % 60.38)
314 | consume(22.51 and 17.99 < 45.24)
315 | consume(25.25 and 52.71 > 11.10)
316 | consume(16.98 and 57.60 <= 50.2)
317 | consume(72.85 and 96.17 >= 51.28)
318 | consume(64.5 and 98.77 == 90.60)
319 | consume(50.43 and 69.97 ~= 30.9)
320 | consume(30.49 and 81.15 and 93.19)
321 | consume(3.77 and 85.85 or 85.74)
322 | consume(15.63 and 78.24 ^ 71.43)
323 |
324 | consume(72.88 or 87.12 + 56.51)
325 | consume(12.69 or 62.38 - 75.54)
326 | consume(60.15 or 12.76 * 51.40)
327 | consume(15.22 or 36.69 / 73.60)
328 | consume(18.32 or 9.33 % 26.81)
329 | consume(65.29 or 69.93 < 19.68)
330 | consume(70.18 or 10.83 > 20.4)
331 | consume(22.21 or 31.4 <= 87.47)
332 | consume(17.74 or 71.20 >= 71.34)
333 | consume(38.19 or 54.19 == 36.2)
334 | consume(92.76 or 70.37 ~= 36.92)
335 | consume(97.21 or 67.89 and 68.40)
336 | consume(60.21 or 13.62 or 87.33)
337 | consume(75.36 or 57.56 ^ 99.33)
338 |
339 | consume(20.91 ^ 9.70 + 75.64)
340 | consume(39.84 ^ 82.44 - 30.81)
341 | consume(48.73 ^ 24.16 * 32.42)
342 | consume(30.42 ^ 38.54 / 77.53)
343 | consume(43.37 ^ 60.20 % 57.49)
344 | consume(11.86 ^ 82.53 < 39.76)
345 | consume(16.97 ^ 98.10 > 2.57)
346 | consume(37.90 ^ 9.24 <= 25.24)
347 | consume(37.77 ^ 47.85 >= 26.65)
348 | consume(60.43 ^ 88.89 == 34.55)
349 | consume(76.47 ^ 41.22 ~= 11.23)
350 | consume(94.66 ^ 8.43 and 66.69)
351 | consume(36.88 ^ 6.64 or 75.66)
352 | consume(95.17 ^ 94.7 ^ 57.63)
353 |
--------------------------------------------------------------------------------
/src/main/java/me/saharnooby/luajssyntax/LuaJSToLuaConverter.java:
--------------------------------------------------------------------------------
1 | package me.saharnooby.luajssyntax;
2 |
3 | import lombok.NonNull;
4 | import me.saharnooby.luajssyntax.exception.InvalidSyntaxException;
5 | import me.saharnooby.luajssyntax.util.Printer;
6 | import org.antlr.v4.runtime.ParserRuleContext;
7 | import org.antlr.v4.runtime.Token;
8 | import org.antlr.v4.runtime.tree.ParseTree;
9 | import org.antlr.v4.runtime.tree.TerminalNode;
10 |
11 | import java.lang.reflect.InvocationTargetException;
12 | import java.lang.reflect.Method;
13 | import java.util.HashSet;
14 | import java.util.List;
15 | import java.util.Set;
16 | import java.util.function.Consumer;
17 |
18 | /**
19 | * @author saharNooby
20 | * @since 16:28 20.08.2019
21 | */
22 | @SuppressWarnings("unused")
23 | final class LuaJSToLuaConverter {
24 |
25 | private final Printer printer;
26 | /**
27 | * MD5 hash of the source code.
28 | */
29 | private final String sourceHash;
30 |
31 | /**
32 | * Current loop nesting level, 0 == not inside loop currently.
33 | * This value is id of current label used to emulate continue statement.
34 | */
35 | private int loopLevel = 0;
36 | /**
37 | * Set of used ids of continue labels.
38 | * Unused labels will not be emitted.
39 | */
40 | private final Set usedLabels = new HashSet<>();
41 |
42 | /**
43 | * Index of the variable used to store pcall status.
44 | */
45 | private int nextStatusVarIndex;
46 |
47 | public LuaJSToLuaConverter(@NonNull Printer printer, @NonNull String sourceHash) {
48 | this.printer = printer;
49 | this.sourceHash = sourceHash;
50 | }
51 |
52 | private void print(String s) {
53 | this.printer.print(s);
54 | }
55 |
56 | private void line(Token token) {
57 | this.printer.setExpectedLine(token.getLine());
58 | }
59 |
60 | public void print(LuaJSSyntaxParser.ProgramContext ctx) {
61 | print(ctx.statement());
62 | }
63 |
64 | // region Statements
65 |
66 | private void print(LuaJSSyntaxParser.SemicolonContext ctx) {
67 |
68 | }
69 |
70 | private void print(LuaJSSyntaxParser.BreakContext ctx) {
71 | print("break");
72 | }
73 |
74 | private void print(LuaJSSyntaxParser.ContinueContext ctx) {
75 | if (this.loopLevel == 0) {
76 | throw new InvalidSyntaxException(ctx.start.getLine(), ctx.start.getCharPositionInLine(), "continue outside of loop", null);
77 | }
78 |
79 | print("goto ");
80 | print(getContinueLabel());
81 |
82 | this.usedLabels.add(this.loopLevel);
83 | }
84 |
85 | private void print(LuaJSSyntaxParser.BlockStatementContext ctx) {
86 | print(ctx, true);
87 | }
88 |
89 | private void print(LuaJSSyntaxParser.BlockStatementContext ctx, boolean printDoEnd) {
90 | if (printDoEnd) {
91 | print("do ");
92 | }
93 |
94 | print(ctx.block().statement());
95 |
96 | if (printDoEnd) {
97 | print(" end");
98 | }
99 | }
100 |
101 | private void printWithoutDoEnd(LuaJSSyntaxParser.StatementContext ctx) {
102 | if (ctx instanceof LuaJSSyntaxParser.BlockStatementContext) {
103 | print((LuaJSSyntaxParser.BlockStatementContext) ctx, false);
104 | } else {
105 | print(ctx);
106 | }
107 | }
108 |
109 | private void print(LuaJSSyntaxParser.LocalVariableDeclarationContext ctx) {
110 | print("local ");
111 | print(ctx.namelist());
112 |
113 | if (ctx.explist() != null) {
114 | print(" = ");
115 | print(ctx.explist());
116 | }
117 | }
118 |
119 | private void print(LuaJSSyntaxParser.GlobalVariableDeclarationContext ctx) {
120 | print(ctx.varlist());
121 | print(" = ");
122 | print(ctx.explist());
123 | }
124 |
125 | private void print(LuaJSSyntaxParser.AssginmentOperatorContext ctx) {
126 | print(ctx.var());
127 | print(" = ");
128 | print(ctx.var(), ctx.assignmentOperator().start, ctx.exp(), true);
129 | }
130 |
131 | private void print(LuaJSSyntaxParser.FunctionCallContext ctx) {
132 | print(ctx.var());
133 | print(ctx.nameAndArgs());
134 | }
135 |
136 | private void print(LuaJSSyntaxParser.LabelDeclarationContext ctx) {
137 | print("::");
138 | print(ctx.NAME());
139 | print("::");
140 | }
141 |
142 | private void print(LuaJSSyntaxParser.GotoContext ctx) {
143 | print("goto ");
144 | print(ctx.NAME());
145 | }
146 |
147 | private void print(LuaJSSyntaxParser.ReturnContext ctx) {
148 | LuaJSSyntaxParser.ExplistContext explist = ctx.explist();
149 |
150 | if (explist != null) {
151 | print("return ");
152 | print(explist);
153 | } else {
154 | print("return");
155 | }
156 | }
157 |
158 | private void print(LuaJSSyntaxParser.IfContext ctx) {
159 | print("if (");
160 | print(ctx.exp());
161 | print(") then ");
162 | printWithoutDoEnd(ctx.statement(0));
163 |
164 | if (ctx.statement().size() > 1) {
165 | print(" else ");
166 | printWithoutDoEnd(ctx.statement(1));
167 | }
168 |
169 | print(" end");
170 | }
171 |
172 | private void print(LuaJSSyntaxParser.WhileContext ctx) {
173 | print("while (");
174 | print(ctx.exp());
175 | print(") do ");
176 | onLoopStart();
177 | printWithoutDoEnd(ctx.statement());
178 | onLoopEnd();
179 | print(" end");
180 | }
181 |
182 | private void print(LuaJSSyntaxParser.DoWhileContext ctx) {
183 | print("repeat ");
184 | onLoopStart();
185 | printWithoutDoEnd(ctx.statement());
186 | onLoopEnd();
187 | print(" until (not (");
188 | print(ctx.exp());
189 | print("))");
190 | }
191 |
192 | private void print(LuaJSSyntaxParser.ForContext ctx) {
193 | if (printOptimizedLoop(ctx)) {
194 | return;
195 | }
196 |
197 | print("do ");
198 |
199 | if (ctx.init != null) {
200 | print(ctx.init);
201 | print("; ");
202 | }
203 |
204 | print("while ");
205 |
206 | if (ctx.exp() != null) {
207 | print("(");
208 | print(ctx.exp());
209 | print(")");
210 | } else {
211 | print("true");
212 | }
213 |
214 | print(" do ");
215 | onLoopStart();
216 | printWithoutDoEnd(ctx.body);
217 | onLoopEnd();
218 |
219 | if (ctx.after != null) {
220 | print(" ");
221 | print(ctx.after);
222 | print("; ");
223 | }
224 |
225 | print(" end");
226 | print(" end");
227 | }
228 |
229 | private boolean printOptimizedLoop(LuaJSSyntaxParser.ForContext ctx) {
230 | //for (let x = start_number; x (<=|>=|<|>) limit_number; x++|x+=step_number|x--|x-=step_number) statement
231 |
232 | if (!(ctx.init instanceof LuaJSSyntaxParser.LocalVariableDeclarationContext)) {
233 | return false;
234 | }
235 |
236 | LuaJSSyntaxParser.LocalVariableDeclarationContext var = (LuaJSSyntaxParser.LocalVariableDeclarationContext) ctx.init;
237 |
238 | if (var.namelist().NAME().size() != 1) {
239 | return false;
240 | }
241 |
242 | if (var.explist() == null || var.explist().exp().size() != 1) {
243 | return false;
244 | }
245 |
246 | if (!(var.explist().exp(0) instanceof LuaJSSyntaxParser.NumberLiteralContext)) {
247 | return false;
248 | }
249 |
250 | String name = var.namelist().NAME(0).getText();
251 | String start = var.explist().exp(0).getText();
252 |
253 | if (!(ctx.exp() instanceof LuaJSSyntaxParser.ComparisonOperatorContext)) {
254 | return false;
255 | }
256 |
257 | LuaJSSyntaxParser.ComparisonOperatorContext comp = (LuaJSSyntaxParser.ComparisonOperatorContext) ctx.exp();
258 |
259 | if (!(comp.exp(0) instanceof LuaJSSyntaxParser.VarExpressionContext)) {
260 | return false;
261 | }
262 |
263 | if (!(comp.exp(1) instanceof LuaJSSyntaxParser.NumberLiteralContext)) {
264 | return false;
265 | }
266 |
267 | if (!comp.exp(0).getText().equals(name)) {
268 | return false;
269 | }
270 |
271 | String op = comp.op.getText();
272 |
273 | if (!op.contains(">") && !op.contains("<")) {
274 | return false;
275 | }
276 |
277 | if (!op.contains("=")) {
278 | return false;
279 | }
280 |
281 | String stop = comp.exp(1).getText();
282 |
283 | String step;
284 |
285 | if (ctx.after instanceof LuaJSSyntaxParser.IncrementContext) {
286 | step = "1";
287 | } else if (ctx.after instanceof LuaJSSyntaxParser.DecrementContext) {
288 | step = "-1";
289 | } else {
290 | LuaJSSyntaxParser.AssginmentOperatorContext after = (LuaJSSyntaxParser.AssginmentOperatorContext) ctx.after;
291 |
292 | String assignOp = after.assignmentOperator().getText();
293 |
294 | if (!assignOp.equals("+=") && !assignOp.equals("-=")) {
295 | return false;
296 | }
297 |
298 | if (!after.var().getText().equals(name)) {
299 | return false;
300 | }
301 |
302 | if (!(after.exp() instanceof LuaJSSyntaxParser.NumberLiteralContext)) {
303 | return false;
304 | }
305 |
306 | String stepNumber = after.exp().getText();
307 |
308 | step = assignOp.equals("-=") ? "-" + stepNumber : stepNumber;
309 | }
310 |
311 | if (step == null) {
312 | return false;
313 | }
314 |
315 | print("for ");
316 | print(name);
317 | print(" = ");
318 | print(start);
319 | print(", ");
320 | print(stop);
321 | print(", ");
322 | print(step);
323 | print(" do ");
324 | onLoopStart();
325 | printWithoutDoEnd(ctx.body);
326 | onLoopEnd();
327 | print(" end");
328 |
329 | return true;
330 | }
331 |
332 | private void print(LuaJSSyntaxParser.ForInContext ctx) {
333 | print("for ");
334 | print(ctx.namelist());
335 | print(" in ");
336 | print(ctx.exp());
337 | print(" do ");
338 | onLoopStart();
339 | printWithoutDoEnd(ctx.statement());
340 | onLoopEnd();
341 | print(" end");
342 | }
343 |
344 | private void print(LuaJSSyntaxParser.ForOfContext ctx) {
345 | print("for ");
346 |
347 | if (ctx.NAME().size() > 1) {
348 | print(ctx.NAME(1));
349 | } else {
350 | print("_");
351 | }
352 |
353 | print(", ");
354 | print(ctx.NAME(0));
355 |
356 | print(" in ipairs(");
357 | print(ctx.exp());
358 | print(") do ");
359 | onLoopStart();
360 | printWithoutDoEnd(ctx.statement());
361 | onLoopEnd();
362 | print(" end");
363 | }
364 |
365 | private void print(LuaJSSyntaxParser.FunctionDeclarationContext ctx) {
366 | print("function ");
367 |
368 | for (int i = 0; i < ctx.funcname().NAME().size(); i++) {
369 | if (i > 0) {
370 | print(":");
371 | }
372 |
373 | print(ctx.funcname().NAME().get(i));
374 | }
375 |
376 | print("(");
377 |
378 | if (ctx.namelist() != null) {
379 | print(ctx.namelist());
380 | }
381 |
382 | print(") ");
383 | print(ctx.block().statement());
384 | print(" end");
385 | }
386 |
387 | private void print(LuaJSSyntaxParser.TryCatchContext ctx) {
388 | line(ctx.start);
389 | print("do local ");
390 |
391 | String suffix = this.sourceHash.substring(0, 8) + "_" + this.nextStatusVarIndex++;
392 |
393 | String resName = "res_" + suffix;
394 | String eName = "e_" + suffix;
395 |
396 | print(resName);
397 | print(", ");
398 | print(eName);
399 | print(" = pcall(function() ");
400 |
401 | print(ctx.block(0).statement());
402 |
403 | print(" end); if not ");
404 | print(resName);
405 | print(" then local ");
406 | print(ctx.NAME().getText());
407 | print(" = ");
408 | print(eName);
409 | print("; ");
410 |
411 | print(ctx.block(1).statement());
412 |
413 | print(" end end");
414 | }
415 |
416 | private void print(LuaJSSyntaxParser.ThrowContext ctx) {
417 | line(ctx.start);
418 | print("error(");
419 | print(ctx.exp());
420 | print(")");
421 | }
422 |
423 | private void print(LuaJSSyntaxParser.DecrementContext ctx) {
424 | print(ctx.var());
425 | print(" = ");
426 | print(ctx.var());
427 | print(" - 1");
428 | }
429 |
430 | private void print(LuaJSSyntaxParser.IncrementContext ctx) {
431 | print(ctx.var());
432 | print(" = ");
433 | print(ctx.var());
434 | print(" + 1");
435 | }
436 |
437 | // endregion
438 |
439 | // region Expressions
440 |
441 | private void print(LuaJSSyntaxParser.ParenthesisExpressionContext ctx) {
442 | print("(");
443 | print(ctx.exp());
444 | print(")");
445 | }
446 |
447 | private void print(LuaJSSyntaxParser.LiteralContext ctx) {
448 | print(ctx.getText());
449 | }
450 |
451 | private void print(LuaJSSyntaxParser.StringLiteralContext ctx) {
452 | StringBuilder builder = new StringBuilder();
453 |
454 | String text = ctx.getText();
455 |
456 | builder.append(text.charAt(0));
457 |
458 | for (int i = 1; i < text.length() - 1; i++) {
459 | if (text.charAt(i) == '\\' && text.charAt(i + 1) == 'u') {
460 | ++i;
461 | int a = Character.digit(text.charAt(++i), 16);
462 | int b = Character.digit(text.charAt(++i), 16);
463 | int c = Character.digit(text.charAt(++i), 16);
464 | int d = Character.digit(text.charAt(++i), 16);
465 | builder.append((char) ((a << 12) + (b << 8) + (c << 4) + d));
466 | } else {
467 | builder.append(text.charAt(i));
468 | }
469 | }
470 |
471 | builder.append(text.charAt(text.length() - 1));
472 |
473 | print(builder.toString());
474 | }
475 |
476 | private void print(LuaJSSyntaxParser.NumberLiteralContext ctx) {
477 | print(ctx.getText());
478 | }
479 |
480 | private void print(LuaJSSyntaxParser.FunctionLiteralContext ctx) {
481 | print("function (");
482 |
483 | if (ctx.namelist() != null) {
484 | print(ctx.namelist());
485 | }
486 |
487 | print(") ");
488 | print(ctx.block().statement());
489 | print(" end");
490 | }
491 |
492 | private void print(LuaJSSyntaxParser.ArrowFunctionLiteralContext ctx) {
493 | print("function (");
494 |
495 | if (ctx.namelist() != null) {
496 | print(ctx.namelist());
497 | } else if (ctx.NAME() != null) {
498 | print(ctx.NAME());
499 | }
500 |
501 | print(") ");
502 |
503 | if (ctx.exp() != null) {
504 | print("return ");
505 | print(ctx.exp());
506 | } else {
507 | print(ctx.block().statement());
508 | }
509 |
510 | print(" end");
511 | }
512 |
513 | private void print(LuaJSSyntaxParser.VarExpressionContext ctx) {
514 | print(ctx.var());
515 | }
516 |
517 | private void print(LuaJSSyntaxParser.TernaryOperatorContext ctx) {
518 | print("((");
519 | print(ctx.exp(0));
520 | print(") and (");
521 | print(ctx.exp(1));
522 | print(") or (");
523 | print(ctx.exp(2));
524 | print("))");
525 | }
526 |
527 | private void print(LuaJSSyntaxParser.FunctionCallExpressionContext ctx) {
528 | print(ctx.var());
529 | print(ctx.nameAndArgs());
530 | }
531 |
532 | private void print(LuaJSSyntaxParser.TableExpressionContext ctx) {
533 | print("{");
534 |
535 | if (ctx.table().entries() != null) {
536 | printCommaSeparated(ctx.table().entries().entry(), this::print);
537 | }
538 |
539 | print("}");
540 | }
541 |
542 | private void print(LuaJSSyntaxParser.ListExpressionContext ctx) {
543 | print("{");
544 |
545 | if (ctx.list().elements() != null) {
546 | printCommaSeparated(ctx.list().elements().exp(), this::print);
547 | }
548 |
549 | print("}");
550 | }
551 |
552 | private void print(LuaJSSyntaxParser.PowerOperatorContext ctx) {
553 | print(ctx.exp(0), ctx.op, ctx.exp(1));
554 | }
555 |
556 | private void print(LuaJSSyntaxParser.UnaryOperatorContext ctx) {
557 | String op = ctx.op.getText();
558 |
559 | if (op.equals("~")) {
560 | print("bit32.bnot(");
561 | print(ctx.exp());
562 | print(")");
563 | return;
564 | }
565 |
566 | if (op.equals("!")) {
567 | print("(not ");
568 | print(ctx.exp());
569 | print(")");
570 | return;
571 | }
572 |
573 | print(op);
574 | print(ctx.exp());
575 | }
576 |
577 | private void print(LuaJSSyntaxParser.MulDivModOperatorContext ctx) {
578 | print(ctx.exp(0), ctx.op, ctx.exp(1));
579 | }
580 |
581 | private void print(LuaJSSyntaxParser.AddSubOperatorContext ctx) {
582 | print(ctx.exp(0), ctx.op, ctx.exp(1));
583 | }
584 |
585 | private void print(LuaJSSyntaxParser.ConcatOperatorContext ctx) {
586 | print(ctx.exp(0), ctx.op, ctx.exp(1));
587 | }
588 |
589 | private void print(LuaJSSyntaxParser.ComparisonOperatorContext ctx) {
590 | print(ctx.exp(0), ctx.op, ctx.exp(1));
591 | }
592 |
593 | private void print(LuaJSSyntaxParser.AndOperatorContext ctx) {
594 | print(ctx.exp(0), ctx.op, ctx.exp(1));
595 | }
596 |
597 | private void print(LuaJSSyntaxParser.OrOperatorContext ctx) {
598 | print(ctx.exp(0), ctx.op, ctx.exp(1));
599 | }
600 |
601 | private void print(LuaJSSyntaxParser.BitwiseShiftContext ctx) {
602 | print(ctx.exp(0), ctx.op, ctx.exp(1));
603 | }
604 |
605 | private void print(LuaJSSyntaxParser.BitwiseAndContext ctx) {
606 | print(ctx.exp(0), ctx.op, ctx.exp(1));
607 | }
608 |
609 | private void print(LuaJSSyntaxParser.BitwiseXorContext ctx) {
610 | print(ctx.exp(0), ctx.op, ctx.exp(1));
611 | }
612 |
613 | private void print(LuaJSSyntaxParser.BitwiseOrContext ctx) {
614 | print(ctx.exp(0), ctx.op, ctx.exp(1));
615 | }
616 |
617 | // endregion
618 |
619 | private void print(List statements) {
620 | for (int i = 0; i < statements.size(); i++) {
621 | print(statements.get(i));
622 | print(";");
623 |
624 | if (i < statements.size() - 1) {
625 | print(" ");
626 | }
627 | }
628 | }
629 |
630 | private void print(LuaJSSyntaxParser.NamelistContext ctx) {
631 | printCommaSeparated(ctx.NAME(), this::print);
632 | }
633 |
634 | private void print(LuaJSSyntaxParser.VarlistContext ctx) {
635 | printCommaSeparated(ctx.var(), this::print);
636 | }
637 |
638 | private void print(LuaJSSyntaxParser.VarContext ctx) {
639 | int offset;
640 |
641 | if (ctx.NAME() != null) {
642 | print(ctx.NAME());
643 |
644 | offset = 0;
645 | } else {
646 | line(ctx.exp().start);
647 | print("(");
648 | print(ctx.exp());
649 | print(")");
650 | print(ctx.varSuffix(0));
651 |
652 | offset = 1;
653 | }
654 |
655 | for (int i = offset; i < ctx.varSuffix().size(); i++) {
656 | print(ctx.varSuffix(i));
657 | }
658 | }
659 |
660 | private void print(LuaJSSyntaxParser.VarSuffixContext ctx) {
661 | if (ctx.nameAndArgs() != null) {
662 | for (LuaJSSyntaxParser.NameAndArgsContext arg : ctx.nameAndArgs()) {
663 | print(arg);
664 | }
665 | }
666 |
667 | if (ctx.exp() != null) {
668 | line(ctx.exp().start);
669 | print("[");
670 | print(ctx.exp());
671 | print("]");
672 | } else {
673 | line(ctx.NAME().getSymbol());
674 | print(".");
675 | print(ctx.NAME());
676 | }
677 | }
678 |
679 | private void print(LuaJSSyntaxParser.NameAndArgsContext ctx) {
680 | line(ctx.start);
681 |
682 | if (ctx.NAME() != null) {
683 | print(":");
684 | print(ctx.NAME());
685 | }
686 |
687 | print(ctx.args());
688 | }
689 |
690 | private void print(LuaJSSyntaxParser.ArgsContext ctx) {
691 | line(ctx.start);
692 | print("(");
693 |
694 | if (ctx.explist() != null) {
695 | print(ctx.explist());
696 | }
697 |
698 | print(")");
699 | }
700 |
701 | private void print(LuaJSSyntaxParser.ExplistContext explist) {
702 | printCommaSeparated(explist.exp(), this::print);
703 | }
704 |
705 | private void print(LuaJSSyntaxParser.EntryContext ctx) {
706 | if (ctx.NAME() != null) {
707 | print(ctx.NAME());
708 | } else {
709 | print("[");
710 | print(ctx.key_expr().exp());
711 | print("]");
712 | }
713 |
714 | print("=");
715 | print(ctx.exp());
716 | }
717 |
718 | private void print(ParserRuleContext left, Token opToken, LuaJSSyntaxParser.ExpContext right) {
719 | print(left, opToken, right, false);
720 | }
721 |
722 | private void print(ParserRuleContext left, Token opToken, LuaJSSyntaxParser.ExpContext right, boolean compound) {
723 | String op = opToken.getText();
724 |
725 | if (compound) {
726 | op = op.substring(0, op.length() - 1);
727 | }
728 |
729 | String call = null;
730 |
731 | switch (op) {
732 | case "&":
733 | call = "bit32.band";
734 | break;
735 | case "|":
736 | call = "bit32.bor";
737 | break;
738 | case "^":
739 | call = "bit32.bxor";
740 | break;
741 | case "<<":
742 | call = "bit32.lshift";
743 | break;
744 | case ">>":
745 | call = "bit32.rshift";
746 | break;
747 | case "**":
748 | op = "^";
749 | break;
750 | case "&&":
751 | op = "and";
752 | break;
753 | case "||":
754 | op = "or";
755 | break;
756 | case "!=":
757 | op = "~=";
758 | break;
759 | }
760 |
761 | boolean wrapLeft = op.equals("..") && !isConcatOrString(left);
762 | boolean wrapRight = op.equals("..") && !isConcatOrString(right);
763 |
764 | if (call != null) {
765 | line(opToken);
766 | print(call);
767 | print("(");
768 | }
769 |
770 | if (wrapLeft) {
771 | print("tostring(");
772 | }
773 |
774 | if (left instanceof LuaJSSyntaxParser.VarContext) {
775 | print((LuaJSSyntaxParser.VarContext) left);
776 | } else if (left instanceof LuaJSSyntaxParser.ExpContext) {
777 | print((LuaJSSyntaxParser.ExpContext) left);
778 | }
779 |
780 | if (wrapLeft) {
781 | print(")");
782 | }
783 |
784 | if (call != null) {
785 | print(", ");
786 | print(right);
787 | print(")");
788 | } else {
789 | print(" ");
790 | line(opToken);
791 | print(op);
792 | print(" ");
793 |
794 | if (wrapRight) {
795 | print("tostring(");
796 | }
797 |
798 | print(right);
799 |
800 | if (wrapRight) {
801 | print(")");
802 | }
803 | }
804 |
805 | }
806 |
807 | private void print(Token token) {
808 | line(token);
809 | print(token.getText());
810 | }
811 |
812 | private void print(TerminalNode node) {
813 | print(node.getSymbol());
814 | }
815 |
816 | private void onLoopStart() {
817 | this.loopLevel++;
818 | }
819 |
820 | private void onLoopEnd() {
821 | if (this.usedLabels.remove(this.loopLevel)) {
822 | print("::");
823 | print(getContinueLabel());
824 | print("::;");
825 | }
826 |
827 | this.loopLevel--;
828 | }
829 |
830 | private String getContinueLabel() {
831 | return "continue_" + this.sourceHash.substring(0, 8) + "_" + this.loopLevel;
832 | }
833 |
834 | // Utils
835 |
836 | private void printCommaSeparated(@NonNull List list, @NonNull Consumer printer) {
837 | for (int i = 0; i < list.size(); i++) {
838 | printer.accept(list.get(i));
839 |
840 | if (i < list.size() - 1) {
841 | print(", ");
842 | }
843 | }
844 | }
845 |
846 | private static boolean isConcatOrString(ParserRuleContext exp) {
847 | return exp instanceof LuaJSSyntaxParser.ConcatOperatorContext || exp instanceof LuaJSSyntaxParser.StringLiteralContext;
848 | }
849 |
850 | // Dynamic dispatching
851 |
852 | private void print(LuaJSSyntaxParser.StatementContext ctx) {
853 | line(ctx.start);
854 | dispatch(ctx, LuaJSSyntaxParser.StatementContext.class);
855 | }
856 |
857 | private void print(LuaJSSyntaxParser.ExpContext ctx) {
858 | line(ctx.start);
859 | dispatch(ctx, LuaJSSyntaxParser.ExpContext.class);
860 | }
861 |
862 | private void dispatch(T argument, Class baseClass) {
863 | try {
864 | //noinspection JavaReflectionMemberAccess
865 | Method method = getClass().getDeclaredMethod("print", argument.getClass());
866 |
867 | if (method.getParameterTypes()[0] == baseClass) {
868 | throw new IllegalArgumentException("Invalid input");
869 | }
870 |
871 | method.invoke(this, argument);
872 | } catch (InvocationTargetException e) {
873 | if (e.getTargetException() instanceof RuntimeException) {
874 | throw (RuntimeException)e.getTargetException();
875 | } else {
876 | throw new RuntimeException(e);
877 | }
878 | } catch (ReflectiveOperationException e) {
879 | throw new RuntimeException(e);
880 | }
881 | }
882 |
883 | }
884 |
--------------------------------------------------------------------------------