├── .github └── workflows │ └── jarbuild.yml ├── .hgignore ├── .idea ├── artifacts │ └── unluac_jar.xml └── vcs.xml ├── README.md ├── authors.txt ├── license.txt ├── out └── .gitkeep ├── src ├── META-INF │ └── MANIFEST.MF └── unluac │ ├── Configuration.java │ ├── Main.java │ ├── Version.java │ ├── assemble │ ├── Assembler.java │ ├── AssemblerException.java │ ├── Directive.java │ └── Tokenizer.java │ ├── decompile │ ├── AssertionManager.java │ ├── Code.java │ ├── CodeExtract.java │ ├── Constant.java │ ├── ControlFlowHandler.java │ ├── Declaration.java │ ├── Decompiler.java │ ├── Disassembler.java │ ├── Function.java │ ├── Op.java │ ├── OpcodeMap.java │ ├── OperandFormat.java │ ├── Output.java │ ├── OutputProvider.java │ ├── Registers.java │ ├── Upvalues.java │ ├── Validator.java │ ├── VariableFinder.java │ ├── Walker.java │ ├── block │ │ ├── AlwaysLoop.java │ │ ├── Block.java │ │ ├── Break.java │ │ ├── ContainerBlock.java │ │ ├── DoEndBlock.java │ │ ├── ElseEndBlock.java │ │ ├── ForBlock.java │ │ ├── ForBlock50.java │ │ ├── ForBlock51.java │ │ ├── Goto.java │ │ ├── IfThenElseBlock.java │ │ ├── IfThenEndBlock.java │ │ ├── OnceLoop.java │ │ ├── OuterBlock.java │ │ ├── RepeatBlock.java │ │ ├── SetBlock.java │ │ ├── TForBlock.java │ │ └── WhileBlock.java │ ├── condition │ │ ├── AndCondition.java │ │ ├── BinaryCondition.java │ │ ├── Condition.java │ │ ├── ConstantCondition.java │ │ ├── FinalSetCondition.java │ │ ├── NotCondition.java │ │ ├── OrCondition.java │ │ └── TestCondition.java │ ├── expression │ │ ├── BinaryExpression.java │ │ ├── ClosureExpression.java │ │ ├── ConstantExpression.java │ │ ├── Expression.java │ │ ├── FunctionCall.java │ │ ├── GlobalExpression.java │ │ ├── LocalVariable.java │ │ ├── TableLiteral.java │ │ ├── TableReference.java │ │ ├── UnaryExpression.java │ │ ├── UpvalueExpression.java │ │ └── Vararg.java │ ├── operation │ │ ├── CallOperation.java │ │ ├── GlobalSet.java │ │ ├── LoadNil.java │ │ ├── MultipleRegisterSet.java │ │ ├── Operation.java │ │ ├── RegisterSet.java │ │ ├── ReturnOperation.java │ │ ├── TableSet.java │ │ └── UpvalueSet.java │ ├── statement │ │ ├── Assignment.java │ │ ├── Declare.java │ │ ├── FunctionCallStatement.java │ │ ├── Label.java │ │ ├── Return.java │ │ └── Statement.java │ └── target │ │ ├── GlobalTarget.java │ │ ├── TableTarget.java │ │ ├── Target.java │ │ ├── UpvalueTarget.java │ │ └── VariableTarget.java │ ├── parse │ ├── BHeader.java │ ├── BInteger.java │ ├── BIntegerType.java │ ├── BList.java │ ├── BObject.java │ ├── BObjectType.java │ ├── LAbsLineInfo.java │ ├── LAbsLineInfoType.java │ ├── LBoolean.java │ ├── LBooleanType.java │ ├── LConstantType.java │ ├── LFunction.java │ ├── LFunctionType.java │ ├── LHeader.java │ ├── LHeaderType.java │ ├── LLocal.java │ ├── LLocalType.java │ ├── LNil.java │ ├── LNumber.java │ ├── LNumberType.java │ ├── LObject.java │ ├── LSourceLines.java │ ├── LString.java │ ├── LStringType.java │ ├── LUpvalue.java │ └── LUpvalueType.java │ ├── test │ ├── Compare.java │ ├── LuaC.java │ ├── LuaSpec.java │ ├── RunExtendedTests.java │ ├── RunTest.java │ ├── RunTests.java │ ├── TestFiles.java │ ├── TestReport.java │ ├── TestResult.java │ ├── TestSuite.java │ └── UnluacSpec.java │ └── util │ ├── Stack.java │ └── StringUtils.java ├── test └── src │ ├── 51_adjust02.lua │ ├── 51_adjust03.lua │ ├── 51_ellipsis.lua │ ├── 51_ellipsis02.lua │ ├── 51_expression.lua │ ├── 51_expression03.lua │ ├── 51_expression2.lua │ ├── 51_method03.lua │ ├── 51_string03.lua │ ├── 52_goto01.lua │ ├── 52_goto02.lua │ ├── 52_goto03.lua │ ├── 52_loadkx01.lua │ ├── 53_expression.lua │ ├── 53_expression02.lua │ ├── 54_tbc01.lua │ ├── adjust01.lua │ ├── adjust04.lua │ ├── adjust05.lua │ ├── adjust06.lua │ ├── always01.lua │ ├── always02.lua │ ├── always03.lua │ ├── always04.lua │ ├── assign.lua │ ├── booleanassign01.lua │ ├── booleanassign02.lua │ ├── booleanassign03.lua │ ├── booleanassign04.lua │ ├── booleanassign05.lua │ ├── booleanassign06.lua │ ├── booleanassign07.lua │ ├── booleanassign08.lua │ ├── booleanassign09.lua │ ├── booleanassign10.lua │ ├── booleanassign11.lua │ ├── booleanassign12.lua │ ├── booleanassign13.lua │ ├── booleanassign14.lua │ ├── booleanassign15.lua │ ├── booleanassign16.lua │ ├── booleanassign17.lua │ ├── booleanassign18.lua │ ├── booleanassign19.lua │ ├── booleanassign20.lua │ ├── booleanassign21.lua │ ├── booleanassign22.lua │ ├── booleanassign23.lua │ ├── booleanassign24.lua │ ├── booleanassign25.lua │ ├── booleanassign26.lua │ ├── booleanassign27.lua │ ├── booleanassign28.lua │ ├── booleanexpression01.lua │ ├── booleanexpression02.lua │ ├── booleanexpression03.lua │ ├── booleanexpression04.lua │ ├── booleanexpression05.lua │ ├── booleanexpression06.lua │ ├── booleanexpression07.lua │ ├── booleanexpression08.lua │ ├── booleanexpression09.lua │ ├── booleanexpression10.lua │ ├── booleanmultiassign01.lua │ ├── booleanmultiassign02.lua │ ├── booleanselfassign01.lua │ ├── break01.lua │ ├── break02.lua │ ├── break03.lua │ ├── break04.lua │ ├── break05.lua │ ├── break06.lua │ ├── break07.lua │ ├── break08.lua │ ├── break09.lua │ ├── break10.lua │ ├── close01.lua │ ├── close02.lua │ ├── close03.lua │ ├── close04.lua │ ├── closure.lua │ ├── combinebassign01.lua │ ├── combinebassign02.lua │ ├── combinebassign03.lua │ ├── combinebassign04.lua │ ├── combinebassign05.lua │ ├── combinebassign07.lua │ ├── combinebexpression01.lua │ ├── combinebexpression02.lua │ ├── combinebexpression03.lua │ ├── combinebexpression04.lua │ ├── combinebexpression05.lua │ ├── combinebexpression06.lua │ ├── combinebexpression07.lua │ ├── compare01.lua │ ├── compareassign01.lua │ ├── compareassign02.lua │ ├── compareexpression.lua │ ├── compareexpression02.lua │ ├── compareorder01.lua │ ├── compareorder02.lua │ ├── compareorder03.lua │ ├── compareorder04.lua │ ├── compareorder05.lua │ ├── compareorder06.lua │ ├── compareorder07.lua │ ├── compareorder08.lua │ ├── complexassign01.lua │ ├── complexassign02.lua │ ├── complexassign03.lua │ ├── condition.lua │ ├── condition02.lua │ ├── condition03.lua │ ├── control01.lua │ ├── control02.lua │ ├── control03.lua │ ├── control04.lua │ ├── control05.lua │ ├── control06.lua │ ├── control07.lua │ ├── declare.lua │ ├── declare02.lua │ ├── declare03.lua │ ├── declare04.lua │ ├── declare05.lua │ ├── doend01.lua │ ├── doend02.lua │ ├── doend03.lua │ ├── doend04.lua │ ├── doend05.lua │ ├── doend06.lua │ ├── doend07.lua │ ├── doend08.lua │ ├── ellipsis03.lua │ ├── else01.lua │ ├── else02.lua │ ├── else03.lua │ ├── else04.lua │ ├── else05.lua │ ├── else06.lua │ ├── else07.lua │ ├── expression.lua │ ├── expression02.lua │ ├── final01.lua │ ├── final02.lua │ ├── functioncall.lua │ ├── if01.lua │ ├── if02.lua │ ├── if03.lua │ ├── if04.lua │ ├── if05.lua │ ├── if06.lua │ ├── if07.lua │ ├── ifthen.lua │ ├── ifthenelse.lua │ ├── inlineconstant01.lua │ ├── inlinefunction01.lua │ ├── inlinefunction02.lua │ ├── literal.lua │ ├── literallist.lua │ ├── localbooleanassign.lua │ ├── localfunction01.lua │ ├── localfunction02.lua │ ├── localfunction03.lua │ ├── localfunction04.lua │ ├── loop01.lua │ ├── loop02.lua │ ├── loop03.lua │ ├── loop04.lua │ ├── method01.lua │ ├── method02.lua │ ├── multiassign.lua │ ├── multiassign02.lua │ ├── multiassign03.lua │ ├── multiassign04.lua │ ├── multiassign05.lua │ ├── multiassign06.lua │ ├── multiliteraltarget.lua │ ├── nestedif.lua │ ├── nestedif02.lua │ ├── number01.lua │ ├── number02.lua │ ├── number03.lua │ ├── once01.lua │ ├── once02.lua │ ├── once03.lua │ ├── once04.lua │ ├── once05.lua │ ├── repeat.lua │ ├── repeat02.lua │ ├── repeat03.lua │ ├── report01_full.lua │ ├── report01a.lua │ ├── report01b.lua │ ├── report01c.lua │ ├── report01d.lua │ ├── report02.lua │ ├── report02a.lua │ ├── report02b.lua │ ├── report02c.lua │ ├── report02d.lua │ ├── report02e.lua │ ├── report03.lua │ ├── report04.lua │ ├── report05.lua │ ├── scope02.lua │ ├── scope03.lua │ ├── self01.lua │ ├── string01.lua │ ├── string02.lua │ ├── string04.lua │ ├── table01.lua │ ├── table02.lua │ ├── table03.lua │ ├── table06.lua │ ├── table07.lua │ ├── unused01.lua │ ├── upvalue01.lua │ ├── upvalue02.lua │ ├── upvalue03.lua │ ├── upvalue04.lua │ ├── upvalue05.lua │ ├── while.lua │ ├── while02.lua │ ├── while03.lua │ ├── while04.lua │ ├── while05.lua │ ├── while06.lua │ └── while07.lua └── unluac.iml /.github/workflows/jarbuild.yml: -------------------------------------------------------------------------------- 1 | name: unluac Nightly Build 2 | on: push 3 | 4 | jobs: 5 | jarbuild: 6 | name: Build Jar 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Get commit info 11 | id: vars 12 | shell: bash 13 | run: | 14 | echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" 15 | echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" 16 | - name: Setup JDK 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: '9.0.4' 20 | - name: Build 21 | run: | 22 | mkdir build 23 | javac -d build -sourcepath src src/unluac/*.java 24 | jar -cfm build/unluac.jar src/META-INF/MANIFEST.MF -C build . 25 | - name: Upload 26 | uses: actions/upload-artifact@v2 27 | with: 28 | name: unluac-${{ steps.vars.outputs.branch }}-${{ steps.vars.outputs.sha_short }}.jar 29 | path: build/unluac.jar -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | .gradle 3 | bin 4 | build 5 | luac 6 | test/working 7 | *.orig 8 | *.rej 9 | -------------------------------------------------------------------------------- /.idea/artifacts/unluac_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/ 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # unluac for MiWifi 2 | 3 | ![unluac Nightly Build](https://github.com/NyaMisty/unluac_miwifi/workflows/unluac%20Nightly%20Build/badge.svg) 4 | 5 | Xiaomi Router encrypts its lua files in models AC2100, AX3600, R4. 6 | 7 | They modified the Lua interpreter, which introduces string encryption, shifted opcode order, and customized opcodes. 8 | 9 | This unluac is imported from upstream unluac at 2020.6.14 10 | 11 | Credits: 12 | - @lvqier for the initial port from https://github.com/lvqier/unluac 13 | - unluac team for a brilliant luac decompiler 14 | -------------------------------------------------------------------------------- /authors.txt: -------------------------------------------------------------------------------- 1 | tehtmi -- main developer 2 | Thomas Klaeger -- added support for Lua 5.0 3 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2016 tehtmi 2 | With Portions Copyright (c) 2014 Thomas Klaeger 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /out/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaMisty/unluac_miwifi/20a679402a409b6c3829e7fcba96cf5c49cffd08/out/.gitkeep -------------------------------------------------------------------------------- /src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: unluac.Main 3 | 4 | -------------------------------------------------------------------------------- /src/unluac/Configuration.java: -------------------------------------------------------------------------------- 1 | package unluac; 2 | 3 | public class Configuration { 4 | 5 | public enum Mode { 6 | DECOMPILE, 7 | DISASSEMBLE, 8 | ASSEMBLE, 9 | } 10 | 11 | public enum VariableMode { 12 | DEFAULT, 13 | FINDER, 14 | } 15 | 16 | public boolean rawstring = false; 17 | public Mode mode = Mode.DECOMPILE; 18 | public VariableMode variable = VariableMode.DEFAULT; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/unluac/assemble/AssemblerException.java: -------------------------------------------------------------------------------- 1 | package unluac.assemble; 2 | 3 | @SuppressWarnings("serial") 4 | public class AssemblerException extends Exception { 5 | 6 | AssemblerException(String msg) { 7 | super(msg); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/unluac/assemble/Tokenizer.java: -------------------------------------------------------------------------------- 1 | package unluac.assemble; 2 | 3 | import java.io.IOException; 4 | import java.io.Reader; 5 | 6 | public class Tokenizer { 7 | 8 | private StringBuilder b; 9 | private Reader r; 10 | 11 | public Tokenizer(Reader r) { 12 | this.r = r; 13 | b = new StringBuilder(); 14 | } 15 | 16 | public String next() throws IOException { 17 | b.setLength(0); 18 | 19 | boolean inToken = false; 20 | boolean inString = false; 21 | boolean isLPrefix = false; 22 | 23 | for(;;) { 24 | int code = r.read(); 25 | if(code == -1) break; 26 | char c = (char)code; 27 | //if(c == '\n') System.out.println("line"); 28 | if(Character.isWhitespace(c)) { 29 | if(inToken && !inString) { 30 | break; 31 | } else if(inString) { 32 | b.append(c); 33 | } 34 | } else if(inString && c == '"') { 35 | b.append(c); 36 | break; 37 | } else { 38 | if((!inToken || isLPrefix) && c == '"') { 39 | inString = true; 40 | } else if(!inToken && c == 'L') { 41 | isLPrefix = true; 42 | } else { 43 | isLPrefix = false; 44 | } 45 | inToken = true; 46 | b.append(c); 47 | } 48 | } 49 | 50 | //System.out.println("token: <" + b.toString() + ">"); 51 | 52 | if(b.length() == 0) { 53 | return null; 54 | } else { 55 | return b.toString(); 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/unluac/decompile/AssertionManager.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile; 2 | 3 | public class AssertionManager { 4 | 5 | public static boolean assertCritical(boolean condition, String message) { 6 | if(condition) { 7 | // okay 8 | } else { 9 | critical(message); 10 | } 11 | return condition; 12 | } 13 | 14 | public static void critical(String message) { 15 | throw new IllegalStateException(message); 16 | } 17 | 18 | //static only 19 | private AssertionManager() {} 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/unluac/decompile/CodeExtract.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile; 2 | 3 | import unluac.Version; 4 | 5 | public class CodeExtract { 6 | 7 | public static class Field { 8 | 9 | public Field(int size, int shift) { 10 | this(size, shift, 0); 11 | } 12 | 13 | public Field(int size, int shift, int offset) { 14 | this.size = size; 15 | this.shift = shift; 16 | this.mask = size_to_mask(size); 17 | this.offset = offset; 18 | } 19 | 20 | public int extract(int codepoint) { 21 | return ((codepoint >>> shift) & mask) - offset; 22 | } 23 | 24 | public boolean check(int x) { 25 | return ((x + offset) & ~mask) == 0; 26 | } 27 | 28 | public int encode(int x) { 29 | return (x + offset) << shift; 30 | } 31 | 32 | public int clear(int codepoint) { 33 | return codepoint & ~(mask << shift); 34 | } 35 | 36 | public int max() { 37 | return mask - offset; 38 | } 39 | 40 | public final int size; 41 | private final int shift; 42 | private final int mask; 43 | private final int offset; 44 | 45 | } 46 | 47 | public CodeExtract(Version version, int sizeOp, int sizeA, int sizeB, int sizeC) { 48 | switch(version.instructionformat.get()) { 49 | case LUA50: 50 | op = new Field(sizeOp, 0); 51 | A = new Field(sizeA, sizeB + sizeC + sizeOp); 52 | B = new Field(sizeB, sizeB + sizeOp); 53 | C = new Field(sizeC, sizeOp); 54 | k = null; 55 | Ax = null; 56 | sJ = null; 57 | Bx = new Field(sizeB + sizeC, sizeOp); 58 | sBx = new Field(sizeB + sizeC, sizeOp, size_to_mask(sizeB + sizeC) / 2); 59 | x = new Field(32, 0); 60 | break; 61 | case LUA51: 62 | op = new Field(6, 0); 63 | A = new Field(8, 6); 64 | B = new Field(9, 23); 65 | C = new Field(9, 14); 66 | k = null; 67 | Ax = new Field(26, 6); 68 | sJ = null; 69 | Bx = new Field(18, 14); 70 | sBx = new Field(18, 14, 131071); 71 | x = new Field(32, 0); 72 | break; 73 | case LUA54: 74 | op = new Field(7, 0); 75 | A = new Field(8, 7); 76 | B = new Field(8, 16); 77 | C = new Field(8, 24); 78 | k = new Field(1, 15); 79 | Ax = new Field(25, 7); 80 | sJ = new Field(25, 7, (1 << 24) - 1); 81 | Bx = new Field(17, 15); 82 | sBx = new Field(17, 15, (1 << 16) - 1); 83 | x = new Field(32, 0); 84 | break; 85 | default: 86 | throw new IllegalStateException(); 87 | } 88 | Integer rk_offset = version.rkoffset.get(); 89 | this.rk_offset = (rk_offset == null) ? -1 : rk_offset; 90 | } 91 | 92 | public boolean is_k(int field) { 93 | return field >= rk_offset; 94 | } 95 | 96 | public int get_k(int field) { 97 | return field - rk_offset; 98 | } 99 | 100 | public int encode_k(int constant) { 101 | return constant + rk_offset; 102 | } 103 | 104 | public final Field op; 105 | public final Field A; 106 | public final Field B; 107 | public final Field C; 108 | public final Field k; 109 | public final Field Ax; 110 | public final Field sJ; 111 | public final Field Bx; 112 | public final Field sBx; 113 | public final Field x; 114 | 115 | private final int rk_offset; 116 | 117 | private static int size_to_mask(int size) { 118 | return (int)((1L << size) - 1); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/unluac/decompile/Declaration.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile; 2 | 3 | import unluac.parse.LLocal; 4 | 5 | public class Declaration { 6 | 7 | public final String name; 8 | public final int begin; 9 | public final int end; 10 | public int register; 11 | public boolean tbc; 12 | 13 | /** 14 | * Whether this is an invisible for-loop book-keeping variable. 15 | */ 16 | public boolean forLoop = false; 17 | 18 | /** 19 | * Whether this is an explicit for-loop declared variable. 20 | */ 21 | public boolean forLoopExplicit = false; 22 | 23 | public Declaration(LLocal local, Code code) { 24 | int adjust = 0; 25 | if(local.start >= 1) { 26 | Op op = code.op(local.start); 27 | if(op == Op.MMBIN || op == Op.MMBINI || op == Op.MMBINK || op == Op.EXTRAARG) { 28 | adjust--; 29 | } 30 | } 31 | this.name = local.toString(); 32 | this.begin = local.start + adjust; 33 | this.end = local.end; 34 | this.tbc = false; 35 | } 36 | 37 | public Declaration(String name, int begin, int end) { 38 | this.name = name; 39 | this.begin = begin; 40 | this.end = end; 41 | } 42 | 43 | public boolean isSplitBy(int begin, int end) { 44 | return (begin <= this.begin && this.begin < end && end <= this.end) 45 | || (begin <= this.end && this.end < end - 1 && this.begin < begin); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/unluac/decompile/Function.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile; 2 | 3 | import unluac.Version; 4 | import unluac.decompile.expression.ConstantExpression; 5 | import unluac.decompile.expression.GlobalExpression; 6 | import unluac.parse.LFunction; 7 | 8 | public class Function { 9 | 10 | private Version version; 11 | private Constant[] constants; 12 | private final CodeExtract extract; 13 | 14 | public Function(LFunction function) { 15 | version = function.header.version; 16 | constants = new Constant[function.constants.length]; 17 | for(int i = 0; i < constants.length; i++) { 18 | constants[i] = new Constant(function.constants[i]); 19 | } 20 | extract = function.header.extractor; 21 | } 22 | 23 | public boolean isConstant(int register) { 24 | return extract.is_k(register); 25 | } 26 | 27 | public int constantIndex(int register) { 28 | return extract.get_k(register); 29 | } 30 | 31 | public ConstantExpression getGlobalName(int constantIndex) { 32 | if(!constants[constantIndex].isIdentifier(version)) throw new IllegalStateException(); 33 | return getConstantExpression(constantIndex); 34 | } 35 | 36 | public ConstantExpression getConstantExpression(int constantIndex) { 37 | Constant constant = constants[constantIndex]; 38 | return new ConstantExpression(constant, constant.isIdentifier(version), constantIndex); 39 | } 40 | 41 | public GlobalExpression getGlobalExpression(int constantIndex) { 42 | return new GlobalExpression(getGlobalName(constantIndex), constantIndex); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/unluac/decompile/OperandFormat.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile; 2 | 3 | public enum OperandFormat { 4 | A(Field.A, Format.RAW), 5 | AR(Field.A, Format.REGISTER), 6 | AU(Field.A, Format.UPVALUE), 7 | B(Field.B, Format.RAW), 8 | BR(Field.B, Format.REGISTER), 9 | BRK(Field.B, Format.REGISTER_K), 10 | BK(Field.B, Format.CONSTANT), 11 | BKS(Field.B, Format.CONSTANT_STRING), 12 | BI(Field.B, Format.IMMEDIATE_INTEGER), 13 | BsI(Field.B, Format.IMMEDIATE_SIGNED_INTEGER), 14 | BU(Field.B, Format.UPVALUE), 15 | C(Field.C, Format.RAW), 16 | CR(Field.C, Format.REGISTER), 17 | CRK(Field.C, Format.REGISTER_K), 18 | CRK54(Field.C, Format.REGISTER_K54), 19 | CK(Field.C, Format.CONSTANT), 20 | CKI(Field.C, Format.CONSTANT_INTEGER), 21 | CKS(Field.C, Format.CONSTANT_STRING), 22 | CI(Field.C, Format.IMMEDIATE_INTEGER), 23 | CsI(Field.C, Format.IMMEDIATE_SIGNED_INTEGER), 24 | k(Field.k, Format.RAW), 25 | Ax(Field.Ax, Format.RAW), 26 | sJ(Field.sJ, Format.JUMP), 27 | Bx(Field.Bx, Format.RAW), 28 | BxK(Field.Bx, Format.CONSTANT), 29 | BxJ(Field.Bx, Format.JUMP), 30 | BxJ1(Field.Bx, Format.JUMP, 1), 31 | BxJn(Field.Bx, Format.JUMP_NEGATIVE), 32 | BxF(Field.Bx, Format.FUNCTION), 33 | sBxJ(Field.sBx, Format.JUMP), 34 | sBxI(Field.sBx, Format.IMMEDIATE_INTEGER), 35 | sBxF(Field.sBx, Format.IMMEDIATE_FLOAT), 36 | x(Field.x, Format.RAW); 37 | 38 | public final Field field; 39 | public final Format format; 40 | public final int offset; 41 | 42 | private OperandFormat(Field field, Format format) { 43 | this(field, format, 0); 44 | } 45 | 46 | private OperandFormat(Field field, Format format, int offset) { 47 | this.field = field; 48 | this.format = format; 49 | this.offset = offset; 50 | } 51 | 52 | public static enum Field { 53 | A, 54 | B, 55 | C, 56 | k, 57 | Ax, 58 | sJ, 59 | Bx, 60 | sBx, 61 | x, 62 | } 63 | 64 | public static enum Format { 65 | RAW, 66 | REGISTER, 67 | UPVALUE, 68 | REGISTER_K, 69 | REGISTER_K54, 70 | CONSTANT, 71 | CONSTANT_INTEGER, 72 | CONSTANT_STRING, 73 | FUNCTION, 74 | IMMEDIATE_INTEGER, 75 | IMMEDIATE_SIGNED_INTEGER, 76 | IMMEDIATE_FLOAT, 77 | JUMP, 78 | JUMP_NEGATIVE, 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/unluac/decompile/Output.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile; 2 | 3 | public class Output { 4 | 5 | private OutputProvider out; 6 | private int indentationLevel = 0; 7 | private int position = 0; 8 | 9 | public Output() { 10 | this(new OutputProvider() { 11 | 12 | @Override 13 | public void print(String s) { 14 | System.out.print(s); 15 | } 16 | 17 | @Override 18 | public void print(byte b) { 19 | System.out.write(b); 20 | } 21 | 22 | @Override 23 | public void println() { 24 | System.out.println(); 25 | } 26 | 27 | }); 28 | } 29 | 30 | public Output(OutputProvider out) { 31 | this.out = out; 32 | } 33 | 34 | public void indent() { 35 | indentationLevel += 2; 36 | } 37 | 38 | public void dedent() { 39 | indentationLevel -= 2; 40 | } 41 | 42 | public int getIndentationLevel() { 43 | return indentationLevel; 44 | } 45 | 46 | public int getPosition() { 47 | return position; 48 | } 49 | 50 | public void setIndentationLevel(int indentationLevel) { 51 | this.indentationLevel = indentationLevel; 52 | } 53 | 54 | private void start() { 55 | if(position == 0) { 56 | for(int i = indentationLevel; i != 0; i--) { 57 | out.print(" "); 58 | position++; 59 | } 60 | } 61 | } 62 | 63 | public void print(String s) { 64 | start(); 65 | out.print(s); 66 | position += s.length(); 67 | } 68 | 69 | public void print(byte b) { 70 | start(); 71 | out.print(b); 72 | position += 1; 73 | } 74 | 75 | public void println() { 76 | start(); 77 | out.println(); 78 | position = 0; 79 | } 80 | 81 | public void println(String s) { 82 | print(s); 83 | println(); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/unluac/decompile/OutputProvider.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile; 2 | 3 | public interface OutputProvider { 4 | 5 | public void print(String s); 6 | 7 | public void print(byte b); 8 | 9 | public void println(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/unluac/decompile/Upvalues.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile; 2 | 3 | import unluac.decompile.expression.UpvalueExpression; 4 | import unluac.parse.LFunction; 5 | import unluac.parse.LUpvalue; 6 | 7 | public class Upvalues { 8 | 9 | private final LUpvalue[] upvalues; 10 | 11 | public Upvalues(LFunction func, Declaration[] parentDecls, int line) { 12 | this.upvalues = func.upvalues; 13 | for(LUpvalue upvalue : upvalues) { 14 | if(upvalue.name == null || upvalue.name.isEmpty()) { 15 | if(upvalue.instack) { 16 | if(parentDecls != null) { 17 | for(Declaration decl : parentDecls) { 18 | if(decl.register == upvalue.idx && line >= decl.begin && line < decl.end) { 19 | upvalue.name = decl.name; 20 | break; 21 | } 22 | } 23 | } 24 | } else { 25 | LUpvalue[] parentvals = func.parent.upvalues; 26 | if(upvalue.idx >= 0 && upvalue.idx < parentvals.length) { 27 | upvalue.name = parentvals[upvalue.idx].name; 28 | } 29 | } 30 | } 31 | } 32 | } 33 | 34 | public String getName(int index) { 35 | if(index < upvalues.length && upvalues[index].name != null && !upvalues[index].name.isEmpty()) { 36 | return upvalues[index].name; 37 | } else { 38 | //TODO: SET ERROR 39 | return "_UPVALUE" + index + "_"; 40 | } 41 | } 42 | 43 | public UpvalueExpression getExpression(int index) { 44 | return new UpvalueExpression(getName(index)); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/unluac/decompile/Validator.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile; 2 | 3 | public class Validator { 4 | 5 | public static void process(Decompiler d) { 6 | Code code = d.code; 7 | for(int line = 1; line <= code.length; line++) { 8 | switch(code.op(line)) { 9 | case EQ: { 10 | /* TODO 11 | AssertionManager.assertCritical( 12 | line + 1 <= code.length && code.isJMP(line + 1), 13 | "ByteCode validation failed; EQ instruction is not followed by JMP" 14 | ); 15 | break;*/ 16 | } 17 | case LT: { 18 | break; 19 | } 20 | default: 21 | break; 22 | } 23 | } 24 | } 25 | 26 | //static only 27 | private Validator() {} 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/unluac/decompile/Walker.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile; 2 | 3 | import unluac.decompile.expression.Expression; 4 | import unluac.decompile.statement.Statement; 5 | 6 | public class Walker { 7 | 8 | public void visitStatement(Statement stmt) { 9 | 10 | } 11 | 12 | public void visitExpression(Expression expr) { 13 | 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/AlwaysLoop.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Function; 5 | import unluac.decompile.Output; 6 | import unluac.decompile.expression.ConstantExpression; 7 | import unluac.decompile.statement.Statement; 8 | import unluac.parse.LFunction; 9 | 10 | public class AlwaysLoop extends ContainerBlock { 11 | 12 | private final boolean repeat; 13 | 14 | private ConstantExpression condition; 15 | 16 | public AlwaysLoop(LFunction function, int begin, int end, boolean repeat) { 17 | super(function, begin, end, 0); 18 | this.repeat = repeat; 19 | condition = null; 20 | } 21 | 22 | @Override 23 | public int scopeEnd() { 24 | return end - 2; 25 | } 26 | 27 | @Override 28 | public boolean breakable() { 29 | return true; 30 | } 31 | 32 | @Override 33 | public boolean isUnprotected() { 34 | return true; 35 | } 36 | 37 | @Override 38 | public int getUnprotectedTarget() { 39 | return begin; 40 | } 41 | 42 | @Override 43 | public int getUnprotectedLine() { 44 | return end - 1; 45 | } 46 | 47 | @Override 48 | public int getLoopback() { 49 | return begin; 50 | } 51 | 52 | @Override 53 | public void print(Decompiler d, Output out) { 54 | if(repeat) { 55 | out.println("repeat"); 56 | } else { 57 | out.print("while "); 58 | if(condition == null) { 59 | out.print("true"); 60 | } else { 61 | condition.print(d, out); 62 | } 63 | out.println(" do"); 64 | } 65 | out.indent(); 66 | Statement.printSequence(d, out, statements); 67 | out.dedent(); 68 | if(repeat) { 69 | out.print("until false"); 70 | } else { 71 | out.print("end"); 72 | } 73 | } 74 | 75 | @Override 76 | public boolean useConstant(Function f, int index) { 77 | if(!repeat && condition == null) { 78 | condition = f.getConstantExpression(index); 79 | return true; 80 | } else { 81 | return false; 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /src/unluac/decompile/block/Block.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Registers; 5 | import unluac.decompile.operation.Operation; 6 | import unluac.decompile.statement.Statement; 7 | import unluac.parse.LFunction; 8 | 9 | abstract public class Block extends Statement implements Comparable { 10 | 11 | protected final LFunction function; 12 | public int begin; 13 | public int end; 14 | private final int priority; 15 | public boolean loopRedirectAdjustment = false; 16 | protected boolean scopeUsed = false; 17 | 18 | public Block(LFunction function, int begin, int end, int priority) { 19 | this.function = function; 20 | this.begin = begin; 21 | this.end = end; 22 | this.priority = priority; 23 | } 24 | 25 | abstract public void addStatement(Statement statement); 26 | 27 | public void resolve(Registers r) {} 28 | 29 | public boolean contains(Block block) { 30 | return begin <= block.begin && end >= block.end; 31 | } 32 | 33 | public boolean contains(int line) { 34 | return begin <= line && line < end; 35 | } 36 | 37 | public int scopeEnd() { 38 | return end - 1; 39 | } 40 | 41 | public void useScope() { 42 | scopeUsed = true; 43 | } 44 | 45 | /** 46 | * An unprotected block is one that ends in a JMP instruction. 47 | * If this is the case, any inner statement that tries to jump 48 | * to the end of this block will be redirected. 49 | * 50 | * (One of the Lua compiler's few optimizations is that is changes 51 | * any JMP that targets another JMP to the ultimate target. This 52 | * is what I call redirection.) 53 | */ 54 | abstract public boolean isUnprotected(); 55 | 56 | public int getUnprotectedTarget() { 57 | throw new IllegalStateException(this.toString()); 58 | } 59 | 60 | public int getUnprotectedLine() { 61 | throw new IllegalStateException(this.toString()); 62 | } 63 | 64 | abstract public int getLoopback(); 65 | 66 | abstract public boolean breakable(); 67 | 68 | abstract public boolean isContainer(); 69 | 70 | abstract public boolean isEmpty(); 71 | 72 | public boolean allowsPreDeclare() { 73 | return false; 74 | } 75 | 76 | public boolean isSplitable() { 77 | return false; 78 | } 79 | 80 | public Block[] split(int line) { 81 | throw new IllegalStateException(); 82 | } 83 | 84 | @Override 85 | public int compareTo(Block block) { 86 | if(this.begin < block.begin) { 87 | return -1; 88 | } else if(this.begin == block.begin) { 89 | if(this.end < block.end) { 90 | return 1; 91 | } else if(this.end == block.end) { 92 | return this.priority - block.priority; 93 | } else { 94 | return -1; 95 | } 96 | } else { 97 | return 1; 98 | } 99 | } 100 | 101 | public Operation process(Decompiler d) { 102 | final Statement statement = this; 103 | return new Operation(end - 1) { 104 | 105 | @Override 106 | public Statement process(Registers r, Block block) { 107 | return statement; 108 | } 109 | 110 | }; 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/Break.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | import unluac.decompile.statement.Statement; 7 | import unluac.parse.LFunction; 8 | 9 | public class Break extends Block { 10 | 11 | public final int target; 12 | public String comment; 13 | 14 | public Break(LFunction function, int line, int target) { 15 | super(function, line, line, 2); 16 | this.target = target; 17 | } 18 | 19 | @Override 20 | public void walk(Walker w) { 21 | w.visitStatement(this); 22 | } 23 | 24 | @Override 25 | public void addStatement(Statement statement) { 26 | throw new IllegalStateException(); 27 | } 28 | 29 | @Override 30 | public boolean isContainer() { 31 | return false; 32 | } 33 | 34 | @Override 35 | public boolean isEmpty() { 36 | return true; 37 | } 38 | 39 | @Override 40 | public boolean breakable() { 41 | return false; 42 | } 43 | 44 | @Override 45 | public boolean isUnprotected() { 46 | //Actually, it is unprotected, but not really a block 47 | return false; 48 | } 49 | 50 | @Override 51 | public int getLoopback() { 52 | throw new IllegalStateException(); 53 | } 54 | 55 | @Override 56 | public void print(Decompiler d, Output out) { 57 | out.print("do break end"); 58 | if(comment != null) out.print(" -- " + comment); 59 | } 60 | 61 | @Override 62 | public void printTail(Decompiler d, Output out) { 63 | out.print("break"); 64 | if(comment != null) out.print(" -- " + comment); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/ContainerBlock.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import unluac.decompile.Walker; 7 | import unluac.decompile.statement.Statement; 8 | import unluac.parse.LFunction; 9 | 10 | abstract public class ContainerBlock extends Block { 11 | 12 | protected final List statements; 13 | 14 | public ContainerBlock(LFunction function, int begin, int end, int priority) { 15 | super(function, begin, end, priority); 16 | statements = new ArrayList(Math.max(4, end - begin + 1)); 17 | } 18 | 19 | @Override 20 | public void walk(Walker w) { 21 | w.visitStatement(this); 22 | for(Statement statement : statements) { 23 | statement.walk(w); 24 | } 25 | } 26 | 27 | @Override 28 | public boolean isContainer() { 29 | return begin < end; 30 | } 31 | 32 | @Override 33 | public boolean isEmpty() { 34 | return statements.isEmpty(); 35 | } 36 | 37 | @Override 38 | public void addStatement(Statement statement) { 39 | statements.add(statement); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/DoEndBlock.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.statement.Statement; 6 | import unluac.parse.LFunction; 7 | 8 | public class DoEndBlock extends ContainerBlock { 9 | 10 | public DoEndBlock(LFunction function, int begin, int end) { 11 | super(function, begin, end, 1); 12 | } 13 | 14 | @Override 15 | public boolean breakable() { 16 | return false; 17 | } 18 | 19 | @Override 20 | public boolean isUnprotected() { 21 | return false; 22 | } 23 | 24 | public boolean allowsPreDeclare() { 25 | return true; 26 | } 27 | 28 | @Override 29 | public int getLoopback() { 30 | throw new IllegalStateException(); 31 | } 32 | 33 | @Override 34 | public void print(Decompiler d, Output out) { 35 | out.println("do"); 36 | out.indent(); 37 | Statement.printSequence(d, out, statements); 38 | out.dedent(); 39 | out.print("end"); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/ElseEndBlock.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.statement.Statement; 6 | import unluac.parse.LFunction; 7 | 8 | public class ElseEndBlock extends ContainerBlock { 9 | 10 | public IfThenElseBlock partner; 11 | 12 | public ElseEndBlock(LFunction function, int begin, int end) { 13 | super(function, begin, end, -1); 14 | } 15 | 16 | @Override 17 | public int compareTo(Block block) { 18 | if(block == partner) { 19 | return 1; 20 | } else { 21 | int result = super.compareTo(block); 22 | return result; 23 | } 24 | } 25 | 26 | @Override 27 | public boolean breakable() { 28 | return false; 29 | } 30 | 31 | @Override 32 | public boolean isUnprotected() { 33 | return false; 34 | } 35 | 36 | @Override 37 | public int getLoopback() { 38 | throw new IllegalStateException(); 39 | } 40 | 41 | @Override 42 | public void print(Decompiler d, Output out) { 43 | if(statements.size() == 1 && statements.get(0) instanceof IfThenEndBlock) { 44 | out.print("else"); 45 | statements.get(0).print(d, out); 46 | } else if(statements.size() == 2 && statements.get(0) instanceof IfThenElseBlock && statements.get(1) instanceof ElseEndBlock) { 47 | out.print("else"); 48 | statements.get(0).print(d, out); 49 | statements.get(1).print(d, out); 50 | } else { 51 | out.print("else"); 52 | out.println(); 53 | out.indent(); 54 | Statement.printSequence(d, out, statements); 55 | out.dedent(); 56 | out.print("end"); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/ForBlock.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Registers; 6 | import unluac.decompile.Walker; 7 | import unluac.decompile.expression.Expression; 8 | import unluac.decompile.statement.Statement; 9 | import unluac.decompile.target.Target; 10 | import unluac.parse.LFunction; 11 | 12 | abstract public class ForBlock extends ContainerBlock { 13 | 14 | protected final int register; 15 | protected final boolean forvarClose; 16 | protected final boolean innerClose; 17 | 18 | protected Target target; 19 | protected Expression start; 20 | protected Expression stop; 21 | protected Expression step; 22 | 23 | public ForBlock(LFunction function, int begin, int end, int register, boolean forvarClose, boolean innerClose) { 24 | super(function, begin, end, -1); 25 | this.register = register; 26 | this.forvarClose = forvarClose; 27 | this.innerClose = innerClose; 28 | } 29 | 30 | abstract public void handleVariableDeclarations(Registers r); 31 | 32 | @Override 33 | public void walk(Walker w) { 34 | w.visitStatement(this); 35 | start.walk(w); 36 | stop.walk(w); 37 | step.walk(w); 38 | for(Statement statement : statements) { 39 | statement.walk(w); 40 | } 41 | } 42 | 43 | @Override 44 | public int scopeEnd() { 45 | int scopeEnd = end - 2; 46 | if(forvarClose) scopeEnd--; 47 | if(innerClose) scopeEnd--; 48 | return scopeEnd; 49 | } 50 | 51 | @Override 52 | public boolean breakable() { 53 | return true; 54 | } 55 | 56 | @Override 57 | public boolean isUnprotected() { 58 | return false; 59 | } 60 | 61 | @Override 62 | public int getLoopback() { 63 | throw new IllegalStateException(); 64 | } 65 | 66 | @Override 67 | public void print(Decompiler d, Output out) { 68 | out.print("for "); 69 | target.print(d, out, false); 70 | out.print(" = "); 71 | start.print(d, out); 72 | out.print(", "); 73 | stop.print(d, out); 74 | if(!step.isInteger() || step.asInteger() != 1) { 75 | out.print(", "); 76 | step.print(d, out); 77 | } 78 | out.print(" do"); 79 | out.println(); 80 | out.indent(); 81 | Statement.printSequence(d, out, statements); 82 | out.dedent(); 83 | out.print("end"); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/ForBlock50.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.parse.LFunction; 5 | 6 | public class ForBlock50 extends ForBlock { 7 | 8 | public ForBlock50(LFunction function, int begin, int end, int register, boolean innerClose) { 9 | super(function, begin, end, register, false, innerClose); 10 | } 11 | 12 | @Override 13 | public void resolve(Registers r) { 14 | target = r.getTarget(register, begin - 1); 15 | start = r.getValue(register, begin - 2); 16 | stop = r.getValue(register + 1, begin - 1); 17 | step = r.getValue(register + 2, begin - 1); 18 | } 19 | 20 | @Override 21 | public void handleVariableDeclarations(Registers r) { 22 | r.setExplicitLoopVariable(register, begin - 1, end - 1); 23 | r.setInternalLoopVariable(register + 1, begin - 1, end - 1); 24 | r.setInternalLoopVariable(register + 2, begin - 1, end - 1); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/ForBlock51.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.parse.LFunction; 5 | 6 | public class ForBlock51 extends ForBlock { 7 | 8 | public ForBlock51(LFunction function, int begin, int end, int register, boolean forvarClose, boolean innerClose) { 9 | super(function, begin, end, register, forvarClose, innerClose); 10 | } 11 | 12 | @Override 13 | public void resolve(Registers r) { 14 | target = r.getTarget(register + 3, begin - 1); 15 | start = r.getValue(register, begin - 1); 16 | stop = r.getValue(register + 1, begin - 1); 17 | step = r.getValue(register + 2, begin - 1); 18 | } 19 | 20 | @Override 21 | public void handleVariableDeclarations(Registers r) { 22 | r.setInternalLoopVariable(register, begin - 2, end - 1); 23 | r.setInternalLoopVariable(register + 1, begin - 2, end - 1); 24 | r.setInternalLoopVariable(register + 2, begin - 2, end - 1); 25 | int explicitEnd = end - 2; 26 | if(forvarClose) explicitEnd--; 27 | r.setExplicitLoopVariable(register + 3, begin - 1, explicitEnd); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/Goto.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | import unluac.decompile.statement.Statement; 7 | import unluac.parse.LFunction; 8 | 9 | public class Goto extends Block { 10 | 11 | public final int target; 12 | 13 | public Goto(LFunction function, int line, int target) { 14 | super(function, line, line, 2); 15 | this.target = target; 16 | } 17 | 18 | @Override 19 | public void walk(Walker w) { 20 | w.visitStatement(this); 21 | } 22 | 23 | @Override 24 | public void addStatement(Statement statement) { 25 | throw new IllegalStateException(); 26 | } 27 | 28 | @Override 29 | public boolean isContainer() { 30 | return false; 31 | } 32 | 33 | @Override 34 | public boolean isEmpty() { 35 | return true; 36 | } 37 | 38 | @Override 39 | public boolean breakable() { 40 | return false; 41 | } 42 | 43 | @Override 44 | public boolean isUnprotected() { 45 | //Actually, it is unprotected, but not really a block 46 | return false; 47 | } 48 | 49 | @Override 50 | public int getLoopback() { 51 | throw new IllegalStateException(); 52 | } 53 | 54 | @Override 55 | public void print(Decompiler d, Output out) { 56 | out.print("goto lbl_" + target); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/IfThenElseBlock.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Registers; 6 | import unluac.decompile.Walker; 7 | import unluac.decompile.condition.Condition; 8 | import unluac.decompile.expression.Expression; 9 | import unluac.decompile.statement.Statement; 10 | import unluac.parse.LFunction; 11 | 12 | public class IfThenElseBlock extends ContainerBlock { 13 | 14 | private final Condition cond; 15 | private final int elseTarget; 16 | public ElseEndBlock partner; 17 | 18 | private Expression condexpr; 19 | 20 | public IfThenElseBlock(LFunction function, Condition cond, int begin, int end, int elseTarget) { 21 | super(function, begin, end, -1); 22 | this.cond = cond; 23 | this.elseTarget = elseTarget; 24 | } 25 | 26 | @Override 27 | public void resolve(Registers r) { 28 | condexpr = cond.asExpression(r); 29 | } 30 | 31 | @Override 32 | public void walk(Walker w) { 33 | w.visitStatement(this); 34 | condexpr.walk(w); 35 | for(Statement statement : statements) { 36 | statement.walk(w); 37 | } 38 | } 39 | 40 | @Override 41 | public boolean suppressNewline() { 42 | return true; 43 | } 44 | 45 | @Override 46 | public int compareTo(Block block) { 47 | if(block == partner) { 48 | return -1; 49 | } else { 50 | return super.compareTo(block); 51 | } 52 | } 53 | 54 | @Override 55 | public boolean breakable() { 56 | return false; 57 | } 58 | 59 | @Override 60 | public int scopeEnd() { 61 | return end - 2; 62 | } 63 | 64 | @Override 65 | public boolean isUnprotected() { 66 | return true; 67 | } 68 | 69 | @Override 70 | public int getUnprotectedLine() { 71 | return end - 1; 72 | } 73 | 74 | @Override 75 | public int getUnprotectedTarget() { 76 | return elseTarget; 77 | } 78 | 79 | @Override 80 | public int getLoopback() { 81 | throw new IllegalStateException(); 82 | } 83 | 84 | @Override 85 | public void print(Decompiler d, Output out) { 86 | out.print("if "); 87 | condexpr.print(d, out); 88 | out.print(" then"); 89 | out.println(); 90 | out.indent(); 91 | 92 | Statement.printSequence(d, out, statements); 93 | 94 | out.dedent(); 95 | 96 | // Handle the "empty else" case 97 | if(end == elseTarget) { 98 | out.println("else"); 99 | out.println("end"); 100 | } 101 | 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/OnceLoop.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.statement.Statement; 6 | import unluac.parse.LFunction; 7 | 8 | public class OnceLoop extends ContainerBlock { 9 | 10 | public OnceLoop(LFunction function, int begin, int end) { 11 | super(function, begin, end, 0); 12 | } 13 | 14 | @Override 15 | public int scopeEnd() { 16 | return end - 1; 17 | } 18 | 19 | @Override 20 | public boolean breakable() { 21 | return true; 22 | } 23 | 24 | @Override 25 | public boolean isUnprotected() { 26 | return false; 27 | } 28 | 29 | @Override 30 | public int getLoopback() { 31 | return begin; 32 | } 33 | 34 | @Override 35 | public void print(Decompiler d, Output out) { 36 | out.println("repeat"); 37 | out.indent(); 38 | Statement.printSequence(d, out, statements); 39 | out.dedent(); 40 | out.print("until true"); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/OuterBlock.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.statement.Return; 6 | import unluac.decompile.statement.Statement; 7 | import unluac.parse.LFunction; 8 | 9 | public class OuterBlock extends ContainerBlock { 10 | 11 | public OuterBlock(LFunction function, int length) { 12 | super(function, 0, length + 1, -2); 13 | } 14 | 15 | @Override 16 | public boolean breakable() { 17 | return false; 18 | } 19 | 20 | @Override 21 | public boolean isUnprotected() { 22 | return false; 23 | } 24 | 25 | @Override 26 | public int getLoopback() { 27 | throw new IllegalStateException(); 28 | } 29 | 30 | @Override 31 | public int scopeEnd() { 32 | return (end - 1) + function.header.version.outerblockscopeadjustment.get(); 33 | } 34 | 35 | @Override 36 | public void print(Decompiler d, Output out) { 37 | /* extra return statement */ 38 | int last = statements.size() - 1; 39 | if(last < 0 || !(statements.get(last) instanceof Return)) { 40 | throw new IllegalStateException(statements.get(last).toString()); 41 | } 42 | statements.remove(last); 43 | Statement.printSequence(d, out, statements); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/RepeatBlock.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Registers; 6 | import unluac.decompile.Walker; 7 | import unluac.decompile.condition.Condition; 8 | import unluac.decompile.expression.Expression; 9 | import unluac.decompile.statement.Statement; 10 | import unluac.parse.LFunction; 11 | 12 | public class RepeatBlock extends ContainerBlock { 13 | 14 | private final Condition cond; 15 | private final int scopeEnd; 16 | 17 | private Expression condexpr; 18 | 19 | public RepeatBlock(LFunction function, Condition cond, int begin, int end) { 20 | this(function, cond, begin, end, end - 1); 21 | } 22 | 23 | public RepeatBlock(LFunction function, Condition cond, int begin, int end, int scopeEnd) { 24 | super(function, begin, end, 0); 25 | this.cond = cond; 26 | this.scopeEnd = scopeEnd; 27 | } 28 | 29 | @Override 30 | public void resolve(Registers r) { 31 | condexpr = cond.asExpression(r); 32 | } 33 | 34 | @Override 35 | public void walk(Walker w) { 36 | w.visitStatement(this); 37 | for(Statement statement : statements) { 38 | statement.walk(w); 39 | } 40 | condexpr.walk(w); 41 | } 42 | 43 | @Override 44 | public int scopeEnd() { 45 | return scopeEnd; 46 | } 47 | 48 | @Override 49 | public boolean breakable() { 50 | return true; 51 | } 52 | 53 | @Override 54 | public boolean isUnprotected() { 55 | return false; 56 | } 57 | 58 | @Override 59 | public int getLoopback() { 60 | throw new IllegalStateException(); 61 | } 62 | 63 | @Override 64 | public void print(Decompiler d, Output out) { 65 | out.print("repeat"); 66 | out.println(); 67 | out.indent(); 68 | Statement.printSequence(d, out, statements); 69 | out.dedent(); 70 | out.print("until "); 71 | condexpr.print(d, out); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/unluac/decompile/block/WhileBlock.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.block; 2 | 3 | import unluac.Version; 4 | import unluac.decompile.Decompiler; 5 | import unluac.decompile.Output; 6 | import unluac.decompile.Registers; 7 | import unluac.decompile.Walker; 8 | import unluac.decompile.condition.Condition; 9 | import unluac.decompile.expression.Expression; 10 | import unluac.decompile.statement.Statement; 11 | import unluac.parse.LFunction; 12 | 13 | public class WhileBlock extends ContainerBlock { 14 | 15 | private Condition cond; 16 | private final int unprotectedTarget; 17 | private final boolean splitable; 18 | 19 | private Expression condexpr; 20 | 21 | public WhileBlock(LFunction function, Condition cond, int begin, int end, int unprotectedTarget) { 22 | super(function, begin, end, -1); 23 | this.cond = cond; 24 | this.unprotectedTarget = unprotectedTarget; 25 | this.splitable = (function.header.version.whileformat.get() == Version.WhileFormat.TOP_CONDITION); 26 | } 27 | 28 | @Override 29 | public void resolve(Registers r) { 30 | condexpr = cond.asExpression(r); 31 | } 32 | 33 | @Override 34 | public void walk(Walker w) { 35 | w.visitStatement(this); 36 | condexpr.walk(w); 37 | for(Statement statement : statements) { 38 | statement.walk(w); 39 | } 40 | } 41 | 42 | @Override 43 | public int scopeEnd() { 44 | return end - 2; 45 | } 46 | 47 | @Override 48 | public boolean breakable() { 49 | return true; 50 | } 51 | 52 | @Override 53 | public boolean isUnprotected() { 54 | return unprotectedTarget != -1; 55 | } 56 | 57 | @Override 58 | public int getUnprotectedLine() { 59 | if(unprotectedTarget == -1) { 60 | throw new IllegalStateException(); 61 | } 62 | return end - 1; 63 | } 64 | 65 | @Override 66 | public int getUnprotectedTarget() { 67 | if(unprotectedTarget == -1) { 68 | throw new IllegalStateException(); 69 | } 70 | return unprotectedTarget; 71 | }; 72 | 73 | @Override 74 | public int getLoopback() { 75 | throw new IllegalStateException(); 76 | } 77 | 78 | @Override 79 | public boolean isSplitable() { 80 | return splitable && cond.isSplitable(); 81 | } 82 | 83 | @Override 84 | public Block[] split(int line) { 85 | Condition[] conds = cond.split(); 86 | cond = conds[0]; 87 | return new Block[] { 88 | new IfThenElseBlock(function, conds[1], begin, line + 1, end - 1), 89 | new ElseEndBlock(function, line + 1, end - 1), 90 | }; 91 | } 92 | 93 | @Override 94 | public void print(Decompiler d, Output out) { 95 | out.print("while "); 96 | condexpr.print(d, out); 97 | out.print(" do"); 98 | out.println(); 99 | out.indent(); 100 | Statement.printSequence(d, out, statements); 101 | out.dedent(); 102 | out.print("end"); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/unluac/decompile/condition/AndCondition.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.condition; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.expression.BinaryExpression; 5 | import unluac.decompile.expression.Expression; 6 | 7 | public class AndCondition implements Condition { 8 | 9 | private Condition left; 10 | private Condition right; 11 | 12 | public AndCondition(Condition left, Condition right) { 13 | this.left = left; 14 | this.right = right; 15 | } 16 | 17 | @Override 18 | public Condition inverse() { 19 | if(invertible()) { 20 | return new OrCondition(left.inverse(), right.inverse()); 21 | } else { 22 | return new NotCondition(this); 23 | } 24 | } 25 | 26 | @Override 27 | public boolean invertible() { 28 | return right.invertible(); 29 | } 30 | 31 | @Override 32 | public int register() { 33 | return right.register(); 34 | } 35 | 36 | @Override 37 | public boolean isRegisterTest() { 38 | return false; 39 | } 40 | 41 | @Override 42 | public boolean isOrCondition() { 43 | return false; 44 | } 45 | 46 | @Override 47 | public boolean isSplitable() { 48 | return true; 49 | } 50 | 51 | @Override 52 | public Condition[] split() { 53 | return new Condition[] {left, right}; 54 | } 55 | 56 | @Override 57 | public Expression asExpression(Registers r) { 58 | return new BinaryExpression("and", left.asExpression(r), right.asExpression(r), Expression.PRECEDENCE_AND, Expression.ASSOCIATIVITY_NONE); 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return left + " and " + right; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/unluac/decompile/condition/Condition.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.condition; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.expression.ConstantExpression; 5 | import unluac.decompile.expression.Expression; 6 | 7 | public interface Condition { 8 | 9 | public static enum OperandType { 10 | R, 11 | RK, 12 | K, 13 | I, 14 | F, 15 | } 16 | 17 | public static class Operand { 18 | 19 | public Operand(OperandType type, int value) { 20 | this.type = type; 21 | this.value = value; 22 | } 23 | 24 | public Expression asExpression(Registers r, int line) { 25 | switch(type) { 26 | case R: return r.getExpression(this.value, line); 27 | case RK: return r.getKExpression(this.value, line); 28 | case K: return r.getFunction().getConstantExpression(this.value); 29 | case I: return ConstantExpression.createInteger(this.value); 30 | case F: return ConstantExpression.createDouble((double) this.value); 31 | default: throw new IllegalStateException(); 32 | } 33 | } 34 | 35 | public boolean isRegister(Registers r) { 36 | switch(type) { 37 | case R: return true; 38 | case RK: return !r.isKConstant(this.value); 39 | case K: return false; 40 | case I: return false; 41 | case F: return false; 42 | default: throw new IllegalStateException(); 43 | } 44 | } 45 | 46 | public int getUpdated(Registers r, int line) { 47 | switch(type) { 48 | case R: return r.getUpdated(this.value, line); 49 | case RK: 50 | if(r.isKConstant(this.value)) throw new IllegalStateException(); 51 | return r.getUpdated(this.value, line); 52 | default: throw new IllegalStateException(); 53 | } 54 | } 55 | 56 | public final OperandType type; 57 | public final int value; 58 | 59 | } 60 | 61 | public Condition inverse(); 62 | 63 | public boolean invertible(); 64 | 65 | public int register(); 66 | 67 | public boolean isRegisterTest(); 68 | 69 | public boolean isOrCondition(); 70 | 71 | public boolean isSplitable(); 72 | 73 | public Condition[] split(); 74 | 75 | public Expression asExpression(Registers r); 76 | 77 | @Override 78 | public String toString(); 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/unluac/decompile/condition/ConstantCondition.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.condition; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.expression.ConstantExpression; 5 | import unluac.decompile.expression.Expression; 6 | 7 | public class ConstantCondition implements Condition { 8 | 9 | private int register; 10 | private boolean value; 11 | 12 | public ConstantCondition(int register, boolean value) { 13 | this.register = register; 14 | this.value = value; 15 | } 16 | 17 | @Override 18 | public Condition inverse() { 19 | return new ConstantCondition(register, !value); 20 | } 21 | 22 | @Override 23 | public boolean invertible() { 24 | return true; 25 | } 26 | 27 | @Override 28 | public int register() { 29 | return register; 30 | } 31 | 32 | @Override 33 | public boolean isRegisterTest() { 34 | return false; 35 | } 36 | 37 | @Override 38 | public boolean isOrCondition() { 39 | return false; 40 | } 41 | 42 | @Override 43 | public boolean isSplitable() { 44 | return false; 45 | } 46 | 47 | @Override 48 | public Condition[] split() { 49 | throw new IllegalStateException(); 50 | } 51 | 52 | @Override 53 | public Expression asExpression(Registers r) { 54 | return ConstantExpression.createBoolean(value); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/unluac/decompile/condition/FinalSetCondition.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.condition; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.expression.ConstantExpression; 5 | import unluac.decompile.expression.Expression; 6 | 7 | public class FinalSetCondition implements Condition { 8 | 9 | public static enum Type { 10 | NONE, 11 | REGISTER, 12 | VALUE, 13 | } 14 | 15 | public int line; 16 | private int register; 17 | public Type type; 18 | 19 | public FinalSetCondition(int line, int register) { 20 | this.line = line; 21 | this.register = register; 22 | this.type = Type.NONE; 23 | if(register < 0) { 24 | throw new IllegalStateException(); 25 | } 26 | } 27 | 28 | @Override 29 | public Condition inverse() { 30 | return new NotCondition(this); 31 | } 32 | 33 | @Override 34 | public boolean invertible() { 35 | return false; 36 | } 37 | 38 | @Override 39 | public int register() { 40 | return register; 41 | } 42 | 43 | @Override 44 | public boolean isRegisterTest() { 45 | return false; 46 | } 47 | 48 | @Override 49 | public boolean isOrCondition() { 50 | return false; 51 | } 52 | 53 | @Override 54 | public boolean isSplitable() { 55 | return false; 56 | } 57 | 58 | @Override 59 | public Condition[] split() { 60 | throw new IllegalStateException(); 61 | } 62 | 63 | @Override 64 | public Expression asExpression(Registers r) { 65 | Expression expr; 66 | switch(type) { 67 | case REGISTER: 68 | expr = r.getExpression(register, line + 1); 69 | break; 70 | case VALUE: 71 | expr = r.getValue(register, line + 1); 72 | break; 73 | case NONE: 74 | default: 75 | expr = ConstantExpression.createDouble(register + ((double)line) / 100.0); 76 | break; 77 | } 78 | if(expr == null) { 79 | throw new IllegalStateException(); 80 | } 81 | return expr; 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return "(" + register + ")"; 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /src/unluac/decompile/condition/NotCondition.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.condition; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.expression.Expression; 5 | import unluac.decompile.expression.UnaryExpression; 6 | 7 | public class NotCondition implements Condition { 8 | 9 | private Condition cond; 10 | 11 | public NotCondition(Condition cond) { 12 | this.cond = cond; 13 | } 14 | 15 | @Override 16 | public Condition inverse() { 17 | return cond; 18 | } 19 | 20 | @Override 21 | public boolean invertible() { 22 | return true; 23 | } 24 | 25 | @Override 26 | public int register() { 27 | return cond.register(); 28 | } 29 | 30 | @Override 31 | public boolean isRegisterTest() { 32 | return cond.isRegisterTest(); 33 | } 34 | 35 | @Override 36 | public boolean isOrCondition() { 37 | return false; 38 | } 39 | 40 | @Override 41 | public boolean isSplitable() { 42 | return false; 43 | } 44 | 45 | @Override 46 | public Condition[] split() { 47 | throw new IllegalStateException(); 48 | } 49 | 50 | @Override 51 | public Expression asExpression(Registers r) { 52 | return new UnaryExpression("not ", cond.asExpression(r), Expression.PRECEDENCE_UNARY); 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "not (" + cond + ")"; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/unluac/decompile/condition/OrCondition.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.condition; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.expression.BinaryExpression; 5 | import unluac.decompile.expression.Expression; 6 | 7 | public class OrCondition implements Condition { 8 | 9 | private Condition left; 10 | private Condition right; 11 | 12 | public OrCondition(Condition left, Condition right) { 13 | this.left = left; 14 | this.right = right; 15 | } 16 | 17 | @Override 18 | public Condition inverse() { 19 | if(invertible()) { 20 | return new AndCondition(left.inverse(), right.inverse()); 21 | } else { 22 | return new NotCondition(this); 23 | } 24 | } 25 | 26 | @Override 27 | public boolean invertible() { 28 | return right.invertible(); 29 | } 30 | 31 | @Override 32 | public int register() { 33 | return right.register(); 34 | } 35 | 36 | @Override 37 | public boolean isRegisterTest() { 38 | return false; 39 | } 40 | 41 | @Override 42 | public boolean isOrCondition() { 43 | return true; 44 | } 45 | 46 | @Override 47 | public boolean isSplitable() { 48 | return false; 49 | } 50 | 51 | @Override 52 | public Condition[] split() { 53 | throw new IllegalStateException(); 54 | } 55 | 56 | @Override 57 | public Expression asExpression(Registers r) { 58 | return new BinaryExpression("or", left.asExpression(r), right.asExpression(r), Expression.PRECEDENCE_OR, Expression.ASSOCIATIVITY_NONE); 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return "(" + left + " or " + right + ")"; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/unluac/decompile/condition/TestCondition.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.condition; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.expression.Expression; 5 | 6 | public class TestCondition implements Condition { 7 | 8 | private int line; 9 | private int register; 10 | 11 | public TestCondition(int line, int register) { 12 | this.line = line; 13 | this.register = register; 14 | } 15 | 16 | @Override 17 | public Condition inverse() { 18 | return new NotCondition(this); 19 | } 20 | 21 | @Override 22 | public boolean invertible() { 23 | return false; 24 | } 25 | 26 | @Override 27 | public int register() { 28 | return register; 29 | } 30 | 31 | @Override 32 | public boolean isRegisterTest() { 33 | return true; 34 | } 35 | 36 | @Override 37 | public boolean isOrCondition() { 38 | return false; 39 | } 40 | 41 | @Override 42 | public boolean isSplitable() { 43 | return false; 44 | } 45 | 46 | @Override 47 | public Condition[] split() { 48 | throw new IllegalStateException(); 49 | } 50 | 51 | @Override 52 | public Expression asExpression(Registers r) { 53 | return r.getExpression(register, line); 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "(" + register + ")"; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/unluac/decompile/expression/BinaryExpression.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.expression; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | 7 | public class BinaryExpression extends Expression { 8 | 9 | private final String op; 10 | private final Expression left; 11 | private final Expression right; 12 | private final int associativity; 13 | 14 | public static BinaryExpression replaceRight(BinaryExpression template, Expression replacement) { 15 | return new BinaryExpression(template.op, template.left, replacement, template.precedence, template.associativity); 16 | } 17 | 18 | public BinaryExpression(String op, Expression left, Expression right, int precedence, int associativity) { 19 | super(precedence); 20 | this.op = op; 21 | this.left = left; 22 | this.right = right; 23 | this.associativity = associativity; 24 | } 25 | 26 | @Override 27 | public void walk(Walker w) { 28 | w.visitExpression(this); 29 | left.walk(w); 30 | right.walk(w); 31 | } 32 | 33 | @Override 34 | public boolean isUngrouped() { 35 | return !beginsWithParen(); 36 | } 37 | 38 | @Override 39 | public int getConstantIndex() { 40 | return Math.max(left.getConstantIndex(), right.getConstantIndex()); 41 | } 42 | 43 | @Override 44 | public boolean beginsWithParen() { 45 | return leftGroup() || left.beginsWithParen(); 46 | } 47 | 48 | @Override 49 | public void print(Decompiler d, Output out) { 50 | final boolean leftGroup = leftGroup(); 51 | final boolean rightGroup = rightGroup(); 52 | if(leftGroup) out.print("("); 53 | left.print(d, out); 54 | if(leftGroup) out.print(")"); 55 | out.print(" "); 56 | out.print(op); 57 | out.print(" "); 58 | if(rightGroup) out.print("("); 59 | right.print(d, out); 60 | if(rightGroup) out.print(")"); 61 | } 62 | 63 | public String getOp() { 64 | return op; 65 | } 66 | 67 | private boolean leftGroup() { 68 | return precedence > left.precedence || (precedence == left.precedence && associativity == ASSOCIATIVITY_RIGHT); 69 | } 70 | 71 | private boolean rightGroup() { 72 | return precedence > right.precedence || (precedence == right.precedence && associativity == ASSOCIATIVITY_LEFT); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/unluac/decompile/expression/ClosureExpression.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.expression; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | import unluac.decompile.target.TableTarget; 7 | import unluac.decompile.target.Target; 8 | import unluac.decompile.target.VariableTarget; 9 | import unluac.parse.LFunction; 10 | import unluac.parse.LUpvalue; 11 | 12 | public class ClosureExpression extends Expression { 13 | 14 | private final LFunction function; 15 | private int upvalueLine; 16 | 17 | public ClosureExpression(LFunction function, int upvalueLine) { 18 | super(PRECEDENCE_ATOMIC); 19 | this.function = function; 20 | this.upvalueLine = upvalueLine; 21 | } 22 | 23 | @Override 24 | public void walk(Walker w) { 25 | w.visitExpression(this); 26 | } 27 | 28 | public int getConstantIndex() { 29 | return -1; 30 | } 31 | 32 | @Override 33 | public boolean isClosure() { 34 | return true; 35 | } 36 | 37 | @Override 38 | public boolean isUngrouped() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public boolean isUpvalueOf(int register) { 44 | /* 45 | if(function.header.version == 0x51) { 46 | return false; //TODO: 47 | } 48 | */ 49 | for(int i = 0; i < function.upvalues.length; i++) { 50 | LUpvalue upvalue = function.upvalues[i]; 51 | if(upvalue.instack && upvalue.idx == register) { 52 | return true; 53 | } 54 | } 55 | return false; 56 | } 57 | 58 | @Override 59 | public int closureUpvalueLine() { 60 | return upvalueLine; 61 | } 62 | 63 | @Override 64 | public void print(Decompiler outer, Output out) { 65 | Decompiler d = new Decompiler(function, outer.declList, upvalueLine); 66 | out.print("function"); 67 | printMain(out, d, true); 68 | } 69 | 70 | @Override 71 | public void printClosure(Decompiler outer, Output out, Target name) { 72 | Decompiler d = new Decompiler(function, outer.declList, upvalueLine); 73 | out.print("function "); 74 | if(function.numParams >= 1 && d.declList[0].name.equals("self") && name instanceof TableTarget) { 75 | name.printMethod(outer, out); 76 | printMain(out, d, false); 77 | } else { 78 | name.print(outer, out, false); 79 | printMain(out, d, true); 80 | } 81 | } 82 | 83 | private void printMain(Output out, Decompiler d, boolean includeFirst) { 84 | out.print("("); 85 | int start = includeFirst ? 0 : 1; 86 | if(function.numParams > start) { 87 | new VariableTarget(d.declList[start]).print(d, out, false); 88 | for(int i = start + 1; i < function.numParams; i++) { 89 | out.print(", "); 90 | new VariableTarget(d.declList[i]).print(d, out, false); 91 | } 92 | } 93 | if(function.vararg != 0) { 94 | if(function.numParams > start) { 95 | out.print(", ..."); 96 | } else { 97 | out.print("..."); 98 | } 99 | } 100 | out.print(")"); 101 | out.println(); 102 | out.indent(); 103 | Decompiler.State result = d.decompile(); 104 | d.print(result, out); 105 | out.dedent(); 106 | out.print("end"); 107 | //out.println(); //This is an extra space for formatting 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/unluac/decompile/expression/ConstantExpression.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.expression; 2 | 3 | import unluac.decompile.Constant; 4 | import unluac.decompile.Decompiler; 5 | import unluac.decompile.Output; 6 | import unluac.decompile.Walker; 7 | import unluac.parse.LBoolean; 8 | import unluac.parse.LNil; 9 | 10 | public class ConstantExpression extends Expression { 11 | 12 | private final Constant constant; 13 | private final boolean identifier; 14 | private final int index; 15 | private final int line; 16 | 17 | public static ConstantExpression createNil(int line) { 18 | return new ConstantExpression(new Constant(LNil.NIL), false, -1, line); 19 | } 20 | 21 | public static ConstantExpression createBoolean(boolean v) { 22 | return new ConstantExpression(new Constant(v ? LBoolean.LTRUE : LBoolean.LFALSE), false, -1); 23 | } 24 | 25 | public static ConstantExpression createInteger(int i) { 26 | return new ConstantExpression(new Constant(i), false, -1); 27 | } 28 | 29 | public static ConstantExpression createDouble(double x) { 30 | return new ConstantExpression(new Constant(x), false, -1); 31 | } 32 | 33 | private static int getPrecedence(Constant constant) { 34 | if(constant.isNumber() && constant.isNegative()) { 35 | return PRECEDENCE_UNARY; 36 | } else { 37 | return PRECEDENCE_ATOMIC; 38 | } 39 | } 40 | 41 | public ConstantExpression(Constant constant, boolean identifier, int index) { 42 | this(constant, identifier, index, -1); 43 | } 44 | 45 | private ConstantExpression(Constant constant, boolean identifier, int index, int line) { 46 | super(getPrecedence(constant)); 47 | this.constant = constant; 48 | this.identifier = identifier; 49 | this.index = index; 50 | this.line = line; 51 | } 52 | 53 | @Override 54 | public void walk(Walker w) { 55 | w.visitExpression(this); 56 | } 57 | 58 | @Override 59 | public int getConstantIndex() { 60 | return index; 61 | } 62 | 63 | @Override 64 | public int getConstantLine() { 65 | return line; 66 | } 67 | 68 | @Override 69 | public void print(Decompiler d, Output out) { 70 | constant.print(d, out, false); 71 | } 72 | 73 | @Override 74 | public void printBraced(Decompiler d, Output out) { 75 | constant.print(d, out, true); 76 | } 77 | 78 | @Override 79 | public boolean isConstant() { 80 | return true; 81 | } 82 | 83 | @Override 84 | public boolean isUngrouped() { 85 | return true; 86 | } 87 | 88 | @Override 89 | public boolean isNil() { 90 | return constant.isNil(); 91 | } 92 | 93 | @Override 94 | public boolean isBoolean() { 95 | return constant.isBoolean(); 96 | } 97 | 98 | @Override 99 | public boolean isInteger() { 100 | return constant.isInteger(); 101 | } 102 | 103 | @Override 104 | public int asInteger() { 105 | return constant.asInteger(); 106 | } 107 | 108 | @Override 109 | public boolean isString() { 110 | return constant.isString(); 111 | } 112 | 113 | @Override 114 | public boolean isIdentifier() { 115 | return identifier; 116 | } 117 | 118 | @Override 119 | public String asName() { 120 | return constant.asName(); 121 | } 122 | 123 | @Override 124 | public boolean isBrief() { 125 | return !constant.isString() || constant.asName().length() <= 10; 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /src/unluac/decompile/expression/FunctionCall.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.expression; 2 | 3 | import java.util.ArrayList; 4 | 5 | import unluac.decompile.Decompiler; 6 | import unluac.decompile.Output; 7 | import unluac.decompile.Walker; 8 | 9 | public class FunctionCall extends Expression { 10 | 11 | private final Expression function; 12 | private final Expression[] arguments; 13 | private final boolean multiple; 14 | 15 | public FunctionCall(Expression function, Expression[] arguments, boolean multiple) { 16 | super(PRECEDENCE_ATOMIC); 17 | this.function = function; 18 | this.arguments = arguments; 19 | this.multiple = multiple; 20 | } 21 | 22 | @Override 23 | public void walk(Walker w) { 24 | w.visitExpression(this); 25 | function.walk(w); 26 | for(Expression expression : arguments) { 27 | expression.walk(w); 28 | } 29 | } 30 | 31 | @Override 32 | public int getConstantIndex() { 33 | int index = function.getConstantIndex(); 34 | for(Expression argument : arguments) { 35 | index = Math.max(argument.getConstantIndex(), index); 36 | } 37 | return index; 38 | } 39 | 40 | @Override 41 | public boolean isMultiple() { 42 | return multiple; 43 | } 44 | 45 | @Override 46 | public void printMultiple(Decompiler d, Output out) { 47 | if(!multiple) { 48 | out.print("("); 49 | } 50 | print(d, out); 51 | if(!multiple) { 52 | out.print(")"); 53 | } 54 | } 55 | 56 | private boolean isMethodCall() { 57 | return function.isMemberAccess() && arguments.length > 0 && function.getTable() == arguments[0]; 58 | } 59 | 60 | @Override 61 | public boolean beginsWithParen() { 62 | if(isMethodCall()) { 63 | Expression obj = function.getTable(); 64 | return obj.isUngrouped() || obj.beginsWithParen(); 65 | } else { 66 | return function.isUngrouped() || function.beginsWithParen(); 67 | } 68 | } 69 | 70 | @Override 71 | public void print(Decompiler d, Output out) { 72 | ArrayList args = new ArrayList(arguments.length); 73 | if(isMethodCall()) { 74 | Expression obj = function.getTable(); 75 | if(obj.isUngrouped()) { 76 | out.print("("); 77 | obj.print(d, out); 78 | out.print(")"); 79 | } else { 80 | obj.print(d, out); 81 | } 82 | out.print(":"); 83 | out.print(function.getField()); 84 | for(int i = 1; i < arguments.length; i++) { 85 | args.add(arguments[i]); 86 | } 87 | } else { 88 | if(function.isUngrouped()) { 89 | out.print("("); 90 | function.print(d, out); 91 | out.print(")"); 92 | } else { 93 | function.print(d, out); 94 | } 95 | for(int i = 0; i < arguments.length; i++) { 96 | args.add(arguments[i]); 97 | } 98 | } 99 | out.print("("); 100 | Expression.printSequence(d, out, args, false, true); 101 | out.print(")"); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/unluac/decompile/expression/GlobalExpression.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.expression; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | 7 | public class GlobalExpression extends Expression { 8 | 9 | private final ConstantExpression name; 10 | private final int index; 11 | 12 | public GlobalExpression(ConstantExpression name, int index) { 13 | super(PRECEDENCE_ATOMIC); 14 | this.name = name; 15 | this.index = index; 16 | } 17 | 18 | @Override 19 | public void walk(Walker w) { 20 | w.visitExpression(this); 21 | name.walk(w); 22 | } 23 | 24 | @Override 25 | public int getConstantIndex() { 26 | return index; 27 | } 28 | 29 | @Override 30 | public boolean isDotChain() { 31 | return true; 32 | } 33 | 34 | @Override 35 | public void print(Decompiler d, Output out) { 36 | out.print(name.asName()); 37 | } 38 | 39 | @Override 40 | public boolean isBrief() { 41 | return true; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/unluac/decompile/expression/LocalVariable.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.expression; 2 | 3 | import unluac.decompile.Declaration; 4 | import unluac.decompile.Decompiler; 5 | import unluac.decompile.Output; 6 | import unluac.decompile.Walker; 7 | 8 | public class LocalVariable extends Expression { 9 | 10 | private final Declaration decl; 11 | 12 | public LocalVariable(Declaration decl) { 13 | super(PRECEDENCE_ATOMIC); 14 | this.decl = decl; 15 | } 16 | 17 | @Override 18 | public void walk(Walker w) { 19 | w.visitExpression(this); 20 | } 21 | 22 | @Override 23 | public int getConstantIndex() { 24 | return -1; 25 | } 26 | 27 | @Override 28 | public boolean isDotChain() { 29 | return true; 30 | } 31 | 32 | @Override 33 | public void print(Decompiler d, Output out) { 34 | out.print(decl.name); 35 | } 36 | 37 | @Override 38 | public boolean isBrief() { 39 | return true; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/unluac/decompile/expression/TableReference.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.expression; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | 7 | public class TableReference extends Expression { 8 | 9 | private final Expression table; 10 | private final Expression index; 11 | 12 | public TableReference(Expression table, Expression index) { 13 | super(PRECEDENCE_ATOMIC); 14 | this.table = table; 15 | this.index = index; 16 | } 17 | 18 | @Override 19 | public void walk(Walker w) { 20 | w.visitExpression(this); 21 | table.walk(w); 22 | index.walk(w); 23 | } 24 | 25 | @Override 26 | public int getConstantIndex() { 27 | return Math.max(table.getConstantIndex(), index.getConstantIndex()); 28 | } 29 | 30 | @Override 31 | public void print(Decompiler d, Output out) { 32 | boolean isGlobal = table.isEnvironmentTable(d) && index.isIdentifier(); 33 | if(!isGlobal) { 34 | if(table.isUngrouped()) { 35 | out.print("("); 36 | table.print(d, out); 37 | out.print(")"); 38 | } 39 | else 40 | { 41 | table.print(d, out); 42 | } 43 | } 44 | if(index.isIdentifier()) { 45 | if(!isGlobal) { 46 | out.print("."); 47 | } 48 | out.print(index.asName()); 49 | } else { 50 | out.print("["); 51 | index.printBraced(d, out); 52 | out.print("]"); 53 | } 54 | } 55 | 56 | @Override 57 | public boolean isDotChain() { 58 | return index.isIdentifier() && table.isDotChain(); 59 | } 60 | 61 | @Override 62 | public boolean isMemberAccess() { 63 | return index.isIdentifier(); 64 | } 65 | 66 | @Override 67 | public boolean beginsWithParen() { 68 | return table.isUngrouped() || table.beginsWithParen(); 69 | } 70 | 71 | @Override 72 | public Expression getTable() { 73 | return table; 74 | } 75 | 76 | @Override 77 | public String getField() { 78 | return index.asName(); 79 | } 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/unluac/decompile/expression/UnaryExpression.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.expression; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | 7 | public class UnaryExpression extends Expression { 8 | 9 | private final String op; 10 | private final Expression expression; 11 | 12 | public UnaryExpression(String op, Expression expression, int precedence) { 13 | super(precedence); 14 | this.op = op; 15 | this.expression = expression; 16 | } 17 | 18 | @Override 19 | public void walk(Walker w) { 20 | w.visitExpression(this); 21 | expression.walk(w); 22 | } 23 | 24 | @Override 25 | public boolean isUngrouped() { 26 | return true; 27 | } 28 | 29 | @Override 30 | public int getConstantIndex() { 31 | return expression.getConstantIndex(); 32 | } 33 | 34 | @Override 35 | public void print(Decompiler d, Output out) { 36 | out.print(op); 37 | if(precedence > expression.precedence) out.print("("); 38 | expression.print(d, out); 39 | if(precedence > expression.precedence) out.print(")"); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/unluac/decompile/expression/UpvalueExpression.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.expression; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | 7 | public class UpvalueExpression extends Expression { 8 | 9 | private final String name; 10 | 11 | public UpvalueExpression(String name) { 12 | super(PRECEDENCE_ATOMIC); 13 | this.name = name; 14 | } 15 | 16 | @Override 17 | public void walk(Walker w) { 18 | w.visitExpression(this); 19 | } 20 | 21 | @Override 22 | public int getConstantIndex() { 23 | return -1; 24 | } 25 | 26 | @Override 27 | public boolean isDotChain() { 28 | return true; 29 | } 30 | 31 | @Override 32 | public void print(Decompiler d, Output out) { 33 | out.print(name); 34 | } 35 | 36 | @Override 37 | public boolean isBrief() { 38 | return true; 39 | } 40 | 41 | @Override 42 | public boolean isEnvironmentTable(Decompiler d) { 43 | return d.getVersion().isEnvironmentTable(name); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/unluac/decompile/expression/Vararg.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.expression; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | 7 | public class Vararg extends Expression { 8 | 9 | private final boolean multiple; 10 | 11 | public Vararg(int length, boolean multiple) { 12 | super(PRECEDENCE_ATOMIC); 13 | this.multiple = multiple; 14 | } 15 | 16 | @Override 17 | public void walk(Walker w) { 18 | w.visitExpression(this); 19 | } 20 | 21 | @Override 22 | public int getConstantIndex() { 23 | return -1; 24 | } 25 | 26 | @Override 27 | public void print(Decompiler d, Output out) { 28 | //out.print("..."); 29 | out.print(multiple ? "..." : "(...)"); 30 | } 31 | 32 | @Override 33 | public void printMultiple(Decompiler d, Output out) { 34 | out.print(multiple ? "..." : "(...)"); 35 | } 36 | 37 | @Override 38 | public boolean isMultiple() { 39 | return multiple; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/unluac/decompile/operation/CallOperation.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.operation; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.block.Block; 5 | import unluac.decompile.expression.FunctionCall; 6 | import unluac.decompile.statement.FunctionCallStatement; 7 | import unluac.decompile.statement.Statement; 8 | 9 | public class CallOperation extends Operation { 10 | 11 | private FunctionCall call; 12 | 13 | public CallOperation(int line, FunctionCall call) { 14 | super(line); 15 | this.call = call; 16 | } 17 | 18 | @Override 19 | public Statement process(Registers r, Block block) { 20 | return new FunctionCallStatement(call); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/unluac/decompile/operation/GlobalSet.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.operation; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.block.Block; 5 | import unluac.decompile.expression.ConstantExpression; 6 | import unluac.decompile.expression.Expression; 7 | import unluac.decompile.statement.Assignment; 8 | import unluac.decompile.statement.Statement; 9 | import unluac.decompile.target.GlobalTarget; 10 | 11 | public class GlobalSet extends Operation { 12 | 13 | private ConstantExpression global; 14 | private Expression value; 15 | 16 | public GlobalSet(int line, ConstantExpression global, Expression value) { 17 | super(line); 18 | this.global = global; 19 | this.value = value; 20 | } 21 | 22 | @Override 23 | public Statement process(Registers r, Block block) { 24 | return new Assignment(new GlobalTarget(global), value, line); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/unluac/decompile/operation/LoadNil.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.operation; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.block.Block; 5 | import unluac.decompile.expression.ConstantExpression; 6 | import unluac.decompile.expression.Expression; 7 | import unluac.decompile.statement.Assignment; 8 | import unluac.decompile.statement.Statement; 9 | 10 | public class LoadNil extends Operation { 11 | 12 | public final int registerFirst; 13 | public final int registerLast; 14 | 15 | public LoadNil(int line, int registerFirst, int registerLast) { 16 | super(line); 17 | this.registerFirst = registerFirst; 18 | this.registerLast = registerLast; 19 | } 20 | 21 | @Override 22 | public Statement process(Registers r, Block block) { 23 | int count = 0; 24 | Assignment assignment = new Assignment(); 25 | Expression nil = ConstantExpression.createNil(line); 26 | int scopeEnd = -1; 27 | for(int register = registerFirst; register <= registerLast; register++) { 28 | if(r.isAssignable(register, line)) { 29 | scopeEnd = r.getDeclaration(register, line).end; 30 | } 31 | } 32 | for(int register = registerFirst; register <= registerLast; register++) { 33 | r.setValue(register, line, nil); 34 | if(r.isAssignable(register, line) && r.getDeclaration(register, line).end == scopeEnd) { 35 | assignment.addLast(r.getTarget(register, line), nil, line); 36 | count++; 37 | } 38 | } 39 | if(count > 0) { 40 | return assignment; 41 | } else { 42 | return null; 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/unluac/decompile/operation/MultipleRegisterSet.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.operation; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.block.Block; 5 | import unluac.decompile.expression.Expression; 6 | import unluac.decompile.statement.Assignment; 7 | import unluac.decompile.statement.Statement; 8 | 9 | public class MultipleRegisterSet extends Operation { 10 | 11 | public final int registerFirst; 12 | public final int registerLast; 13 | public final Expression value; 14 | 15 | public MultipleRegisterSet(int line, int registerFirst, int registerLast, Expression value) { 16 | super(line); 17 | this.registerFirst = registerFirst; 18 | this.registerLast = registerLast; 19 | this.value = value; 20 | } 21 | 22 | @Override 23 | public Statement process(Registers r, Block block) { 24 | int count = 0; 25 | Assignment assignment = new Assignment(); 26 | for(int register = registerFirst; register <= registerLast; register++) { 27 | r.setValue(register, line, value); 28 | if(r.isAssignable(register, line)) { 29 | assignment.addLast(r.getTarget(register, line), value, line); 30 | count++; 31 | } 32 | } 33 | if(count > 0) { 34 | return assignment; 35 | } else { 36 | return null; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/unluac/decompile/operation/Operation.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.operation; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.block.Block; 5 | import unluac.decompile.statement.Statement; 6 | 7 | abstract public class Operation { 8 | 9 | public final int line; 10 | 11 | public Operation(int line) { 12 | this.line = line; 13 | } 14 | 15 | abstract public Statement process(Registers r, Block block); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/unluac/decompile/operation/RegisterSet.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.operation; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.block.Block; 5 | import unluac.decompile.expression.Expression; 6 | import unluac.decompile.statement.Assignment; 7 | import unluac.decompile.statement.Statement; 8 | 9 | public class RegisterSet extends Operation { 10 | 11 | public final int register; 12 | public final Expression value; 13 | 14 | public RegisterSet(int line, int register, Expression value) { 15 | super(line); 16 | this.register = register; 17 | this.value = value; 18 | /* 19 | if(value.isMultiple()) { 20 | System.out.println("-- multiple @" + register); 21 | } 22 | */ 23 | } 24 | 25 | @Override 26 | public Statement process(Registers r, Block block) { 27 | //System.out.println("-- processing register set " + register + "@" + line); 28 | r.setValue(register, line, value); 29 | /* 30 | if(value.isMultiple()) { 31 | System.out.println("-- process multiple @" + register); 32 | } 33 | */ 34 | if(r.isAssignable(register, line)) { 35 | //System.out.println("-- assignment!"); 36 | return new Assignment(r.getTarget(register, line), value, line); 37 | } else { 38 | return null; 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/unluac/decompile/operation/ReturnOperation.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.operation; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.block.Block; 5 | import unluac.decompile.expression.Expression; 6 | import unluac.decompile.statement.Return; 7 | import unluac.decompile.statement.Statement; 8 | 9 | public class ReturnOperation extends Operation { 10 | 11 | private Expression[] values; 12 | 13 | public ReturnOperation(int line, Expression value) { 14 | super(line); 15 | values = new Expression[1]; 16 | values[0] = value; 17 | } 18 | 19 | public ReturnOperation(int line, Expression[] values) { 20 | super(line); 21 | this.values = values; 22 | } 23 | 24 | @Override 25 | public Statement process(Registers r, Block block) { 26 | return new Return(values); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/unluac/decompile/operation/TableSet.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.operation; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.block.Block; 5 | import unluac.decompile.expression.Expression; 6 | import unluac.decompile.expression.TableLiteral; 7 | import unluac.decompile.statement.Assignment; 8 | import unluac.decompile.statement.Statement; 9 | import unluac.decompile.target.TableTarget; 10 | 11 | public class TableSet extends Operation { 12 | 13 | private Expression table; 14 | private Expression index; 15 | private Expression value; 16 | private boolean isTable; 17 | private int timestamp; 18 | 19 | public TableSet(int line, Expression table, Expression index, Expression value, boolean isTable, int timestamp) { 20 | super(line); 21 | this.table = table; 22 | this.index = index; 23 | this.value = value; 24 | this.isTable = isTable; 25 | this.timestamp = timestamp; 26 | } 27 | 28 | @Override 29 | public Statement process(Registers r, Block block) { 30 | // .isTableLiteral() is sufficient when there is debugging info 31 | if(!r.isStrippedDefault && table.isTableLiteral() && (value.isMultiple() || table.isNewEntryAllowed())) { 32 | table.addEntry(new TableLiteral.Entry(index, value, !isTable, timestamp)); 33 | return null; 34 | } else { 35 | return new Assignment(new TableTarget(table, index), value, line); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/unluac/decompile/operation/UpvalueSet.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.operation; 2 | 3 | import unluac.decompile.Registers; 4 | import unluac.decompile.block.Block; 5 | import unluac.decompile.expression.Expression; 6 | import unluac.decompile.statement.Assignment; 7 | import unluac.decompile.statement.Statement; 8 | import unluac.decompile.target.UpvalueTarget; 9 | 10 | public class UpvalueSet extends Operation { 11 | 12 | private UpvalueTarget target; 13 | private Expression value; 14 | 15 | public UpvalueSet(int line, String upvalue, Expression value) { 16 | super(line); 17 | target = new UpvalueTarget(upvalue); 18 | this.value = value; 19 | } 20 | 21 | @Override 22 | public Statement process(Registers r, Block block) { 23 | return new Assignment(target, value, line); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/unluac/decompile/statement/Declare.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.statement; 2 | 3 | import java.util.List; 4 | 5 | import unluac.decompile.Declaration; 6 | import unluac.decompile.Decompiler; 7 | import unluac.decompile.Output; 8 | import unluac.decompile.Walker; 9 | 10 | public class Declare extends Statement { 11 | 12 | private final List decls; 13 | 14 | public Declare(List decls) { 15 | this.decls = decls; 16 | } 17 | 18 | @Override 19 | public void walk(Walker w) { 20 | w.visitStatement(this); 21 | } 22 | 23 | @Override 24 | public void print(Decompiler d, Output out) { 25 | out.print("local "); 26 | out.print(decls.get(0).name); 27 | for(int i = 1; i < decls.size(); i++) { 28 | out.print(", "); 29 | out.print(decls.get(i).name); 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/unluac/decompile/statement/FunctionCallStatement.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.statement; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | import unluac.decompile.expression.FunctionCall; 7 | 8 | public class FunctionCallStatement extends Statement { 9 | 10 | private FunctionCall call; 11 | 12 | public FunctionCallStatement(FunctionCall call) { 13 | this.call = call; 14 | } 15 | 16 | @Override 17 | public void walk(Walker w) { 18 | w.visitStatement(this); 19 | call.walk(w); 20 | } 21 | 22 | @Override 23 | public void print(Decompiler d, Output out) { 24 | call.print(d, out); 25 | } 26 | 27 | @Override 28 | public boolean beginsWithParen() { 29 | return call.beginsWithParen(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/unluac/decompile/statement/Label.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.statement; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | 7 | public class Label extends Statement { 8 | 9 | private String name; 10 | 11 | public Label(int line) { 12 | name = "lbl_" + line; 13 | } 14 | 15 | public void walk(Walker w) { 16 | w.visitStatement(this); 17 | } 18 | 19 | @Override 20 | public void print(Decompiler d, Output out) { 21 | out.print("::" + name + "::"); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/unluac/decompile/statement/Return.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.statement; 2 | 3 | import java.util.ArrayList; 4 | 5 | import unluac.decompile.Decompiler; 6 | import unluac.decompile.Output; 7 | import unluac.decompile.Walker; 8 | import unluac.decompile.expression.Expression; 9 | 10 | public class Return extends Statement { 11 | 12 | private Expression[] values; 13 | 14 | public Return() { 15 | values = new Expression[0]; 16 | } 17 | 18 | public Return(Expression value) { 19 | values = new Expression[1]; 20 | values[0] = value; 21 | } 22 | 23 | public Return(Expression[] values) { 24 | this.values = values; 25 | } 26 | 27 | public void walk(Walker w) { 28 | w.visitStatement(this); 29 | for(Expression expression : values) { 30 | expression.walk(w); 31 | } 32 | } 33 | 34 | @Override 35 | public void print(Decompiler d, Output out) { 36 | out.print("do "); 37 | printTail(d, out); 38 | out.print(" end"); 39 | } 40 | 41 | @Override 42 | public void printTail(Decompiler d, Output out) { 43 | out.print("return"); 44 | if(values.length > 0) { 45 | out.print(" "); 46 | ArrayList rtns = new ArrayList(values.length); 47 | for(Expression value : values) { 48 | rtns.add(value); 49 | } 50 | Expression.printSequence(d, out, rtns, false, true); 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/unluac/decompile/statement/Statement.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.statement; 2 | 3 | import java.util.List; 4 | 5 | import unluac.decompile.Decompiler; 6 | import unluac.decompile.Function; 7 | import unluac.decompile.Output; 8 | import unluac.decompile.Walker; 9 | 10 | abstract public class Statement { 11 | 12 | /** 13 | * Prints out a sequences of statements on separate lines. Correctly 14 | * informs the last statement that it is last in a block. 15 | */ 16 | public static void printSequence(Decompiler d, Output out, List stmts) { 17 | int n = stmts.size(); 18 | for(int i = 0; i < n; i++) { 19 | boolean last = (i + 1 == n); 20 | Statement stmt = stmts.get(i); 21 | if(stmt.beginsWithParen() && (i > 0 || d.getVersion().allowpreceedingsemicolon.get())) { 22 | out.print(";"); 23 | } 24 | if(last) { 25 | stmt.printTail(d, out); 26 | } else { 27 | stmt.print(d, out); 28 | } 29 | if(!stmt.suppressNewline()) { 30 | out.println(); 31 | } 32 | } 33 | } 34 | 35 | abstract public void print(Decompiler d, Output out); 36 | 37 | public void printTail(Decompiler d, Output out) { 38 | print(d, out); 39 | } 40 | 41 | public String comment; 42 | 43 | public void addComment(String comment) { 44 | this.comment = comment; 45 | } 46 | 47 | public abstract void walk(Walker w); 48 | 49 | public boolean beginsWithParen() { 50 | return false; 51 | } 52 | 53 | public boolean suppressNewline() { 54 | return false; 55 | } 56 | 57 | public boolean useConstant(Function f, int index) { 58 | return false; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/unluac/decompile/target/GlobalTarget.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.target; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | import unluac.decompile.expression.ConstantExpression; 7 | import unluac.decompile.expression.Expression; 8 | 9 | public class GlobalTarget extends Target { 10 | 11 | private final Expression name; 12 | 13 | public GlobalTarget(ConstantExpression name) { 14 | this.name = name; 15 | } 16 | 17 | @Override 18 | public void walk(Walker w) { 19 | name.walk(w); 20 | } 21 | 22 | @Override 23 | public void print(Decompiler d, Output out, boolean declare) { 24 | out.print(name.asName()); 25 | } 26 | 27 | @Override 28 | public void printMethod(Decompiler d, Output out) { 29 | throw new IllegalStateException(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/unluac/decompile/target/TableTarget.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.target; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | import unluac.decompile.expression.Expression; 7 | import unluac.decompile.expression.TableReference; 8 | 9 | public class TableTarget extends Target { 10 | 11 | private final Expression table; 12 | private final Expression index; 13 | 14 | public TableTarget(Expression table, Expression index) { 15 | this.table = table; 16 | this.index = index; 17 | } 18 | 19 | @Override 20 | public void walk(Walker w) { 21 | table.walk(w); 22 | index.walk(w); 23 | } 24 | 25 | @Override 26 | public void print(Decompiler d, Output out, boolean declare) { 27 | new TableReference(table, index).print(d, out); 28 | } 29 | 30 | @Override 31 | public void printMethod(Decompiler d, Output out) { 32 | table.print(d, out); 33 | out.print(":"); 34 | out.print(index.asName()); 35 | } 36 | 37 | @Override 38 | public boolean isFunctionName() { 39 | if(!index.isIdentifier()) { 40 | return false; 41 | } 42 | if(!table.isDotChain()) { 43 | return false; 44 | } 45 | return true; 46 | } 47 | 48 | @Override 49 | public boolean beginsWithParen() { 50 | return table.isUngrouped() || table.beginsWithParen(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/unluac/decompile/target/Target.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.target; 2 | 3 | import unluac.decompile.Declaration; 4 | import unluac.decompile.Decompiler; 5 | import unluac.decompile.Output; 6 | import unluac.decompile.Walker; 7 | 8 | abstract public class Target { 9 | 10 | abstract public void walk(Walker w); 11 | 12 | abstract public void print(Decompiler d, Output out, boolean declare); 13 | 14 | abstract public void printMethod(Decompiler d, Output out); 15 | 16 | public boolean isDeclaration(Declaration decl) { 17 | return false; 18 | } 19 | 20 | public boolean isLocal() { 21 | return false; 22 | } 23 | 24 | public int getIndex() { 25 | throw new IllegalStateException(); 26 | } 27 | 28 | public boolean isFunctionName() { 29 | return true; 30 | } 31 | 32 | public boolean beginsWithParen() { 33 | return false; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/unluac/decompile/target/UpvalueTarget.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.target; 2 | 3 | import unluac.decompile.Decompiler; 4 | import unluac.decompile.Output; 5 | import unluac.decompile.Walker; 6 | 7 | public class UpvalueTarget extends Target{ 8 | 9 | private final String name; 10 | 11 | public UpvalueTarget(String name) { 12 | this.name = name; 13 | } 14 | 15 | @Override 16 | public void walk(Walker w) {} 17 | 18 | @Override 19 | public void print(Decompiler d, Output out, boolean declare) { 20 | out.print(name); 21 | } 22 | 23 | @Override 24 | public void printMethod(Decompiler d, Output out) { 25 | throw new IllegalStateException(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/unluac/decompile/target/VariableTarget.java: -------------------------------------------------------------------------------- 1 | package unluac.decompile.target; 2 | 3 | import unluac.decompile.Declaration; 4 | import unluac.decompile.Decompiler; 5 | import unluac.decompile.Output; 6 | import unluac.decompile.Walker; 7 | 8 | public class VariableTarget extends Target { 9 | 10 | public final Declaration decl; 11 | 12 | public VariableTarget(Declaration decl) { 13 | this.decl = decl; 14 | } 15 | 16 | @Override 17 | public void walk(Walker w) {} 18 | 19 | @Override 20 | public void print(Decompiler d, Output out, boolean declare) { 21 | out.print(decl.name); 22 | if(declare && decl.tbc) { 23 | out.print(" "); 24 | } 25 | } 26 | 27 | @Override 28 | public void printMethod(Decompiler d, Output out) { 29 | throw new IllegalStateException(); 30 | } 31 | 32 | @Override 33 | public boolean isDeclaration(Declaration decl) { 34 | return this.decl == decl; 35 | } 36 | 37 | @Override 38 | public boolean isLocal() { 39 | return true; 40 | } 41 | 42 | @Override 43 | public int getIndex() { 44 | return decl.register; 45 | } 46 | 47 | public boolean equals(Object obj) { 48 | if(obj instanceof VariableTarget) { 49 | VariableTarget t = (VariableTarget) obj; 50 | return decl == t.decl; 51 | } else { 52 | return false; 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/unluac/parse/BInteger.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | import java.math.BigInteger; 4 | import java.util.ArrayList; 5 | 6 | public class BInteger extends BObject { 7 | 8 | private final BigInteger big; 9 | private final int n; 10 | 11 | private static BigInteger MAX_INT = null; 12 | private static BigInteger MIN_INT = null; 13 | 14 | public BInteger(BInteger b) { 15 | this.big = b.big; 16 | this.n = b.n; 17 | } 18 | 19 | public BInteger(int n) { 20 | this.big = null; 21 | this.n = n; 22 | } 23 | 24 | public BInteger(BigInteger big) { 25 | this.big = big; 26 | this.n = 0; 27 | if(MAX_INT == null) { 28 | MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); 29 | MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE); 30 | } 31 | } 32 | 33 | public int asInt() { 34 | if(big == null) { 35 | return n; 36 | } else if(big.compareTo(MAX_INT) > 0 || big.compareTo(MIN_INT) < 0) { 37 | throw new IllegalStateException("The size of an integer is outside the range that unluac can handle."); 38 | } else { 39 | return big.intValue(); 40 | } 41 | } 42 | 43 | public byte[] littleEndianBytes(int size) { 44 | ArrayList bytes = new ArrayList(); 45 | if(big == null) { 46 | if(size >= 1) bytes.add((byte)(n & 0xFF)); 47 | if(size >= 2) bytes.add((byte)((n >>> 8) & 0xFF)); 48 | if(size >= 3) bytes.add((byte)((n >>> 16) & 0xFF)); 49 | if(size >= 4) bytes.add((byte)((n >>> 24) & 0xFF)); 50 | } else { 51 | BigInteger n = big; 52 | boolean negate = false; 53 | if(n.signum() < 0) { 54 | n = n.negate(); 55 | n = n.subtract(BigInteger.ONE); 56 | negate = true; 57 | } 58 | BigInteger b256 = BigInteger.valueOf(256); 59 | BigInteger b255 = BigInteger.valueOf(255); 60 | while(n.compareTo(b256) < 0 && size > 0) { 61 | int v = n.and(b255).intValue(); 62 | if(negate) { 63 | v = ~v; 64 | } 65 | bytes.add((byte)v); 66 | n = n.divide(b256); 67 | size--; 68 | } 69 | } 70 | while(size > bytes.size()) bytes.add((byte)0); 71 | byte[] array = new byte[bytes.size()]; 72 | for(int i = 0; i < bytes.size(); i++) { 73 | array[i] = bytes.get(i); 74 | } 75 | return array; 76 | } 77 | 78 | public byte[] compressedBytes() { 79 | BigInteger value = big; 80 | if(value == null) { 81 | value = BigInteger.valueOf(n); 82 | } 83 | if(value.compareTo(BigInteger.ZERO) == 0) { 84 | return new byte[] {0}; 85 | } 86 | ArrayList bytes = new ArrayList((value.bitCount() + 6) / 7); 87 | BigInteger limit = BigInteger.valueOf(0x7F); 88 | while(value.compareTo(BigInteger.ZERO) > 0) { 89 | bytes.add((byte) value.and(limit).intValue()); 90 | value = value.shiftRight(7); 91 | } 92 | byte[] array = new byte[bytes.size()]; 93 | for(int i = 0; i < bytes.size(); i++) { 94 | array[i] = bytes.get(i); 95 | } 96 | return array; 97 | } 98 | 99 | public void iterate(Runnable thunk) { 100 | if(big == null) { 101 | int i = n; 102 | while(i-- != 0) { 103 | thunk.run(); 104 | } 105 | } else { 106 | BigInteger i = big; 107 | while(i.signum() > 0) { 108 | thunk.run(); 109 | i = i.subtract(BigInteger.ONE); 110 | } 111 | } 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/unluac/parse/BList.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | import java.util.Iterator; 4 | import java.util.List; 5 | 6 | public class BList extends BObject { 7 | 8 | public final BInteger length; 9 | private final List values; 10 | 11 | public BList(BInteger length, List values) { 12 | this.length = length; 13 | this.values = values; 14 | } 15 | 16 | public T get(int index) { 17 | return values.get(index); 18 | } 19 | 20 | public Iterator iterator() { 21 | return values.iterator(); 22 | } 23 | 24 | public T[] asArray(final T[] array) { 25 | length.iterate(new Runnable() { 26 | 27 | private int i = 0; 28 | 29 | @Override 30 | public void run() { 31 | array[i] = values.get(i); 32 | i++; 33 | } 34 | 35 | }); 36 | return array; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/unluac/parse/BObject.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | abstract public class BObject { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/unluac/parse/BObjectType.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.nio.ByteBuffer; 6 | import java.util.ArrayList; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | 10 | abstract public class BObjectType { 11 | 12 | abstract public T parse(ByteBuffer buffer, BHeader header); 13 | 14 | abstract public void write(OutputStream out, BHeader header, T object) throws IOException; 15 | 16 | public final BList parseList(final ByteBuffer buffer, final BHeader header) { 17 | BInteger length = header.integer.parse(buffer, header); 18 | final List values = new ArrayList(); 19 | length.iterate(new Runnable() { 20 | 21 | @Override 22 | public void run() { 23 | values.add(parse(buffer, header)); 24 | } 25 | 26 | }); 27 | return new BList(length, values); 28 | } 29 | 30 | public final void writeList(OutputStream out, BHeader header, T[] array) throws IOException { 31 | header.integer.write(out, header, new BInteger(array.length)); 32 | for(T object : array) { 33 | write(out, header, object); 34 | } 35 | } 36 | 37 | public final void writeList(OutputStream out, BHeader header, BList blist) throws IOException { 38 | header.integer.write(out, header, blist.length); 39 | Iterator it = blist.iterator(); 40 | while(it.hasNext()) { 41 | write(out, header, it.next()); 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/unluac/parse/LAbsLineInfo.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | public class LAbsLineInfo extends LObject { 4 | 5 | public final int pc; 6 | public final int line; 7 | 8 | public LAbsLineInfo(int pc, int line) { 9 | this.pc = pc; 10 | this.line = line; 11 | } 12 | 13 | @Override 14 | public boolean equals(Object o) { 15 | if(o instanceof LAbsLineInfo) { 16 | LAbsLineInfo other = (LAbsLineInfo) o; 17 | return pc == other.pc && line == other.line; 18 | } else { 19 | return false; 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/unluac/parse/LAbsLineInfoType.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.nio.ByteBuffer; 6 | 7 | public class LAbsLineInfoType extends BObjectType { 8 | 9 | @Override 10 | public LAbsLineInfo parse(ByteBuffer buffer, BHeader header) { 11 | int pc = header.integer.parse(buffer, header).asInt(); 12 | int line = header.integer.parse(buffer, header).asInt(); 13 | return new LAbsLineInfo(pc, line); 14 | } 15 | 16 | @Override 17 | public void write(OutputStream out, BHeader header, LAbsLineInfo object) throws IOException { 18 | header.integer.write(out, header, new BInteger(object.pc)); 19 | header.integer.write(out, header, new BInteger(object.line)); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/unluac/parse/LBoolean.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | public class LBoolean extends LObject { 4 | 5 | public static final LBoolean LTRUE = new LBoolean(true); 6 | public static final LBoolean LFALSE = new LBoolean(false); 7 | 8 | private final boolean value; 9 | 10 | private LBoolean(boolean value) { 11 | this.value = value; 12 | } 13 | 14 | public boolean value() { 15 | return value; 16 | } 17 | 18 | public String toPrintString() { 19 | return Boolean.toString(value); 20 | } 21 | 22 | @Override 23 | public boolean equals(Object o) { 24 | return this == o; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/unluac/parse/LBooleanType.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.nio.ByteBuffer; 6 | 7 | 8 | public class LBooleanType extends BObjectType { 9 | 10 | @Override 11 | public LBoolean parse(ByteBuffer buffer, BHeader header) { 12 | int value = buffer.get(); 13 | if((value & 0xFFFFFFFE) != 0) { 14 | throw new IllegalStateException(); 15 | } else { 16 | LBoolean bool = value == 0 ? LBoolean.LFALSE : LBoolean.LTRUE; 17 | if(header.debug) { 18 | System.out.println("-- parsed " + bool); 19 | } 20 | return bool; 21 | } 22 | } 23 | 24 | @Override 25 | public void write(OutputStream out, BHeader header, LBoolean object) throws IOException { 26 | int value = object.value() ? 1 : 0; 27 | out.write(value); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/unluac/parse/LFunction.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | public class LFunction extends BObject { 4 | 5 | public BHeader header; 6 | public LString name; 7 | public int linedefined; 8 | public int lastlinedefined; 9 | public LFunction parent; 10 | public int[] code; 11 | public int[] lines; 12 | public LAbsLineInfo[] abslineinfo; 13 | public LLocal[] locals; 14 | public LObject[] constants; 15 | public LUpvalue[] upvalues; 16 | public LFunction[] functions; 17 | public int maximumStackSize; 18 | public int numUpvalues; 19 | public int numParams; 20 | public int vararg; 21 | public boolean stripped; 22 | 23 | public LFunction(BHeader header, LString name, int linedefined, int lastlinedefined, int[] code, int[] lines, LAbsLineInfo[] abslineinfo, LLocal[] locals, LObject[] constants, LUpvalue[] upvalues, LFunction[] functions, int maximumStackSize, int numUpValues, int numParams, int vararg) { 24 | this.header = header; 25 | this.name = name; 26 | this.linedefined = linedefined; 27 | this.lastlinedefined = lastlinedefined; 28 | this.code = code; 29 | this.lines = lines; 30 | this.abslineinfo = abslineinfo; 31 | this.locals = locals; 32 | this.constants = constants; 33 | this.upvalues = upvalues; 34 | this.functions = functions; 35 | this.maximumStackSize = maximumStackSize; 36 | this.numUpvalues = numUpValues; 37 | this.numParams = numParams; 38 | this.vararg = vararg; 39 | this.stripped = false; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/unluac/parse/LHeader.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | import unluac.decompile.CodeExtract; 4 | 5 | public class LHeader extends BObject { 6 | 7 | public static enum LEndianness { 8 | BIG, 9 | LITTLE; 10 | } 11 | 12 | public final int format; 13 | public final LEndianness endianness; 14 | public final BIntegerType integer; 15 | public final BIntegerType sizeT; 16 | public final LBooleanType bool; 17 | public final LNumberType number; 18 | public final LNumberType linteger; 19 | public final LNumberType lfloat; 20 | public final LStringType string; 21 | public final LConstantType constant; 22 | public final LAbsLineInfoType abslineinfo; 23 | public final LLocalType local; 24 | public final LUpvalueType upvalue; 25 | public final LFunctionType function; 26 | public final CodeExtract extractor; 27 | 28 | public LHeader(int format, LEndianness endianness, BIntegerType integer, BIntegerType sizeT, LBooleanType bool, LNumberType number, LNumberType linteger, LNumberType lfloat, LStringType string, LConstantType constant, LAbsLineInfoType abslineinfo, LLocalType local, LUpvalueType upvalue, LFunctionType function, CodeExtract extractor) { 29 | this.format = format; 30 | this.endianness = endianness; 31 | this.integer = integer; 32 | this.sizeT = sizeT; 33 | this.bool = bool; 34 | this.number = number; 35 | this.linteger = linteger; 36 | this.lfloat = lfloat; 37 | this.string = string; 38 | this.constant = constant; 39 | this.abslineinfo = abslineinfo; 40 | this.local = local; 41 | this.upvalue = upvalue; 42 | this.function = function; 43 | this.extractor = extractor; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/unluac/parse/LLocal.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | 4 | public class LLocal extends BObject { 5 | 6 | public final LString name; 7 | public final int start; 8 | public final int end; 9 | 10 | /* Used by the decompiler for annotation. */ 11 | public boolean forLoop = false; 12 | 13 | public LLocal(LString name, BInteger start, BInteger end) { 14 | this.name = name; 15 | this.start = start.asInt(); 16 | this.end = end.asInt(); 17 | } 18 | 19 | public String toString() { 20 | return name.deref(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/unluac/parse/LLocalType.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.nio.ByteBuffer; 6 | 7 | 8 | public class LLocalType extends BObjectType { 9 | 10 | @Override 11 | public LLocal parse(ByteBuffer buffer, BHeader header) { 12 | LString name = header.string.parse(buffer, header); 13 | BInteger start = header.integer.parse(buffer, header); 14 | BInteger end = header.integer.parse(buffer, header); 15 | if(header.debug) { 16 | System.out.print("-- parsing local, name: "); 17 | System.out.print(name); 18 | System.out.print(" from " + start.asInt() + " to " + end.asInt()); 19 | System.out.println(); 20 | } 21 | return new LLocal(name, start, end); 22 | } 23 | 24 | @Override 25 | public void write(OutputStream out, BHeader header, LLocal object) throws IOException { 26 | header.string.write(out, header, object.name); 27 | header.integer.write(out, header, new BInteger(object.start)); 28 | header.integer.write(out, header, new BInteger(object.end)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/unluac/parse/LNil.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | public class LNil extends LObject{ 4 | 5 | public static final LNil NIL = new LNil(); 6 | 7 | private LNil() { 8 | 9 | } 10 | 11 | @Override 12 | public String toPrintString() { 13 | return "nil"; 14 | } 15 | 16 | @Override 17 | public boolean equals(Object o) { 18 | return this == o; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/unluac/parse/LObject.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | 4 | abstract public class LObject extends BObject { 5 | 6 | public String deref() { 7 | throw new IllegalStateException(); 8 | } 9 | 10 | public String toPrintString() { 11 | throw new IllegalStateException(); 12 | } 13 | 14 | abstract public boolean equals(Object o); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/unluac/parse/LSourceLines.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | public class LSourceLines { 6 | 7 | public static LSourceLines parse(ByteBuffer buffer) { 8 | int number = buffer.getInt(); 9 | while(number-- > 0) { 10 | buffer.getInt(); 11 | } 12 | return null; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/unluac/parse/LString.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | import unluac.util.StringUtils; 4 | 5 | public class LString extends LObject { 6 | 7 | public final String value; 8 | public boolean islong; 9 | 10 | public LString(String value) { 11 | this.value = value; 12 | islong = false; 13 | } 14 | 15 | @Override 16 | public String deref() { 17 | return value; 18 | } 19 | 20 | @Override 21 | public String toPrintString() { 22 | String prefix = ""; 23 | if(islong) prefix = "L"; 24 | return prefix + StringUtils.toPrintString(value); 25 | } 26 | 27 | @Override 28 | public boolean equals(Object o) { 29 | if(o instanceof LString) { 30 | LString os = (LString) o; 31 | return os.value.equals(value) && os.islong == islong; 32 | } 33 | return false; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/unluac/parse/LUpvalue.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | public class LUpvalue extends BObject { 4 | 5 | public boolean instack; 6 | public int idx; 7 | 8 | public String name; 9 | public LString bname; 10 | public int kind; 11 | 12 | public boolean equals(Object obj) { 13 | if(obj instanceof LUpvalue) { 14 | LUpvalue upvalue = (LUpvalue) obj; 15 | if(!(instack == upvalue.instack && idx == upvalue.idx && kind == upvalue.kind)) { 16 | return false; 17 | } 18 | if(name == upvalue.name) { 19 | return true; 20 | } 21 | return name != null && name.equals(upvalue.name); 22 | } else { 23 | return false; 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/unluac/parse/LUpvalueType.java: -------------------------------------------------------------------------------- 1 | package unluac.parse; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.nio.ByteBuffer; 6 | 7 | import unluac.Version; 8 | 9 | public abstract class LUpvalueType extends BObjectType { 10 | 11 | public static LUpvalueType get(Version.UpvalueType type) { 12 | switch(type) { 13 | case LUA50: return new LUpvalueType50(); 14 | case LUA54: return new LUpvalueType54(); 15 | default: throw new IllegalStateException(); 16 | } 17 | } 18 | 19 | } 20 | 21 | class LUpvalueType50 extends LUpvalueType { 22 | 23 | @Override 24 | public LUpvalue parse(ByteBuffer buffer, BHeader header) { 25 | LUpvalue upvalue = new LUpvalue(); 26 | upvalue.instack = buffer.get() != 0; 27 | upvalue.idx = 0xFF & buffer.get(); 28 | upvalue.kind = -1; 29 | return upvalue; 30 | } 31 | 32 | @Override 33 | public void write(OutputStream out, BHeader header, LUpvalue object) throws IOException { 34 | out.write((byte)(object.instack ? 1 : 0)); 35 | out.write(object.idx); 36 | } 37 | } 38 | 39 | class LUpvalueType54 extends LUpvalueType { 40 | 41 | @Override 42 | public LUpvalue parse(ByteBuffer buffer, BHeader header) { 43 | LUpvalue upvalue = new LUpvalue(); 44 | upvalue.instack = buffer.get() != 0; 45 | upvalue.idx = 0xFF & buffer.get(); 46 | upvalue.kind = 0xFF & buffer.get(); 47 | return upvalue; 48 | } 49 | 50 | @Override 51 | public void write(OutputStream out, BHeader header, LUpvalue object) throws IOException { 52 | out.write((byte)(object.instack ? 1 : 0)); 53 | out.write(object.idx); 54 | out.write(object.kind); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/unluac/test/LuaC.java: -------------------------------------------------------------------------------- 1 | package unluac.test; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | 7 | public class LuaC { 8 | 9 | public static void compile(LuaSpec spec, String in, String out) throws IOException { 10 | String luac = spec.getLuaCName(); 11 | luac = System.getProperty(luac, luac); 12 | if(System.getProperty("os.name").contains("Windows")) { 13 | luac = luac + ".exe"; 14 | } 15 | String[] args = spec.getArgs(); 16 | String[] full = new String[4 + args.length]; 17 | int i = 0; 18 | full[i++] = luac; 19 | for(String arg : args) { 20 | full[i++] = arg; 21 | } 22 | full[i++] = "-o"; 23 | full[i++] = out; 24 | full[i++] = in; 25 | ProcessBuilder pb = new ProcessBuilder(full); 26 | pb.directory(null); 27 | Process p = pb.start(); 28 | while(true) { 29 | try { 30 | if(p.waitFor() == 0) { 31 | return; 32 | } else { 33 | BufferedReader r = new BufferedReader(new InputStreamReader(p.getErrorStream())); 34 | String line = null; 35 | do { 36 | line = r.readLine(); 37 | if(line != null) { 38 | System.err.println(line); 39 | } 40 | } while(line != null); 41 | 42 | throw new IOException("luac failed on file: " + in); 43 | } 44 | } catch(InterruptedException e ) { 45 | 46 | } 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/unluac/test/LuaSpec.java: -------------------------------------------------------------------------------- 1 | package unluac.test; 2 | 3 | public class LuaSpec { 4 | 5 | public enum NumberFormat { 6 | DEFAULT, 7 | FLOAT, 8 | INT32, 9 | INT64 10 | } 11 | 12 | public LuaSpec() { 13 | this.isDefault = true; 14 | this.version = 0; 15 | this.numberFormat = NumberFormat.DEFAULT; 16 | this.strip = false; 17 | } 18 | 19 | public LuaSpec(int version) { 20 | this.isDefault = false; 21 | this.version = version; 22 | this.numberFormat = NumberFormat.DEFAULT; 23 | this.strip = false; 24 | } 25 | 26 | public String id() { 27 | String id = "lua"; 28 | id += Integer.toHexString(version); 29 | return id; 30 | } 31 | 32 | public void setNumberFormat(NumberFormat format) { 33 | this.numberFormat = format; 34 | } 35 | 36 | public void setStrip(boolean strip) { 37 | this.strip = strip; 38 | } 39 | 40 | public String getLuaCName() { 41 | return "luac" + getVersionString() + getNumberFormatString(); 42 | } 43 | 44 | public String[] getArgs() { 45 | if(strip) { 46 | return new String[] {"-s"}; 47 | } else { 48 | return new String[] {}; 49 | } 50 | } 51 | 52 | public boolean compatible(String filename) { 53 | int version = 0; 54 | int underscore = filename.indexOf('_'); 55 | if(underscore != -1) { 56 | String prefix = filename.substring(0, underscore); 57 | try { 58 | version = Integer.parseInt(prefix, 16); 59 | } catch(NumberFormatException e) {} 60 | } 61 | return version == 0 || this.version >= version; 62 | } 63 | 64 | private String getVersionString() { 65 | if(isDefault) { 66 | return ""; 67 | } else { 68 | return Integer.toHexString(version); 69 | } 70 | } 71 | 72 | private String getNumberFormatString() { 73 | switch(numberFormat) { 74 | case DEFAULT: 75 | return ""; 76 | case FLOAT: 77 | return "_float"; 78 | case INT32: 79 | return "_int32"; 80 | case INT64: 81 | return "_int64"; 82 | default: 83 | throw new IllegalStateException(); 84 | } 85 | } 86 | 87 | private boolean isDefault; 88 | private int version; 89 | private NumberFormat numberFormat; 90 | private boolean strip; 91 | } 92 | -------------------------------------------------------------------------------- /src/unluac/test/RunExtendedTests.java: -------------------------------------------------------------------------------- 1 | package unluac.test; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.FileSystem; 6 | import java.nio.file.FileSystems; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | public class RunExtendedTests { 13 | 14 | private static void gatherTests(Path base, Path folder, List files) throws IOException { 15 | for(Path file : Files.newDirectoryStream(folder, "*.lua")) { 16 | String relative = base.relativize(file).toString(); 17 | files.add(relative.substring(0, relative.length() - 4)); 18 | } 19 | for(Path dir : Files.newDirectoryStream(folder)) { 20 | if(Files.isDirectory(dir)) { 21 | gatherTests(base, dir, files); 22 | } 23 | } 24 | } 25 | 26 | public static void main(String[] args) throws IOException { 27 | FileSystem fs = FileSystems.getDefault(); 28 | Path luatest = fs.getPath(args[0]); 29 | TestReport report = new TestReport(); 30 | for(int version = 0x50; version <= 0x54; version++) { 31 | LuaSpec spec = new LuaSpec(version); 32 | UnluacSpec uspec = new UnluacSpec(); 33 | System.out.println(spec.id()); 34 | for(Path subfolder : Files.newDirectoryStream(luatest)) { 35 | if(Files.isDirectory(subfolder) && spec.compatible(subfolder.getFileName().toString())) { 36 | List files = new ArrayList(); 37 | gatherTests(subfolder, subfolder, files); 38 | TestSuite suite = new TestSuite(subfolder.getFileName().toString(), subfolder.toString() + File.separator, files.toArray(new String[files.size()])); 39 | System.out.print("\t" + subfolder.getFileName().toString()); 40 | suite.run(spec, uspec, report); 41 | System.out.println(); 42 | } 43 | } 44 | } 45 | report.report(System.out); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/unluac/test/RunTest.java: -------------------------------------------------------------------------------- 1 | package unluac.test; 2 | 3 | import java.io.IOException; 4 | 5 | public class RunTest { 6 | 7 | public static void main(String[] args) throws IOException { 8 | LuaSpec spec = new LuaSpec(0x54); 9 | UnluacSpec uspec = new UnluacSpec(); 10 | //uspec.disassemble = true; 11 | if(TestFiles.suite.run(spec, uspec, args[0])) { 12 | System.exit(0); 13 | } else { 14 | System.exit(1); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/unluac/test/RunTests.java: -------------------------------------------------------------------------------- 1 | package unluac.test; 2 | 3 | import java.io.IOException; 4 | 5 | public class RunTests { 6 | 7 | public static void main(String[] args) throws IOException { 8 | boolean result = true; 9 | TestReport report = new TestReport(); 10 | for(int version = 0x50; version <= 0x54; version++) { 11 | LuaSpec spec = new LuaSpec(version); 12 | UnluacSpec uspec = new UnluacSpec(); 13 | System.out.print("lua" + Integer.toHexString(version)); 14 | result = result & TestFiles.suite.run(spec, uspec, report); 15 | System.out.println(); 16 | } 17 | report.report(System.out); 18 | if(result) { 19 | System.exit(0); 20 | } else { 21 | System.exit(1); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/unluac/test/TestReport.java: -------------------------------------------------------------------------------- 1 | package unluac.test; 2 | 3 | import java.io.PrintStream; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | public class TestReport { 8 | 9 | private int passed = 0; 10 | private int failed = 0; 11 | private int skipped = 0; 12 | 13 | private List failedTests = new ArrayList(); 14 | private List skippedTests = new ArrayList(); 15 | 16 | public void report(PrintStream out) { 17 | if(failed == 0 && skipped == 0) { 18 | out.println("All tests passed!"); 19 | } else { 20 | for(String failed : failedTests) { 21 | out.println("Failed: " + failed); 22 | } 23 | for(String skipped : skippedTests) { 24 | out.println("Skipped: " + skipped); 25 | } 26 | out.println("Failed " + failed + " of " + (failed + passed) + " tests, skipped " + skipped + " tests."); 27 | } 28 | } 29 | 30 | public void result(String test, TestResult result) { 31 | switch(result) { 32 | case OK: 33 | passed++; 34 | break; 35 | case FAILED: 36 | failedTests.add(test); 37 | failed++; 38 | break; 39 | case SKIPPED: 40 | skippedTests.add(test); 41 | skipped++; 42 | break; 43 | default: 44 | throw new IllegalStateException(); 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/unluac/test/TestResult.java: -------------------------------------------------------------------------------- 1 | package unluac.test; 2 | 3 | public enum TestResult { 4 | 5 | OK, SKIPPED, FAILED 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/unluac/test/UnluacSpec.java: -------------------------------------------------------------------------------- 1 | package unluac.test; 2 | 3 | import java.io.IOException; 4 | 5 | import unluac.Main; 6 | 7 | public class UnluacSpec { 8 | 9 | public UnluacSpec() { 10 | disassemble = false; 11 | } 12 | 13 | public void run(String in, String out) throws IOException { 14 | if(!disassemble) { 15 | Main.decompile(in, out); 16 | } else { 17 | Main.disassemble(in, out); 18 | } 19 | } 20 | 21 | public boolean disassemble; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/unluac/util/Stack.java: -------------------------------------------------------------------------------- 1 | package unluac.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | 6 | public class Stack { 7 | 8 | private final ArrayList data; 9 | 10 | public Stack() { 11 | data = new ArrayList(); 12 | } 13 | 14 | public boolean isEmpty() { 15 | return data.isEmpty(); 16 | } 17 | 18 | public T peek() { 19 | return data.get(data.size() - 1); 20 | } 21 | 22 | public T peek(int i) { 23 | return data.get(data.size() - 1 - i); 24 | } 25 | 26 | public T pop() { 27 | return data.remove(data.size() - 1); 28 | } 29 | 30 | public void push(T item) { 31 | if (data.size() > 65536) { 32 | throw new IndexOutOfBoundsException("Trying to push more than 65536 items!"); 33 | } 34 | data.add(item); 35 | } 36 | 37 | public int size() { 38 | return data.size(); 39 | } 40 | 41 | public void reverse() { 42 | Collections.reverse(data); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/unluac/util/StringUtils.java: -------------------------------------------------------------------------------- 1 | package unluac.util; 2 | 3 | public class StringUtils { 4 | 5 | public static String toPrintString(String s) { 6 | if(s == null) return "\"\""; 7 | StringBuilder b = new StringBuilder(); 8 | b.append('"'); 9 | for(int i = 0; i < s.length(); i++) { 10 | char c = s.charAt(i); 11 | int ci = (int)c; 12 | if(c == '"') { 13 | b.append("\\\""); 14 | } else if(c == '\\') { 15 | b.append("\\\\"); 16 | } else if(ci >= 32 && ci <= 126) { 17 | b.append(c); 18 | } else if(c == '\n') { 19 | b.append("\\n"); 20 | } else if(c == '\t') { 21 | b.append("\\t"); 22 | } else if(c == '\r') { 23 | b.append("\\r"); 24 | } else if(c == '\b') { 25 | b.append("\\b"); 26 | } else if(c == '\f') { 27 | b.append("\\f"); 28 | } else if(ci == 11) { 29 | b.append("\\v"); 30 | } else if(ci == 7) { 31 | b.append("\\a"); 32 | } else { 33 | b.append(String.format("\\x%02x", ci)); 34 | } 35 | } 36 | b.append('"'); 37 | return b.toString(); 38 | } 39 | 40 | public static String fromPrintString(String s) { 41 | if(s.charAt(0) != '"') throw new IllegalStateException("Bad string " + s); 42 | if(s.charAt(s.length() - 1) != '"') throw new IllegalStateException("Bad string " + s); 43 | StringBuilder b = new StringBuilder(); 44 | for(int i = 1; i < s.length() - 1; /* nothing */) { 45 | char c = s.charAt(i++); 46 | if(c == '\\') { 47 | if(i < s.length() - 1) { 48 | c = s.charAt(i++); 49 | if(c == '"') { 50 | b.append('"'); 51 | } else if(c == '\\') { 52 | b.append('\\'); 53 | } else if(c == 'n') { 54 | b.append('\n'); 55 | } else if(c == 't') { 56 | b.append('\t'); 57 | } else if(c == 'r') { 58 | b.append('\r'); 59 | } else if(c == 'b') { 60 | b.append('\b'); 61 | } else if(c == 'f') { 62 | b.append('\f'); 63 | } else if(c == 'v') { 64 | b.append((char) 11); 65 | } else if(c == 'a') { 66 | b.append((char) 7); 67 | } else if(c == 'x') { 68 | if(i + 1 < s.length() - 1) { 69 | String digits = s.substring(i, i + 2); 70 | i += 2; 71 | b.append((char) Integer.parseInt(digits, 16)); 72 | } else { 73 | return null; // error 74 | } 75 | } else { 76 | return null; // error 77 | } 78 | } else { 79 | return null; // error 80 | } 81 | } else { 82 | b.append(c); 83 | } 84 | } 85 | return b.toString(); 86 | } 87 | 88 | private StringUtils() {} 89 | } 90 | -------------------------------------------------------------------------------- /test/src/51_adjust02.lua: -------------------------------------------------------------------------------- 1 | function f(...) 2 | return (g((...))) 3 | end -------------------------------------------------------------------------------- /test/src/51_adjust03.lua: -------------------------------------------------------------------------------- 1 | function f(...) 2 | return (g(...)) 3 | end -------------------------------------------------------------------------------- /test/src/51_ellipsis.lua: -------------------------------------------------------------------------------- 1 | local a, b, c 2 | a = ... 3 | a, b = ... 4 | a, b = ..., 2 5 | a, b, c = 1, ... 6 | a, b, c = ... 7 | -------------------------------------------------------------------------------- /test/src/51_ellipsis02.lua: -------------------------------------------------------------------------------- 1 | local x = 0 2 | function f(...) 3 | x = g() == a or ... 4 | end 5 | -------------------------------------------------------------------------------- /test/src/51_expression.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = x % y % z 3 | a = (x % y) % z 4 | a = x % (y % z) 5 | a = x / y % z 6 | a = x * y % z 7 | a = x % y * z 8 | a = x % y / z 9 | a = x + y % z 10 | a = (x + y) % z 11 | a = x % y - z 12 | a = x % (y - z) 13 | a = x % y ^ z 14 | a = (x % y) ^ z 15 | a = x ^ y % z 16 | a = x ^ (y % z) 17 | -------------------------------------------------------------------------------- /test/src/51_expression03.lua: -------------------------------------------------------------------------------- 1 | local x = 0 2 | local y = 0 3 | 4 | x = x % 5 5 | x = 5 % x 6 | x = x % "5" 7 | x = "5" % x 8 | x = x % y 9 | -------------------------------------------------------------------------------- /test/src/51_expression2.lua: -------------------------------------------------------------------------------- 1 | local a, b 2 | 3 | a = (-1) ^ b 4 | a = (-0.0) ^ b 5 | a = 2 ^ b 6 | -------------------------------------------------------------------------------- /test/src/51_method03.lua: -------------------------------------------------------------------------------- 1 | print((arg).x) -------------------------------------------------------------------------------- /test/src/51_string03.lua: -------------------------------------------------------------------------------- 1 | print[==[ 2 | lots of garbage to start so that unluac will attempt to decompile as long string 3 | lots of garbage to start so that unluac will attempt to decompile as long string 4 | lots of garbage to start so that unluac will attempt to decompile as long string 5 | lots of garbage to start so that unluac will attempt to decompile as long string 6 | lots of garbage to start so that unluac will attempt to decompile as long string 7 | lots of garbage to start so that unluac will attempt to decompile as long string 8 | lots of garbage to start so that unluac will attempt to decompile as long string 9 | lots of garbage to start so that unluac will attempt to decompile as long string 10 | lots of garbage to start so that unluac will attempt to decompile as long string 11 | lots of garbage to start so that unluac will attempt to decompile as long string 12 | lots of garbage to start so that unluac will attempt to decompile as long string 13 | lots of garbage to start so that unluac will attempt to decompile as long string 14 | lots of garbage to start so that unluac will attempt to decompile as long string 15 | lots of garbage to start so that unluac will attempt to decompile as long string 16 | lots of garbage to start so that unluac will attempt to decompile as long string 17 | lots of garbage to start so that unluac will attempt to decompile as long string 18 | lots of garbage to start so that unluac will attempt to decompile as long string 19 | (yes, very long) 20 | disallow this kind of pipe: ]] 21 | now, make the end fail to match the next pipe without actually 22 | containing it in the string]=]==] 23 | 24 | print[=[ 25 | lots of garbage to start so that unluac will attempt to decompile as long string 26 | lots of garbage to start so that unluac will attempt to decompile as long string 27 | lots of garbage to start so that unluac will attempt to decompile as long string 28 | lots of garbage to start so that unluac will attempt to decompile as long string 29 | lots of garbage to start so that unluac will attempt to decompile as long string 30 | lots of garbage to start so that unluac will attempt to decompile as long string 31 | lots of garbage to start so that unluac will attempt to decompile as long string 32 | lots of garbage to start so that unluac will attempt to decompile as long string 33 | lots of garbage to start so that unluac will attempt to decompile as long string 34 | lots of garbage to start so that unluac will attempt to decompile as long string 35 | lots of garbage to start so that unluac will attempt to decompile as long string 36 | lots of garbage to start so that unluac will attempt to decompile as long string 37 | lots of garbage to start so that unluac will attempt to decompile as long string 38 | lots of garbage to start so that unluac will attempt to decompile as long string 39 | lots of garbage to start so that unluac will attempt to decompile as long string 40 | lots of garbage to start so that unluac will attempt to decompile as long string 41 | lots of garbage to start so that unluac will attempt to decompile as long string 42 | (yes, very long) 43 | same test but for the basic pipe end: ]]=] -------------------------------------------------------------------------------- /test/src/52_goto01.lua: -------------------------------------------------------------------------------- 1 | for x = 1, 10 do 2 | for y = 1, 10 do 3 | print(x, y) 4 | if f(x, y) then 5 | print("guard") 6 | goto eof 7 | end 8 | end 9 | end 10 | ::eof:: 11 | -------------------------------------------------------------------------------- /test/src/52_goto02.lua: -------------------------------------------------------------------------------- 1 | for x = 1, 10 do 2 | for y = 1, 10 do 3 | print(x, y) 4 | if f(x, y) then 5 | goto eof 6 | end 7 | end 8 | end 9 | ::eof:: 10 | -------------------------------------------------------------------------------- /test/src/52_goto03.lua: -------------------------------------------------------------------------------- 1 | while "outer" do 2 | for k, v in pairs(t) do 3 | if x then 4 | if y then 5 | print("guard") 6 | goto out 7 | else 8 | print("else") 9 | end 10 | else 11 | goto out 12 | end 13 | end 14 | end 15 | ::out:: 16 | -------------------------------------------------------------------------------- /test/src/53_expression.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = (x | y) | z 3 | a = x | (y | z) 4 | a = x ~ y | z 5 | a = x | y ~ z 6 | a = (x ~ y) ~ z 7 | a = x ~ (y ~ z) 8 | a = x ~ y | z 9 | a = x | y ~ z 10 | a = x ~ y & z 11 | a = x & y ~ z 12 | a = (x & y) & z 13 | a = x & (y & z) 14 | a = x ~ y & z 15 | a = x & y ~ z 16 | a = x << y & z 17 | a = x & y << z 18 | a = x >> y & z 19 | a = x & y >> z 20 | a = (x << y) << z 21 | a = x << (y << z) 22 | a = x << y & z 23 | a = x & y << z 24 | a = x << y .. z 25 | a = x .. y << z 26 | a = (x >> y) >> z 27 | a = x >> (y >> z) 28 | a = x >> y & z 29 | a = x & y >> z 30 | a = x >> y .. z 31 | a = x .. y >> z 32 | a = (x >> y) << z 33 | a = x >> (y << z) 34 | a = (x << y) >> z 35 | a = x << (y >> z) 36 | a = (x // y) // z 37 | a = x // (y // z) 38 | a = x - y // z 39 | a = x // y - z 40 | a = x + y // z 41 | a = x // y + z 42 | a = (x // y) // z 43 | a = x // (y // z) 44 | a = (x // y) / z 45 | a = x // (y / z) 46 | a = (x / y) // z 47 | a = x / (y // z) 48 | a = (~x) ~ y 49 | a = ~(x ~ y) 50 | -------------------------------------------------------------------------------- /test/src/53_expression02.lua: -------------------------------------------------------------------------------- 1 | local x = 0 2 | local y = 0 3 | 4 | x = x | 5 5 | x = 5 | x 6 | x = x | "5" 7 | x = x | y 8 | x = "5" | x 9 | x = x & 5 10 | x = 5 & x 11 | x = x & "5" 12 | x = x & y 13 | x = "5" ~ x 14 | x = x ~ 5 15 | x = 5 ~ x 16 | x = x ~ "5" 17 | x = "5" ~ x 18 | x = x ~ y 19 | 20 | x = x << 5 21 | x = x << (-5) 22 | x = 5 << x 23 | x = (-5) << x 24 | x = x >> 5 25 | x = x >> (-5) 26 | x = 5 >> x 27 | x = (-5) >> x 28 | 29 | x = x << "5" 30 | x = "5" << x 31 | x = x << y 32 | x = x >> "5" 33 | x = "5" >> x 34 | x = x >> y 35 | -------------------------------------------------------------------------------- /test/src/54_tbc01.lua: -------------------------------------------------------------------------------- 1 | (function() 2 | local x = 5 3 | print(x) 4 | end)() 5 | (function() 6 | local x , y = 5, 6 7 | print(x) 8 | end)() 9 | (function() 10 | local y, x = 5, 6 11 | print(x) 12 | end)() 13 | (function() 14 | local x = 5 15 | local y = 6 16 | print(x) 17 | end)() 18 | -------------------------------------------------------------------------------- /test/src/adjust01.lua: -------------------------------------------------------------------------------- 1 | f((g())) -------------------------------------------------------------------------------- /test/src/adjust04.lua: -------------------------------------------------------------------------------- 1 | return f() -------------------------------------------------------------------------------- /test/src/adjust05.lua: -------------------------------------------------------------------------------- 1 | for x in (pairs(t)) do 2 | print(x) 3 | end -------------------------------------------------------------------------------- /test/src/adjust06.lua: -------------------------------------------------------------------------------- 1 | local t = {(f())} 2 | local s = {1, 2, 3, (g())} 3 | 4 | for i = 1, 10 do 5 | print(t[i], s[i]) 6 | end 7 | -------------------------------------------------------------------------------- /test/src/always01.lua: -------------------------------------------------------------------------------- 1 | while true do 2 | local a = {feed()} 3 | if -a == 0 then break end 4 | process(a) 5 | end 6 | -------------------------------------------------------------------------------- /test/src/always02.lua: -------------------------------------------------------------------------------- 1 | repeat 2 | f() 3 | until false 4 | -------------------------------------------------------------------------------- /test/src/always03.lua: -------------------------------------------------------------------------------- 1 | while true do end 2 | -------------------------------------------------------------------------------- /test/src/always04.lua: -------------------------------------------------------------------------------- 1 | function test1() 2 | repeat 3 | repeat 4 | break 5 | until true 6 | until false 7 | end 8 | 9 | function test2() 10 | while true do 11 | repeat 12 | break 13 | until true 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /test/src/assign.lua: -------------------------------------------------------------------------------- 1 | local a = 1 2 | local b = 2 3 | local c = 3 4 | -------------------------------------------------------------------------------- /test/src/booleanassign01.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = x or y 3 | a = x and y 4 | -------------------------------------------------------------------------------- /test/src/booleanassign02.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = w and x and y and z 3 | a = w or x or y or z 4 | a = w and x or y and z 5 | a = (w or x) and (y or z) 6 | a = (b and c or d and e) and (f and g or h and i) or (j and k or l and m) and (n and o or p and q) 7 | -------------------------------------------------------------------------------- /test/src/booleanassign03.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = d and e and f and a and g and h and i 3 | a = d or e or f or a or g or h or i 4 | -------------------------------------------------------------------------------- /test/src/booleanassign04.lua: -------------------------------------------------------------------------------- 1 | x = a and b 2 | x = a or b 3 | x = a and b and c and d 4 | x = a or b or c or d 5 | -------------------------------------------------------------------------------- /test/src/booleanassign05.lua: -------------------------------------------------------------------------------- 1 | local value = thing.a or thing.b or "default" 2 | print(value) -------------------------------------------------------------------------------- /test/src/booleanassign06.lua: -------------------------------------------------------------------------------- 1 | if not thing.a and not thing.b then 2 | local value = "default" 3 | end -------------------------------------------------------------------------------- /test/src/booleanassign07.lua: -------------------------------------------------------------------------------- 1 | if not thing.a and not thing.b then 2 | side_effects() 3 | local value = "default" 4 | end -------------------------------------------------------------------------------- /test/src/booleanassign08.lua: -------------------------------------------------------------------------------- 1 | local value = "initial" 2 | print(value) 3 | value = thing.a or thing.b or "default" 4 | print(value) -------------------------------------------------------------------------------- /test/src/booleanassign09.lua: -------------------------------------------------------------------------------- 1 | local result = a < b and not c 2 | print(result) -------------------------------------------------------------------------------- /test/src/booleanassign10.lua: -------------------------------------------------------------------------------- 1 | local x 2 | if x == nil then 3 | x = (not y) or (z == w) 4 | end 5 | print(x) -------------------------------------------------------------------------------- /test/src/booleanassign11.lua: -------------------------------------------------------------------------------- 1 | local a, b = "asdf", "qwer" 2 | local val = not (a and b) 3 | print(tostring(val)) 4 | -------------------------------------------------------------------------------- /test/src/booleanassign12.lua: -------------------------------------------------------------------------------- 1 | local x = x or a == b 2 | x = true 3 | 4 | local y = x or a ~= b 5 | y = true 6 | 7 | local z = a == b or c == d 8 | z = true 9 | -------------------------------------------------------------------------------- /test/src/booleanassign13.lua: -------------------------------------------------------------------------------- 1 | local a, b, c, d, e, g 2 | a = f() or a 3 | b = f() or b 4 | if e then 5 | d = f() or d 6 | e = f() or e 7 | end 8 | -------------------------------------------------------------------------------- /test/src/booleanassign14.lua: -------------------------------------------------------------------------------- 1 | local a, b, c, d, e, g 2 | 3 | a = g or a 4 | b = g or b 5 | if e then 6 | d = g or d 7 | e = g or e 8 | end 9 | -------------------------------------------------------------------------------- /test/src/booleanassign15.lua: -------------------------------------------------------------------------------- 1 | local x = f() 2 | g = x or nil 3 | -------------------------------------------------------------------------------- /test/src/booleanassign16.lua: -------------------------------------------------------------------------------- 1 | local a, b = f() 2 | local c = not a and 1 or b + 1 3 | print(c) 4 | -------------------------------------------------------------------------------- /test/src/booleanassign17.lua: -------------------------------------------------------------------------------- 1 | local x, y 2 | x = x and f(x,0,y and 1 or 2,"asdf") or 3 3 | -------------------------------------------------------------------------------- /test/src/booleanassign18.lua: -------------------------------------------------------------------------------- 1 | local t, u, i = f() 2 | local x, y = t[i] or 1, u[i] or 2 3 | print(x, y) 4 | -------------------------------------------------------------------------------- /test/src/booleanassign19.lua: -------------------------------------------------------------------------------- 1 | local t, u, v, i = f() 2 | local x, y, z = t[i] or 1, u[i] or 2, v[i] or 3 3 | print(x, y, z) 4 | -------------------------------------------------------------------------------- /test/src/booleanassign20.lua: -------------------------------------------------------------------------------- 1 | local x, y = f() 2 | if not y then 3 | x, y = a, b 4 | end 5 | print(x, y) 6 | -------------------------------------------------------------------------------- /test/src/booleanassign21.lua: -------------------------------------------------------------------------------- 1 | local x 2 | if a then 3 | print("if") 4 | if not x then 5 | x = b 6 | end 7 | else 8 | print("else") 9 | end 10 | -------------------------------------------------------------------------------- /test/src/booleanassign22.lua: -------------------------------------------------------------------------------- 1 | local x 2 | if a then 3 | if not x then 4 | x = f() 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /test/src/booleanassign23.lua: -------------------------------------------------------------------------------- 1 | local a = x == 0 or {1, 2, 3} 2 | local b = x == 1 or {a = 1, b = 3, c = 3} 3 | print(a, b) 4 | -------------------------------------------------------------------------------- /test/src/booleanassign24.lua: -------------------------------------------------------------------------------- 1 | local upvalue = 0 2 | local a = x == 0 or function() 3 | print(upvalue) 4 | end 5 | -------------------------------------------------------------------------------- /test/src/booleanassign25.lua: -------------------------------------------------------------------------------- 1 | local upvalue1 = 0 2 | function outer() 3 | local upvalue2 = 1 4 | local upvalue3 = 2 5 | local x = f() 6 | local a = x == 0 or function() 7 | print(upvalue1, upvalue2, upvalue3) 8 | end 9 | return a 10 | end -------------------------------------------------------------------------------- /test/src/booleanassign26.lua: -------------------------------------------------------------------------------- 1 | local x = f() 2 | x = not x and 0 or t[x] or x 3 | -------------------------------------------------------------------------------- /test/src/booleanassign27.lua: -------------------------------------------------------------------------------- 1 | local x, y 2 | x, y = x and x < 2 and x or nil, y and y < 3 and y or nil 3 | print(x,y) 4 | -------------------------------------------------------------------------------- /test/src/booleanassign28.lua: -------------------------------------------------------------------------------- 1 | local x = a and (f() or c==0) 2 | print(x) 3 | -------------------------------------------------------------------------------- /test/src/booleanexpression01.lua: -------------------------------------------------------------------------------- 1 | print(a or b) 2 | print(a and b) 3 | -------------------------------------------------------------------------------- /test/src/booleanexpression02.lua: -------------------------------------------------------------------------------- 1 | print(a and b, a or b) 2 | -------------------------------------------------------------------------------- /test/src/booleanexpression03.lua: -------------------------------------------------------------------------------- 1 | print(x == 0 or a.first and a.record.field == value) -------------------------------------------------------------------------------- /test/src/booleanexpression04.lua: -------------------------------------------------------------------------------- 1 | print((not x) and (a == b) and (y < z)) -------------------------------------------------------------------------------- /test/src/booleanexpression05.lua: -------------------------------------------------------------------------------- 1 | print(a == b and (c == d or c == e) and f == g) -------------------------------------------------------------------------------- /test/src/booleanexpression06.lua: -------------------------------------------------------------------------------- 1 | print(not a and b) -------------------------------------------------------------------------------- /test/src/booleanexpression07.lua: -------------------------------------------------------------------------------- 1 | function obj.method(self, x) 2 | self = {name = "asdf"} 3 | self.field = setmetatable(x and table.copy(x) or {}, self) 4 | t[self.name] = self.field 5 | return self 6 | end 7 | -------------------------------------------------------------------------------- /test/src/booleanexpression08.lua: -------------------------------------------------------------------------------- 1 | if a and b or c(x == y or a or 5) and z then 2 | print("hello") 3 | end 4 | -------------------------------------------------------------------------------- /test/src/booleanexpression09.lua: -------------------------------------------------------------------------------- 1 | for k, v in pairs(t) do 2 | if f() and g(a or b) then 3 | print("yes") 4 | else 5 | print("no") 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/src/booleanexpression10.lua: -------------------------------------------------------------------------------- 1 | print((x or {}).__tostring) 2 | -------------------------------------------------------------------------------- /test/src/booleanmultiassign01.lua: -------------------------------------------------------------------------------- 1 | local a, b 2 | a, b = a and b, a or b 3 | a, b = a or b, a and b 4 | a, b = b and a, b or a 5 | a, b = b or a, b and a 6 | a, b = x and y, x or y 7 | -------------------------------------------------------------------------------- /test/src/booleanmultiassign02.lua: -------------------------------------------------------------------------------- 1 | local q 2 | local n, t = f(), q or s[1] 3 | print(n, t) 4 | -------------------------------------------------------------------------------- /test/src/booleanselfassign01.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = a or x 3 | a = a and x 4 | y = y or x 5 | y = y and x 6 | -------------------------------------------------------------------------------- /test/src/break01.lua: -------------------------------------------------------------------------------- 1 | if x then 2 | for i=1,10 do 3 | if a then 4 | print("okay") 5 | elseif b then 6 | print("b") 7 | break 8 | else 9 | print("c") 10 | break 11 | end 12 | end 13 | else 14 | print("else") 15 | end 16 | print("done") 17 | -------------------------------------------------------------------------------- /test/src/break02.lua: -------------------------------------------------------------------------------- 1 | if x then 2 | for i=1,10 do 3 | if a then 4 | print("okay") 5 | elseif b then 6 | print("b") 7 | break 8 | else 9 | break 10 | end 11 | end 12 | else 13 | print("else") 14 | end 15 | print("done") 16 | -------------------------------------------------------------------------------- /test/src/break03.lua: -------------------------------------------------------------------------------- 1 | if x then 2 | for i=1,10 do 3 | if a then 4 | print("okay") 5 | elseif b then 6 | break 7 | elseif c then 8 | dontbreak() 9 | elseif d then 10 | alsodontbreak() 11 | for k = 1, 10 do print("breakable loop") end 12 | else 13 | break 14 | end 15 | print("next") 16 | end 17 | else 18 | print("else") 19 | end 20 | print("done") 21 | -------------------------------------------------------------------------------- /test/src/break04.lua: -------------------------------------------------------------------------------- 1 | local a, b = 5, 5 2 | while a < b do 3 | print("a") 4 | a, b = a / b * j, fmod(a, b) * k 5 | if b > j then 6 | print("b") 7 | if x == nil then 8 | break 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/src/break05.lua: -------------------------------------------------------------------------------- 1 | for k, v in iter() do 2 | if a then 3 | if b then 4 | return 5 | elseif c then 6 | print(c) 7 | elseif d then 8 | print(d) 9 | end 10 | end 11 | break 12 | end 13 | -------------------------------------------------------------------------------- /test/src/break06.lua: -------------------------------------------------------------------------------- 1 | while x < 10 do 2 | if a == 1 then 3 | print(1) 4 | end 5 | if b == 1 then 6 | break 7 | end 8 | if c == 1 then 9 | print(1) 10 | else 11 | break 12 | end 13 | if a == 2 then 14 | print(2) 15 | end 16 | if b == 2 then 17 | break 18 | end 19 | if c == 2 then 20 | print(2) 21 | else 22 | break 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /test/src/break07.lua: -------------------------------------------------------------------------------- 1 | while x do 2 | if b then 3 | guard() 4 | if c then 5 | print("c") 6 | break 7 | end 8 | guard() 9 | else 10 | print("not b") 11 | break 12 | end 13 | guard() 14 | end -------------------------------------------------------------------------------- /test/src/break08.lua: -------------------------------------------------------------------------------- 1 | for i = 1, 10 do 2 | if f(i) then 3 | break 4 | end 5 | if g(i) then 6 | h() 7 | else 8 | break 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /test/src/break09.lua: -------------------------------------------------------------------------------- 1 | for k, v in pairs(t) do 2 | if x then 3 | if y then 4 | print("guard") 5 | break 6 | else 7 | print("else") 8 | end 9 | else 10 | break 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /test/src/break10.lua: -------------------------------------------------------------------------------- 1 | local a 2 | while x do 3 | a = b or c 4 | -- testset redirected by break 5 | break 6 | end 7 | -------------------------------------------------------------------------------- /test/src/close01.lua: -------------------------------------------------------------------------------- 1 | for _, v in pairs(t) do 2 | local x = f() 3 | if x then 4 | f(function() return v end) 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /test/src/close02.lua: -------------------------------------------------------------------------------- 1 | for _, v in pairs(t) do 2 | local x = f() 3 | if x then 4 | f(function() return v end) 5 | else 6 | g(function() return v end) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/src/close03.lua: -------------------------------------------------------------------------------- 1 | for _, request in pairs(t) do 2 | local finished = false 3 | request:executeWithCallback(function() finished = true end) 4 | while not finished do Sleep() end 5 | -- CLOSE 6 | end 7 | -------------------------------------------------------------------------------- /test/src/close04.lua: -------------------------------------------------------------------------------- 1 | repeat 2 | local x = f() 3 | table.insert(t, function() return x end) 4 | until not x 5 | -------------------------------------------------------------------------------- /test/src/closure.lua: -------------------------------------------------------------------------------- 1 | f = function(a, b) 2 | local c = a + b 3 | return c ^ 2 4 | end 5 | print(f(3, 4)) 6 | -------------------------------------------------------------------------------- /test/src/combinebassign01.lua: -------------------------------------------------------------------------------- 1 | local x 2 | x = x == nil or x 3 | print(x) 4 | -------------------------------------------------------------------------------- /test/src/combinebassign02.lua: -------------------------------------------------------------------------------- 1 | local a, b 2 | a = b ~= nil and f(b) or "else" 3 | 4 | a = b == nil and f(b) or "else" 5 | 6 | a = (b ~= nil or f(b)) and "else" 7 | 8 | a = (b == nil or f(b)) and "else" 9 | -------------------------------------------------------------------------------- /test/src/combinebassign03.lua: -------------------------------------------------------------------------------- 1 | local t, x 2 | if a then 3 | x = t[1] == "ref" and t[2] 4 | else 5 | print("else") 6 | end 7 | -------------------------------------------------------------------------------- /test/src/combinebassign04.lua: -------------------------------------------------------------------------------- 1 | local f, t 2 | do 3 | local x = t[2] == "sym" and f() 4 | if x then 5 | return 0 6 | end 7 | end 8 | return 1 9 | -------------------------------------------------------------------------------- /test/src/combinebassign05.lua: -------------------------------------------------------------------------------- 1 | print("guard") 2 | local a, b, c 3 | local d = 4 | a.cond or 5 | (type(b) == "table" and b) or 6 | (type(b) == "string" and f(b, c or "str")) 7 | -------------------------------------------------------------------------------- /test/src/combinebassign07.lua: -------------------------------------------------------------------------------- 1 | local a, b, c, d, e, f 2 | a = b == 0 and c or (d + e) * f 3 | -------------------------------------------------------------------------------- /test/src/combinebexpression01.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = b < c or d < e or f 3 | -------------------------------------------------------------------------------- /test/src/combinebexpression02.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = b or c or d == e 3 | -------------------------------------------------------------------------------- /test/src/combinebexpression03.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = b or c == d or e 3 | -------------------------------------------------------------------------------- /test/src/combinebexpression04.lua: -------------------------------------------------------------------------------- 1 | print(a or b or c == d) 2 | print(a or b == c or d) 3 | print(a and b == c or d) 4 | print(a or b == c and d) 5 | print(a or b ~= c or d) 6 | print(a == b or c or d) 7 | print(a < b and c or d) 8 | print(a ~= b or c and d) 9 | print(a == b and c and d) 10 | -------------------------------------------------------------------------------- /test/src/combinebexpression05.lua: -------------------------------------------------------------------------------- 1 | local a, aa, b, bb = g() 2 | 3 | return (a == b) and f(aa, bb) or a < b 4 | -------------------------------------------------------------------------------- /test/src/combinebexpression06.lua: -------------------------------------------------------------------------------- 1 | local a, aa, b, bb = g() 2 | 3 | return (a == b) and f(aa, bb) or a or b 4 | -------------------------------------------------------------------------------- /test/src/combinebexpression07.lua: -------------------------------------------------------------------------------- 1 | local t, s 2 | function f(a, b) 3 | return (a == b and true) or t[a] and t[b] and t[a] == t[b] 4 | end -------------------------------------------------------------------------------- /test/src/compare01.lua: -------------------------------------------------------------------------------- 1 | local x = f() 2 | if x < 5 then 3 | f() 4 | end 5 | if x < 5.0 then 6 | f() 7 | end 8 | if x < -5 then 9 | f() 10 | end 11 | if x < -5.0 then 12 | f() 13 | end 14 | if x > 5 then 15 | f() 16 | end 17 | if x > 5.0 then 18 | f() 19 | end 20 | if x > -5 then 21 | f() 22 | end 23 | if x > -5.0 then 24 | f() 25 | end 26 | if x <= 5 then 27 | f() 28 | end 29 | if x <= 5.0 then 30 | f() 31 | end 32 | if x <= -5 then 33 | f() 34 | end 35 | if x <= -5.0 then 36 | f() 37 | end 38 | if x >= 5 then 39 | f() 40 | end 41 | if x >= 5.0 then 42 | f() 43 | end 44 | if x >= -5 then 45 | f() 46 | end 47 | if x >= -5.0 then 48 | f() 49 | end 50 | if x == 5 then 51 | f() 52 | end 53 | if x == 5.0 then 54 | f() 55 | end 56 | if x == -5 then 57 | f() 58 | end 59 | if x == -5.0 then 60 | f() 61 | end 62 | if x == "5" then 63 | f() 64 | end 65 | 66 | if 5 < x then 67 | f() 68 | end 69 | if 5.0 < x then 70 | f() 71 | end 72 | if -5 < x then 73 | f() 74 | end 75 | if -5.0 < x then 76 | f() 77 | end 78 | if 5 > x then 79 | f() 80 | end 81 | if 5.0 > x then 82 | f() 83 | end 84 | if -5 > x then 85 | f() 86 | end 87 | if -5.0 > x then 88 | f() 89 | end 90 | if 5 <= x then 91 | f() 92 | end 93 | if 5.0 <= x then 94 | f() 95 | end 96 | if -5 <= x then 97 | f() 98 | end 99 | if -5.0 <= x then 100 | f() 101 | end 102 | if 5 >= x then 103 | f() 104 | end 105 | if 5.0 >= x then 106 | f() 107 | end 108 | if -5 >= x then 109 | f() 110 | end 111 | if -5.0 >= x then 112 | f() 113 | end 114 | if 5 == x then 115 | f() 116 | end 117 | if 5.0 == x then 118 | f() 119 | end 120 | if -5 == x then 121 | f() 122 | end 123 | if -5.0 == x then 124 | f() 125 | end 126 | if "5" == x then 127 | f() 128 | end 129 | -------------------------------------------------------------------------------- /test/src/compareassign01.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = x < y 3 | -------------------------------------------------------------------------------- /test/src/compareassign02.lua: -------------------------------------------------------------------------------- 1 | local x 2 | if not x then 3 | guard() 4 | x = g < 3 5 | end 6 | -------------------------------------------------------------------------------- /test/src/compareexpression.lua: -------------------------------------------------------------------------------- 1 | print(x == y) 2 | print(x < y) 3 | print(x <= y) 4 | -------------------------------------------------------------------------------- /test/src/compareexpression02.lua: -------------------------------------------------------------------------------- 1 | if x and y then 2 | return x < y 3 | end 4 | print("end") 5 | -------------------------------------------------------------------------------- /test/src/compareorder01.lua: -------------------------------------------------------------------------------- 1 | if a < b then 2 | print("a < b") 3 | end 4 | if b > a then 5 | print("b > a") 6 | end 7 | -------------------------------------------------------------------------------- /test/src/compareorder02.lua: -------------------------------------------------------------------------------- 1 | -- In the case of two constants: 2 | -- comparison order is impossible to reproduce from bytecode 3 | -- this case seems unlikely to occur in production code though 4 | -- perhaps guess by the index of the constants? 5 | -- (that could work if both constants are fresh) 6 | if 1 < 2 then 7 | print("1 < 2") 8 | end 9 | if 2 > 1 then 10 | print("2 > 1") 11 | end 12 | -------------------------------------------------------------------------------- /test/src/compareorder03.lua: -------------------------------------------------------------------------------- 1 | if a < 2 then 2 | print("a < 2") 3 | end 4 | if 2 > a then 5 | print("2 > a") 6 | end 7 | -------------------------------------------------------------------------------- /test/src/compareorder04.lua: -------------------------------------------------------------------------------- 1 | print("begin") 2 | if not (math.random(100) > chance) then 3 | print("then") 4 | end 5 | print("end") -------------------------------------------------------------------------------- /test/src/compareorder05.lua: -------------------------------------------------------------------------------- 1 | print("begin") 2 | if math.random(100) <= chance then 3 | print("then") 4 | end 5 | print("end") -------------------------------------------------------------------------------- /test/src/compareorder06.lua: -------------------------------------------------------------------------------- 1 | if f1() == "a" then 2 | g() 3 | end 4 | if "b" == f2() then 5 | g() 6 | end 7 | if f3() ~= "c" then 8 | g() 9 | end 10 | if "d" ~= f4() then 11 | g() 12 | end 13 | -------------------------------------------------------------------------------- /test/src/compareorder07.lua: -------------------------------------------------------------------------------- 1 | if 1 == 1.0 then 2 | f() 3 | end 4 | if 2.0 == 2 then 5 | f() 6 | end 7 | if 3 < 3.0 then 8 | f() 9 | end 10 | if 4.0 < 4 then 11 | f() 12 | end 13 | if 5 > 5.0 then 14 | f() 15 | end 16 | if 6.0 > 6 then 17 | f() 18 | end 19 | if 7 <= 7.0 then 20 | f() 21 | end 22 | if 8.0 <= 8 then 23 | f() 24 | end 25 | if 9 >= 9.0 then 26 | f() 27 | end 28 | if 10.0 >= 10 then 29 | f() 30 | end 31 | if 11 ~= 11.0 then 32 | f() 33 | end 34 | if 12.0 ~= 12 then 35 | f() 36 | end 37 | if "13" == 13 then 38 | f() 39 | end 40 | if 14 == "14" then 41 | f() 42 | end 43 | if "15" == 15.0 then 44 | f() 45 | end 46 | if 16.0 == "16" then 47 | f() 48 | end 49 | if "17" ~= 17 then 50 | f() 51 | end 52 | if 18 ~= "18" then 53 | f() 54 | end 55 | if "19" ~= 19.0 then 56 | f() 57 | end 58 | if 20.0 ~= "20" then 59 | f() 60 | end 61 | -------------------------------------------------------------------------------- /test/src/compareorder08.lua: -------------------------------------------------------------------------------- 1 | if left1("common1") == "common1" then 2 | f() 3 | end 4 | if "common2" == right2("common2") then 5 | f() 6 | end 7 | if left3("common3") < "common3" then 8 | f() 9 | end 10 | if "common4" > right4("common4") then 11 | f() 12 | end 13 | if "left5" == "right5" then 14 | f() 15 | end 16 | -------------------------------------------------------------------------------- /test/src/complexassign01.lua: -------------------------------------------------------------------------------- 1 | if buffer then 2 | print("hello") 3 | end 4 | local single1 = 1 5 | local single2 = 2 6 | local single3 = 3 7 | if buffer then 8 | print("hello") 9 | end 10 | local single4 = 4 11 | local single5 = 5 12 | local single6 = 6 13 | -------------------------------------------------------------------------------- /test/src/complexassign02.lua: -------------------------------------------------------------------------------- 1 | if buffer then 2 | print("hello") 3 | end 4 | local expr1 = a + b + c + d 5 | local expr2 = expr1 + a + b + c + d 6 | local expr3 = a + b + c + d + expr2 7 | -------------------------------------------------------------------------------- /test/src/complexassign03.lua: -------------------------------------------------------------------------------- 1 | if buffer then 2 | print("hello") 3 | end 4 | local multi1a, multi1b, multi1c = 1, 2, 3 5 | local multi2a, multi2b, multi2c = multi_return() 6 | local multi3a, multi3b, multi3c = multi_return(x, y, z) 7 | -------------------------------------------------------------------------------- /test/src/condition.lua: -------------------------------------------------------------------------------- 1 | if a == b and c == d then 2 | f() 3 | end 4 | if a == b or c == d then 5 | f() 6 | end 7 | if a < b then 8 | f() 9 | end 10 | if a <= b then 11 | f() 12 | end 13 | if not a then 14 | f() 15 | end 16 | -------------------------------------------------------------------------------- /test/src/condition02.lua: -------------------------------------------------------------------------------- 1 | local a, b = f() 2 | local test = b == 0 3 | if a and ((test and not a.x) or (not test and not a.y)) then 4 | print(a) 5 | end 6 | -------------------------------------------------------------------------------- /test/src/condition03.lua: -------------------------------------------------------------------------------- 1 | local a 2 | local b 3 | local c, d 4 | local e 5 | if x ~= a and not t[e] then 6 | local f = ((d == x) and c or x) - 1 7 | print("more") 8 | end 9 | -------------------------------------------------------------------------------- /test/src/control01.lua: -------------------------------------------------------------------------------- 1 | if a then 2 | while b do 3 | f() 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/src/control02.lua: -------------------------------------------------------------------------------- 1 | if a then 2 | local x = 3 3 | if b then 4 | print(a, b) 5 | end 6 | print(x) 7 | end -------------------------------------------------------------------------------- /test/src/control03.lua: -------------------------------------------------------------------------------- 1 | if a then 2 | local x = 3 3 | if b then 4 | print(a, b) 5 | end 6 | end -------------------------------------------------------------------------------- /test/src/control04.lua: -------------------------------------------------------------------------------- 1 | local y 2 | if x then 3 | while y do 4 | print("hello") 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /test/src/control05.lua: -------------------------------------------------------------------------------- 1 | for i = 1, 10 do 2 | local x = f() 3 | if a then 4 | local y = g() 5 | if b then 6 | print(b) 7 | end 8 | break 9 | end 10 | end -------------------------------------------------------------------------------- /test/src/control06.lua: -------------------------------------------------------------------------------- 1 | for item in iter() do 2 | if complicated_condition() then 3 | f() 4 | if additional() then 5 | g() 6 | end 7 | break 8 | end 9 | end -------------------------------------------------------------------------------- /test/src/control07.lua: -------------------------------------------------------------------------------- 1 | repeat 2 | repeat 3 | f() 4 | until b 5 | g() 6 | until a -------------------------------------------------------------------------------- /test/src/declare.lua: -------------------------------------------------------------------------------- 1 | local a, b, c 2 | a = 1 3 | b = 2 4 | local d 5 | d = 3 6 | f() 7 | summon = function(bid, count) 8 | if type(bid) == "string" then 9 | bid = beings[bid].nid 10 | end 11 | local last_being 12 | for i = 1, count or 1 do 13 | last_being = Level.drop_being(bid, Level.empty_coord()) 14 | end 15 | return last_being 16 | end 17 | f() 18 | --a, b = a and b, a or b 19 | f() 20 | 21 | --[[while a < c do 22 | if(a == b) then 23 | a = c 24 | else 25 | break 26 | end 27 | end]] --TODO 28 | 29 | --[[while a < c do 30 | if a==b then 31 | c = 3 32 | if c == b then 33 | d = 6 34 | end 35 | end 36 | end]] --FIXED! 37 | 38 | --[[if a==b then 39 | if c==d then 40 | a = 4 41 | if a == c then 42 | a, b = 2, 3 43 | end 44 | end 45 | else 46 | c = 6 47 | end]] --FIXED! 48 | 49 | --[[while a == b do 50 | if c == d then 51 | c = 6 52 | end 53 | break 54 | end]] --OKAY because compiles as 55 | --[[while a == b and c == d do 56 | c = 6 57 | break 58 | end]] 59 | 60 | a, b, c, d = b, c, d, a 61 | return f() -------------------------------------------------------------------------------- /test/src/declare02.lua: -------------------------------------------------------------------------------- 1 | print("begin") 2 | local x, y, z 3 | print("begin") 4 | local a, b, c 5 | c = 4 6 | print(c) 7 | local d, e, f 8 | d = 8 9 | print(d) -------------------------------------------------------------------------------- /test/src/declare03.lua: -------------------------------------------------------------------------------- 1 | print("begin") 2 | local x, y, z -------------------------------------------------------------------------------- /test/src/declare04.lua: -------------------------------------------------------------------------------- 1 | local upvalue 2 | function f() 3 | local a, b 4 | upvalue = nil 5 | end 6 | -------------------------------------------------------------------------------- /test/src/declare05.lua: -------------------------------------------------------------------------------- 1 | t["goto"] = function(x, y) 2 | if x then y() end 3 | end 4 | -------------------------------------------------------------------------------- /test/src/doend01.lua: -------------------------------------------------------------------------------- 1 | do 2 | local a = 512 3 | print(a) 4 | end 5 | do 6 | local b = 255 7 | print(b) 8 | end -------------------------------------------------------------------------------- /test/src/doend02.lua: -------------------------------------------------------------------------------- 1 | while x do 2 | local v, w = 0 3 | print(w, v) 4 | end -------------------------------------------------------------------------------- /test/src/doend03.lua: -------------------------------------------------------------------------------- 1 | for x, y in pairs(t) do 2 | local v, w = 0 3 | print(w, v) 4 | end -------------------------------------------------------------------------------- /test/src/doend04.lua: -------------------------------------------------------------------------------- 1 | for z=1,6 do 2 | local v, w = 0 3 | print(w, v, z) 4 | end -------------------------------------------------------------------------------- /test/src/doend05.lua: -------------------------------------------------------------------------------- 1 | repeat 2 | local v, w = 0 3 | print(w, v) 4 | until x < 100 5 | -------------------------------------------------------------------------------- /test/src/doend06.lua: -------------------------------------------------------------------------------- 1 | while true do 2 | local v, w = 0 3 | print(w, v) 4 | end 5 | -------------------------------------------------------------------------------- /test/src/doend07.lua: -------------------------------------------------------------------------------- 1 | print("guard") 2 | local a 3 | do 4 | local b 5 | print("guard") 6 | b = f() 7 | a = b 8 | end 9 | return a 10 | -------------------------------------------------------------------------------- /test/src/doend08.lua: -------------------------------------------------------------------------------- 1 | print("guard") 2 | local a 3 | do 4 | local b 5 | do 6 | local c 7 | print("guard") 8 | c = f() 9 | b = c 10 | end 11 | a = b 12 | end 13 | return a 14 | -------------------------------------------------------------------------------- /test/src/ellipsis03.lua: -------------------------------------------------------------------------------- 1 | function f(...) 2 | return arg 3 | end 4 | -------------------------------------------------------------------------------- /test/src/else01.lua: -------------------------------------------------------------------------------- 1 | if z == nil and w == nil then 2 | if x == y then 3 | result = true 4 | elseif x == z then 5 | print(z) 6 | if n then 7 | print(n) 8 | end 9 | else 10 | error() 11 | end 12 | else 13 | error() 14 | end 15 | -------------------------------------------------------------------------------- /test/src/else02.lua: -------------------------------------------------------------------------------- 1 | for k, v in ipairs(t) do 2 | if f(k, v) then 3 | guard() 4 | if g(k, v) then 5 | guard() 6 | if h(k, v) then 7 | f2() 8 | else 9 | -- empty 10 | end 11 | else 12 | -- empty 13 | end 14 | else 15 | -- empty 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /test/src/else03.lua: -------------------------------------------------------------------------------- 1 | if x then 2 | print("guard") 3 | if y then 4 | if z then 5 | print("z") 6 | else 7 | print("not z") 8 | end 9 | end 10 | elseif a then 11 | print("a") 12 | end 13 | -------------------------------------------------------------------------------- /test/src/else04.lua: -------------------------------------------------------------------------------- 1 | local a 2 | if x then 3 | a = b or c 4 | -- testset redirected by else 5 | else 6 | print("else") 7 | end 8 | -------------------------------------------------------------------------------- /test/src/else05.lua: -------------------------------------------------------------------------------- 1 | local a 2 | if x then 3 | a = b or c + d 4 | -- testset redirected by else (with MMBIN*) 5 | else 6 | print("else") 7 | end 8 | -------------------------------------------------------------------------------- /test/src/else06.lua: -------------------------------------------------------------------------------- 1 | local x 2 | if test then 3 | print("guard") 4 | x = a or b 5 | -- redirect (5.4) 6 | else 7 | print("guard") 8 | x = c or d 9 | end 10 | -------------------------------------------------------------------------------- /test/src/else07.lua: -------------------------------------------------------------------------------- 1 | local x 2 | if t then 3 | x = y or 3 4 | else 5 | x = (y == 0) 6 | end 7 | -------------------------------------------------------------------------------- /test/src/expression.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = x + y + z 3 | a = x + (y + z) 4 | a = x + y - z 5 | a = x - y + z 6 | a = x - y - z 7 | a = x - (y - z) 8 | a = x * y * z 9 | a = x * (y * z) 10 | a = x + y * z 11 | a = (z + y) / z 12 | a = x / (y + z) 13 | a = x ^ y ^ z 14 | a = (x ^ y) ^ z 15 | a = x .. y .. z 16 | a = (x .. y) .. z 17 | -------------------------------------------------------------------------------- /test/src/expression02.lua: -------------------------------------------------------------------------------- 1 | local x = 0 2 | local y = 0 3 | 4 | x = x + 5 5 | x = x - 5 6 | x = 5 + x 7 | x = (-5) + x 8 | x = 5 - x 9 | x = (-5) - x 10 | x = x + "5" 11 | x = "5" + x 12 | x = x - "5" 13 | x = "5" - x 14 | x = x + y 15 | x = x - y 16 | x = x * 5 17 | x = 5 * x 18 | x = x * "5" 19 | x = "5" * x 20 | x = x * y 21 | x = x / 5 22 | x = 5 / x 23 | x = x / "5" 24 | x = "5" / x 25 | x = x / y 26 | x = x ^ 5 27 | x = 5 ^ x 28 | x = x ^ "5" 29 | x = "5" ^ x 30 | x = x ^ y 31 | x = x .. 5 32 | x = 5 .. x 33 | x = x .. "5" 34 | x = "5" .. x 35 | x = x .. y 36 | -------------------------------------------------------------------------------- /test/src/final01.lua: -------------------------------------------------------------------------------- 1 | if x then 2 | do return end 3 | print(x) 4 | end -------------------------------------------------------------------------------- /test/src/final02.lua: -------------------------------------------------------------------------------- 1 | while x > 0 do 2 | do break end 3 | print(x) 4 | x = x - 1 5 | end -------------------------------------------------------------------------------- /test/src/functioncall.lua: -------------------------------------------------------------------------------- 1 | local a, b, c 2 | a = f(1, 2, 3) 3 | a = f(x, y, z) 4 | a, b = f(1, 2, 3) 5 | a, b, c = 1, f(1, 2, 3) 6 | a, b, c = f(1, 2, 3), 1, 2 7 | a = f(g()) 8 | -------------------------------------------------------------------------------- /test/src/if01.lua: -------------------------------------------------------------------------------- 1 | if a then 2 | if {} then 3 | print("x") 4 | end 5 | end -------------------------------------------------------------------------------- /test/src/if02.lua: -------------------------------------------------------------------------------- 1 | if a then 2 | for _, v in ipairs(mylist) do 3 | print(v) 4 | end 5 | if b then 6 | print("done") 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/src/if03.lua: -------------------------------------------------------------------------------- 1 | local t = {} 2 | do_work(t) 3 | 4 | if not t.x then 5 | t.x = f() 6 | end 7 | -------------------------------------------------------------------------------- /test/src/if04.lua: -------------------------------------------------------------------------------- 1 | if a then 2 | print("separate") 3 | if x == y then 4 | -- empty 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /test/src/if05.lua: -------------------------------------------------------------------------------- 1 | local t = {} 2 | if a then 3 | t[1] = 0 -- a and b can't be combined 4 | if b then 5 | print("middle", t) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/src/if06.lua: -------------------------------------------------------------------------------- 1 | if a then 2 | print("a") 3 | else 4 | local x 5 | if b then 6 | if c then 7 | -- empty 8 | else 9 | print("b,~c") 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /test/src/if07.lua: -------------------------------------------------------------------------------- 1 | return function( self ) 2 | local x = 0 3 | local z = false 4 | if a then 5 | if x == 1 then 6 | self.y = "1" 7 | elseif math.random(100) <= self.x then 8 | self.y = "2" 9 | end 10 | end 11 | z = false 12 | return self.y 13 | end 14 | -------------------------------------------------------------------------------- /test/src/ifthen.lua: -------------------------------------------------------------------------------- 1 | local a, b 2 | if a then 3 | print(a) 4 | end 5 | if a == b then 6 | local c = a + b 7 | print(c ^ 2) 8 | end 9 | if a and b and x and y then 10 | print(a + x, b + y) 11 | end 12 | if a or b or x or y then 13 | print(a * x, b * y) 14 | end 15 | if (a or b) and (x or y) then 16 | print(a * x, b - y) 17 | end 18 | -------------------------------------------------------------------------------- /test/src/ifthenelse.lua: -------------------------------------------------------------------------------- 1 | if a then 2 | f() 3 | else 4 | g() 5 | end 6 | if b then 7 | f() 8 | if a then 9 | g() 10 | end 11 | else 12 | h() 13 | end 14 | if a then 15 | if b then 16 | f() 17 | else 18 | h() 19 | end 20 | g() 21 | end 22 | -------------------------------------------------------------------------------- /test/src/inlineconstant01.lua: -------------------------------------------------------------------------------- 1 | ("string"):method(); 2 | ("string")(); 3 | (1234):method(); 4 | (1234)(); 5 | (nil):method(); 6 | (nil)(); 7 | (true):method(); 8 | (true)(); 9 | -------------------------------------------------------------------------------- /test/src/inlinefunction01.lua: -------------------------------------------------------------------------------- 1 | (function() print "hello" end)() -------------------------------------------------------------------------------- /test/src/inlinefunction02.lua: -------------------------------------------------------------------------------- 1 | -- yes, this doesn't work, but it is syntactically valid 2 | (function(self, s) print(s) end):p("hello") 3 | -------------------------------------------------------------------------------- /test/src/literal.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = 5 3 | a = 2.5 4 | a = "hello" 5 | a = false 6 | a = true 7 | a = nil 8 | -------------------------------------------------------------------------------- /test/src/literallist.lua: -------------------------------------------------------------------------------- 1 | x = {1, 2 | 2, 3 | 7, 4 | "frog", 5 | z, 6 | y * w, 7 | 99} 8 | -------------------------------------------------------------------------------- /test/src/localbooleanassign.lua: -------------------------------------------------------------------------------- 1 | local armor = being.eq.armor 2 | local boots = being.eq.boots 3 | if not armor and not boots then 4 | being:msg( "You have no armor to fix! Nothing happens." ) 5 | return 6 | end 7 | local damaged_armor = armor and armor:is_damaged() 8 | local damaged_boots = boots and boots:is_damaged() 9 | if not damaged_armor and not damaged_boots then 10 | being:msg( "You have no armor that needs fixing! Nothing happens." ) 11 | return 12 | end 13 | ui.blink( YELLOW, 20 ) 14 | -------------------------------------------------------------------------------- /test/src/localfunction01.lua: -------------------------------------------------------------------------------- 1 | local function factorial(n) 2 | if n == 0 then 3 | return 1 4 | else 5 | return factorial(n - 1) * n 6 | end 7 | end 8 | print(factorial(10)) 9 | -------------------------------------------------------------------------------- /test/src/localfunction02.lua: -------------------------------------------------------------------------------- 1 | local factorial = function(n) 2 | if n == 0 then 3 | return 1 4 | else 5 | return factorial(n - 1) * n 6 | end 7 | end 8 | print(factorial(10)) 9 | -------------------------------------------------------------------------------- /test/src/localfunction03.lua: -------------------------------------------------------------------------------- 1 | local function factorial(n) 2 | return "not recursive" 3 | end 4 | print(factorial(10)) 5 | -------------------------------------------------------------------------------- /test/src/localfunction04.lua: -------------------------------------------------------------------------------- 1 | local factorial = function(n) 2 | return "not recursive" 3 | end 4 | print(factorial(10)) 5 | -------------------------------------------------------------------------------- /test/src/loop01.lua: -------------------------------------------------------------------------------- 1 | while true do 2 | print('first') 3 | if test then 4 | print('second') 5 | else 6 | print 'third' 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/src/loop02.lua: -------------------------------------------------------------------------------- 1 | while true do 2 | for k,v in pairs(next_table()) do 3 | if k == "end" then 4 | return 5 | else 6 | break 7 | end 8 | end 9 | end -------------------------------------------------------------------------------- /test/src/loop03.lua: -------------------------------------------------------------------------------- 1 | while true do 2 | for k,v in pairs(next_table()) do 3 | if valid(k) then 4 | print("block") 5 | if k == "end" then 6 | return 7 | else 8 | break 9 | end 10 | end 11 | end 12 | end -------------------------------------------------------------------------------- /test/src/loop04.lua: -------------------------------------------------------------------------------- 1 | local a 2 | for b = 1, 10 do 3 | for c = 1, 10 do 4 | if a then break end 5 | break 6 | end 7 | break 8 | end 9 | -------------------------------------------------------------------------------- /test/src/method01.lua: -------------------------------------------------------------------------------- 1 | function class:method(x) 2 | self:other_method(x) 3 | end -------------------------------------------------------------------------------- /test/src/method02.lua: -------------------------------------------------------------------------------- 1 | local x,y 2 | ;(x+y):print() 3 | ;("aeiou"):gsub(".",print) 4 | print((arg).x) 5 | x = (x+y).z 6 | y = ("asdf").gsub 7 | ;(-x):print() 8 | print() 9 | ;("aeiou").n = x 10 | ;({x=print}).x("hi") -------------------------------------------------------------------------------- /test/src/multiassign.lua: -------------------------------------------------------------------------------- 1 | local a, b, c, d 2 | a, b = b, a 3 | a, b, c, d = b, c, d, a 4 | -------------------------------------------------------------------------------- /test/src/multiassign02.lua: -------------------------------------------------------------------------------- 1 | function f(x) 2 | g, h = x 3 | i, j = x, nil 4 | end 5 | -------------------------------------------------------------------------------- /test/src/multiassign03.lua: -------------------------------------------------------------------------------- 1 | function f(a, b, c) 2 | a, b, c = b + c 3 | return a, b, c 4 | end 5 | 6 | function f(a, b, c) 7 | a, b, c = b + c, nil 8 | return a, b, c 9 | end 10 | 11 | function f(a, b, c) 12 | a, b, c = b + c, nil, nil 13 | return a, b, c 14 | end 15 | 16 | function f(a, b, c, d) 17 | a, b, c, d = b + c, nil, nil 18 | return a, b, c, d 19 | end 20 | -------------------------------------------------------------------------------- /test/src/multiassign04.lua: -------------------------------------------------------------------------------- 1 | local a, b, c = f() 2 | b, c = "", nil 3 | -------------------------------------------------------------------------------- /test/src/multiassign05.lua: -------------------------------------------------------------------------------- 1 | local x, y 2 | x, t[1], t.field, t[x], t[x + 4], y = 1, 2, 3, 4, 5, 6 3 | -------------------------------------------------------------------------------- /test/src/multiassign06.lua: -------------------------------------------------------------------------------- 1 | local a, b = t[1], t[2] or {} 2 | -------------------------------------------------------------------------------- /test/src/multiliteraltarget.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = {f()} 3 | -------------------------------------------------------------------------------- /test/src/nestedif.lua: -------------------------------------------------------------------------------- 1 | if x and y then 2 | f() 3 | if z then 4 | g() 5 | end 6 | end 7 | if x and y then 8 | if z then 9 | g() 10 | end 11 | f() 12 | end 13 | if x then 14 | f() 15 | if y then 16 | if z then 17 | g() 18 | end 19 | h() 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /test/src/nestedif02.lua: -------------------------------------------------------------------------------- 1 | if a then 2 | print(a) 3 | if b then 4 | print(b) 5 | if c then 6 | print(c) 7 | else 8 | print(z) 9 | end 10 | else 11 | print(y) 12 | end 13 | else 14 | print(x) 15 | end -------------------------------------------------------------------------------- /test/src/number01.lua: -------------------------------------------------------------------------------- 1 | local a 2 | a = 1 3 | a = 1.0 4 | a = -0 5 | a = -0.0 6 | -------------------------------------------------------------------------------- /test/src/number02.lua: -------------------------------------------------------------------------------- 1 | print(0.0) 2 | print(-0.0) 3 | -------------------------------------------------------------------------------- /test/src/number03.lua: -------------------------------------------------------------------------------- 1 | print(0.0/1.0) 2 | print(-0.0/1.0) 3 | print(0.0/0.0) 4 | -------------------------------------------------------------------------------- /test/src/once01.lua: -------------------------------------------------------------------------------- 1 | print("guard") 2 | local a = 0 3 | repeat -- once 4 | local b = 1 5 | print("1") 6 | if a then 7 | print("2") 8 | break 9 | else 10 | print("3") 11 | end 12 | print("4") 13 | until true 14 | print("5") 15 | local following = 0 16 | print(following) 17 | -------------------------------------------------------------------------------- /test/src/once02.lua: -------------------------------------------------------------------------------- 1 | local L1 = 0 2 | if a then 3 | print("A") 4 | end 5 | print("guard") 6 | repeat 7 | do break end 8 | print("x") 9 | L1 = 6 10 | until true 11 | print(L1) 12 | -------------------------------------------------------------------------------- /test/src/once03.lua: -------------------------------------------------------------------------------- 1 | local x = 0 2 | repeat 3 | do break end 4 | -- unreachable code 5 | x = 1 6 | until true 7 | print("guard") 8 | repeat 9 | do break end 10 | -- unreachable code 11 | if cond() then 12 | x = 2 13 | end 14 | until true 15 | print("guard") 16 | -------------------------------------------------------------------------------- /test/src/once04.lua: -------------------------------------------------------------------------------- 1 | 2 | for i = 1, 10 do 3 | local t = false 4 | repeat 5 | t = f3(i) 6 | if f4() then 7 | break 8 | else 9 | f1() 10 | end 11 | f2() 12 | until true 13 | if t then 14 | break 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /test/src/once05.lua: -------------------------------------------------------------------------------- 1 | for x = 1, 10 do 2 | repeat 3 | print("before") 4 | do break end 5 | print("after") 6 | until true 7 | end -------------------------------------------------------------------------------- /test/src/repeat.lua: -------------------------------------------------------------------------------- 1 | repeat 2 | f() 3 | until a 4 | repeat 5 | if b then 6 | f() 7 | end 8 | until a 9 | repeat 10 | repeat 11 | f() 12 | until b 13 | g() 14 | until a 15 | repeat 16 | f() 17 | repeat 18 | g() 19 | until b 20 | until a 21 | -------------------------------------------------------------------------------- /test/src/repeat02.lua: -------------------------------------------------------------------------------- 1 | if test then 2 | repeat 3 | -- nothing 4 | until attempt() == test 5 | end 6 | -------------------------------------------------------------------------------- /test/src/repeat03.lua: -------------------------------------------------------------------------------- 1 | if x then 2 | print("x") 3 | else 4 | repeat 5 | print("else") 6 | until test() 7 | end 8 | print("end") 9 | -------------------------------------------------------------------------------- /test/src/report01_full.lua: -------------------------------------------------------------------------------- 1 | function myfunction(value) 2 | value = value==nil and true or value 3 | end -------------------------------------------------------------------------------- /test/src/report01a.lua: -------------------------------------------------------------------------------- 1 | function myfunction(value) 2 | value = true or value 3 | end -------------------------------------------------------------------------------- /test/src/report01b.lua: -------------------------------------------------------------------------------- 1 | function myfunction(value) 2 | value = true or 3 3 | end -------------------------------------------------------------------------------- /test/src/report01c.lua: -------------------------------------------------------------------------------- 1 | function myfunction(value) 2 | value = x or value 3 | end -------------------------------------------------------------------------------- /test/src/report01d.lua: -------------------------------------------------------------------------------- 1 | print(a == b or c or d) -------------------------------------------------------------------------------- /test/src/report02.lua: -------------------------------------------------------------------------------- 1 | function report02(a, b) 2 | if a == 1 then 3 | if f(b) > 0 then 4 | -- do nothing 5 | end 6 | else 7 | return 8 | end 9 | end -------------------------------------------------------------------------------- /test/src/report02a.lua: -------------------------------------------------------------------------------- 1 | local i = get() 2 | if i == "one" then 3 | if check1() then 4 | do1() 5 | end 6 | elseif i == "two" then 7 | if check2() then 8 | do2() 9 | else 10 | -- do nothing 11 | end 12 | else 13 | return 14 | end -------------------------------------------------------------------------------- /test/src/report02b.lua: -------------------------------------------------------------------------------- 1 | local id = x 2 | if check() then 3 | local n = tonumber(string.sub(x, 6)) 4 | id = player.episode[n].script or id 5 | end -------------------------------------------------------------------------------- /test/src/report02c.lua: -------------------------------------------------------------------------------- 1 | if check() then 2 | do1() 3 | else 4 | end -------------------------------------------------------------------------------- /test/src/report02d.lua: -------------------------------------------------------------------------------- 1 | function func() 2 | local x = f() 3 | if test(x) then 4 | end 5 | end -------------------------------------------------------------------------------- /test/src/report02e.lua: -------------------------------------------------------------------------------- 1 | function report02e(input) 2 | local x = 1 3 | if test(x) then 4 | do1(x) 5 | else 6 | error("asdf") 7 | end 8 | print("blah") 9 | local y = 4 10 | while true do 11 | do1() 12 | if not check() then 13 | return 14 | end 15 | local z = getz() 16 | if test(z) then 17 | local data1, data2 = getdata() 18 | if data1 == "valid" then 19 | local data3 = getdata(data2) 20 | if data3 then 21 | print("valid data") 22 | end 23 | end 24 | break 25 | end 26 | end 27 | if test3() then 28 | do3() 29 | else 30 | error("asdf") 31 | end 32 | end -------------------------------------------------------------------------------- /test/src/report03.lua: -------------------------------------------------------------------------------- 1 | function report03() 2 | local x = init() 3 | while true do 4 | local y = f(x) 5 | if y == 0 then 6 | break 7 | end 8 | x = next_x(x, y) 9 | if x == 0 then 10 | break 11 | end 12 | for i = x, 1, -1 do 13 | if i > g(x) or i < 1 then 14 | break 15 | end 16 | local z = h(g(x), y) 17 | if not (z == 4) then 18 | break 19 | end 20 | if z > 0 then 21 | finish() 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /test/src/report04.lua: -------------------------------------------------------------------------------- 1 | function a() 2 | repeat 3 | x = true 4 | until z == 0 5 | end 6 | function b() 7 | repeat 8 | x = true 9 | until z < 0 10 | end 11 | function c() 12 | repeat 13 | x = true 14 | until z <= 0 15 | end 16 | -------------------------------------------------------------------------------- /test/src/report05.lua: -------------------------------------------------------------------------------- 1 | while y do 2 | y() 3 | do break end 4 | while z do 5 | z() 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/src/scope02.lua: -------------------------------------------------------------------------------- 1 | -- Compare with scope03.lua 2 | -- The only difference in the compiled output is the scope of local y. 3 | 4 | if x then 5 | local y = f() 6 | if y then 7 | print("y") 8 | else 9 | -- nothing 10 | end 11 | end 12 | print("done") 13 | -------------------------------------------------------------------------------- /test/src/scope03.lua: -------------------------------------------------------------------------------- 1 | -- Compare with scope02.lua 2 | -- The only difference in the compiled output is the scope of local y. 3 | 4 | if x then 5 | local y = f() 6 | if y then 7 | print("y") 8 | end 9 | else 10 | -- nothing 11 | end 12 | print("done") 13 | -------------------------------------------------------------------------------- /test/src/string01.lua: -------------------------------------------------------------------------------- 1 | print("line1\r\nline2\r\nline3\r\nline4\r\nline1\r\nline2\r\nline3\r\nline4\r\nline1\r\nline2\r\nline3\r\nline4\r\nline1\r\nline2\r\nline3\r\nline4\r\nline1\r\nline2\r\nline3\r\nline4\r\nline1\r\nline2\r\nline3\r\nline4\r\nline1\r\nline2\r\nline3\r\nline4\r\nline1\r\nline2\r\nline3\r\nline4\r\nline1\r\nline2\r\nline3\r\nline4\r\n") 2 | -------------------------------------------------------------------------------- /test/src/string02.lua: -------------------------------------------------------------------------------- 1 | print("nested long string [[support in Lua 5.1 [[ is ]] controlled by ]] LUA_COMPAT_LSTR\nnewlines\nare\nneeded\nto\ntrip\nthe\nunluac\nlong string\nheuristic") 2 | -------------------------------------------------------------------------------- /test/src/string04.lua: -------------------------------------------------------------------------------- 1 | print"This is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nBreak 5.0 long string ]] with this" 2 | 3 | print"This is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nThis is a long multi-line string to trigger unluac's long string heuristic.\nBreak 5.0 long string end->]" 4 | -------------------------------------------------------------------------------- /test/src/table01.lua: -------------------------------------------------------------------------------- 1 | local x 2 | x = {} 3 | x.first = 1 4 | x.second = 2 5 | x.third = 3 6 | y = {first = 1, 7 | second = 2, 8 | third = 3} 9 | -------------------------------------------------------------------------------- /test/src/table02.lua: -------------------------------------------------------------------------------- 1 | if buffer then 2 | print("buffer") 3 | end 4 | local x = {table_elt = 6} 5 | local list = {1, 6 | 6, 7 | 3, 8 | 2, 9 | 6, 10 | 3, 11 | 2, 12 | 6, 13 | 6} 14 | -------------------------------------------------------------------------------- /test/src/table06.lua: -------------------------------------------------------------------------------- 1 | local t = {["a"] = 1, ["b"] = 2, ["c"] = 3} 2 | local u = {[1] = 1, [2] = 2, [3] = 3} 3 | local v = {["a"] = 1, ["b"] = 2, ["c"] = 3, [1] = 1, [2] = 2, [3] = 3} 4 | local w = {[f()] = 1, [g()] = 2, [h()] = 3} 5 | -------------------------------------------------------------------------------- /test/src/table07.lua: -------------------------------------------------------------------------------- 1 | local t = {f()} 2 | local s = {1, 2, 3, g()} 3 | 4 | for i = 1, 10 do 5 | print(t[i], s[i]) 6 | end 7 | -------------------------------------------------------------------------------- /test/src/unused01.lua: -------------------------------------------------------------------------------- 1 | while 1 do 2 | print("x") 3 | work() 4 | end 5 | -------------------------------------------------------------------------------- /test/src/upvalue01.lua: -------------------------------------------------------------------------------- 1 | local upvalue1 = {} 2 | local upvalue2 = {} 3 | function f() 4 | local a = upvalue1.print 5 | local b = upvalue2.print 6 | local c = _ENV.print 7 | return print 8 | end 9 | function g() 10 | return _ENV.print 11 | end 12 | function f2(a) 13 | upvalue1.print = a 14 | upvalue2.print = a 15 | _ENV.print = a 16 | print = a 17 | end 18 | -------------------------------------------------------------------------------- /test/src/upvalue02.lua: -------------------------------------------------------------------------------- 1 | function f() 2 | _ENV[1] = 0 3 | return _ENV[1] 4 | end 5 | -------------------------------------------------------------------------------- /test/src/upvalue03.lua: -------------------------------------------------------------------------------- 1 | function f() 2 | a,b,c = g(),g(),g() 3 | end 4 | -------------------------------------------------------------------------------- /test/src/upvalue04.lua: -------------------------------------------------------------------------------- 1 | if x then 2 | local upvalue = 0 3 | f = function() 4 | print(upvalue) 5 | upvalue = upvalue + 1 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/src/upvalue05.lua: -------------------------------------------------------------------------------- 1 | for k, v in pairs(t) do 2 | function v.__tostring() 3 | return k 4 | end 5 | end 6 | 7 | for k, v in pairs(t) do 8 | local x = v() 9 | function v.__tostring() 10 | return munge(k, x) 11 | end 12 | end 13 | 14 | for k, v in pairs(t) do 15 | local x = v() 16 | function v.__tostring() 17 | return k 18 | end 19 | end 20 | 21 | for k, v in pairs(t) do 22 | local x = v() 23 | print(x) 24 | end 25 | 26 | for k, v in pairs(t) do 27 | local x = v() 28 | local y = g(x) 29 | function v.__tostring() 30 | return munge(k, y) 31 | end 32 | end 33 | 34 | 35 | for i = 1, 1000 do 36 | t[i].__tostring = function() 37 | return i 38 | end 39 | end 40 | 41 | for i = 1, 1000 do 42 | local x = t[i].call() 43 | t[i].__tostring = function() 44 | return munge(i, x) 45 | end 46 | end 47 | 48 | for i = 1, 1000 do 49 | local x = t[i].call() 50 | t[i].__tostring = function() 51 | return i 52 | end 53 | end 54 | 55 | for i = 1, 1000 do 56 | local x = t[i].call() 57 | print(x) 58 | end 59 | 60 | for i = 1, 1000 do 61 | local x = t[i].call() 62 | local y = g(x) 63 | t[i].__tostring = function() 64 | return munge(i, y) 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /test/src/while.lua: -------------------------------------------------------------------------------- 1 | while a do 2 | f() 3 | end 4 | while a do 5 | if b then 6 | f() 7 | end 8 | end 9 | while a do 10 | while b do 11 | f() 12 | end 13 | g() 14 | end 15 | while a do 16 | f() 17 | while b do 18 | g() 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /test/src/while02.lua: -------------------------------------------------------------------------------- 1 | if elseredirect then 2 | if inner then 3 | local x = 1 4 | while x < 100 do 5 | print(x) 6 | x = x + 1 7 | end 8 | end 9 | else 10 | print("else") 11 | end 12 | -------------------------------------------------------------------------------- /test/src/while03.lua: -------------------------------------------------------------------------------- 1 | if elseredirect then 2 | if inner then 3 | local x = 1 4 | while call(a or b) do 5 | print(x) 6 | x = x + 1 7 | end 8 | end 9 | else 10 | print("else") 11 | end 12 | -------------------------------------------------------------------------------- /test/src/while04.lua: -------------------------------------------------------------------------------- 1 | local t = {} 2 | 3 | print("test 1") 4 | 5 | while true do 6 | t[1] = 0 7 | if f() then 8 | break 9 | end 10 | print("loop") 11 | end 12 | 13 | print("test 2") 14 | 15 | -- strange test 16 | -- for Lua 5.1, while f() is not usually to while true if not f() break 17 | -- This is because it doesn't have the 5.2-style if-break optimization 18 | -- To get 5.2-style if-break jump, we need to second target of the 19 | -- if to be redirected -- by putting a break after the if statement. 20 | while true do 21 | t[1] = 0 22 | if f() then 23 | end 24 | do break end 25 | print("loop") 26 | end 27 | 28 | 29 | print("test 3") 30 | 31 | while f() and {1, 2, 3} and g() do 32 | print("loop") 33 | end 34 | 35 | print("test 4") 36 | 37 | while f() and {a = 1, b = 2, c = 3} and g() do 38 | print("loop") 39 | end 40 | -------------------------------------------------------------------------------- /test/src/while05.lua: -------------------------------------------------------------------------------- 1 | if a then 2 | print(1) 3 | end 4 | while b do 5 | print(2) 6 | end 7 | print(3) 8 | -------------------------------------------------------------------------------- /test/src/while06.lua: -------------------------------------------------------------------------------- 1 | while a do 2 | if b then 3 | f() 4 | else 5 | break 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/src/while07.lua: -------------------------------------------------------------------------------- 1 | local x 2 | while test() do 3 | x = a or b + 1 4 | end 5 | -------------------------------------------------------------------------------- /unluac.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | --------------------------------------------------------------------------------