├── COMPARISON.md ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── antlr4 │ └── me │ │ └── saharnooby │ │ └── luajssyntax │ │ └── LuaJSSyntax.g4 └── java │ └── me │ └── saharnooby │ └── luajssyntax │ ├── LuaJSToLua.java │ ├── LuaJSToLuaConverter.java │ ├── Main.java │ ├── exception │ └── InvalidSyntaxException.java │ └── util │ ├── HashUtil.java │ └── Printer.java └── test ├── java └── me │ └── saharnooby │ └── luajssyntax │ ├── ConverterTest.java │ ├── ErrorTest.java │ ├── OptimizationTest.java │ ├── TestGenerator.java │ └── util │ └── HashUtilTest.java └── resources ├── me └── saharnooby │ └── luajssyntax │ ├── ArrowFunctionLiteral.txt │ ├── Bitwise.txt │ ├── Break.txt │ ├── ChainCalls.txt │ ├── Comparison.txt │ ├── Compound.txt │ ├── Concat.txt │ ├── Continue.txt │ ├── DoWhile.txt │ ├── For.txt │ ├── ForIn.txt │ ├── ForOf.txt │ ├── ForOptimized.txt │ ├── FunctionLiteral.txt │ ├── Globals.txt │ ├── If.txt │ ├── Increment.txt │ ├── Label.txt │ ├── Lists.txt │ ├── Literals.txt │ ├── Locals.txt │ ├── Logic.txt │ ├── Math.txt │ ├── Numbers.txt │ ├── OOP.txt │ ├── Parenthesis.txt │ ├── Power.txt │ ├── Priorities.txt │ ├── PrioritiesBitwise.txt │ ├── PrioritiesUnary.txt │ ├── Require.txt │ ├── Return.txt │ ├── Strings.txt │ ├── Tables.txt │ ├── Ternary.txt │ ├── Throw.txt │ ├── TryCatch.txt │ └── Unary.txt └── test_module.lua /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 | 7 | 8 | 45 | 82 | 83 |
LuaJSLua (converted and formatted)
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 | 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 |
84 | 85 | ## Functions 86 | 87 | 88 | 89 | 113 | 137 | 138 |
LuaJSLua (converted and formatted)
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 | 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 |
139 | 140 | ## Conditions and loops 141 | 142 | 143 | 144 | 217 | 290 | 291 |
LuaJSLua (converted and formatted)
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 | 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 |
292 | 293 | ## Exceptions 294 | 295 | 296 | 297 | 314 | 331 | 332 |
LuaJSLua (converted and formatted)
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 | 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 |
333 | 334 | ## Operators 335 | 336 | 337 | 338 | 378 | 418 | 419 |
LuaJSLua (converted and formatted)
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 | 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 |
420 | 421 | ## OOP 422 | 423 | 424 | 425 | 445 | 465 | 466 |
LuaJSLua (converted and formatted)
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 | 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 |
-------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 27 | 28 | 48 | 68 | 69 |
LuaJSLua
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 | 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 |
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. -------------------------------------------------------------------------------- /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/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 | ; -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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 --------------------------------------------------------------------------------