[
  {
    "path": ".gitignore",
    "content": "*.lua[co]\n*.py[cod]\n\n# C extensions\n*.so\n\n# Packages\n*.egg\n*.egg-info\ndist\nbuild\neggs\nparts\nbin\nvar\nsdist\ndevelop-eggs\n.installed.cfg\nlib\nlib64\n__pycache__\n\n# Installer logs\npip-log.txt\n\n# Unit test / coverage reports\n.coverage\n.tox\nnosetests.xml\n\n# Translations\n*.mo\n\n# Mr Developer\n.mr.developer.cfg\n.project\n.pydevproject\n.*.swp\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2013 Andrian Nord\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "代码在fork https://github.com/NightNord/ljd 的基础上修改的\n\n主要修正了原版本没有将_read_header函数解析过的header中的flag值带进_read_protoypes。\n\n解决了原代码只能解析带调试信息的luajit字节码，而解析不带调试信息字节码时报错的问题。\n\n此版本可解析luajit2.1.0-beta2的字节码文件。如果要解析其它版本的luajit字节码文件，需要将\n\nluajit源码中的opcode，写进instruction.py 和 code.py\n\n\n使用说明：python main.py  \"path of luajit-bytecode\"\n\n解释文档：http://www.freebuf.com/column/177810.html\n\n参考：https://github.com/NightNord/ljd\n      https://github.com/feicong/lua_re/blob/master/lua/lua_re3.md\n\t  https://bbs.pediy.com/thread-216800.htm"
  },
  {
    "path": "README.md.txt",
    "content": "LuaJIT raw-bytecode decompiler (LJD)\n===\n\nThe original name was _ljwthgnd_ as in _LuaJIT 'What The Hell is Going On'\nDecompiler_ named under the LuaJIT C sources variable naming convention.\n\n\n__WARNING!__ This code is nor finished, nor tested yet! There is no even\nslightest warranty that resulting code is even near to the original. Use it at\nyour own risk of the wasted time.\n\n__SECOND WARNING!__ And, BTW, this all is a one huge prototype. Because the\n\"release\" version should be written into lua itself. Because it's cool to\ndecompile the decompiler - a great test too!\n\nRequirements\n---\n\nPython __3.0+__ from python.org\n\n\nHow to use it\n---\n\nThere is no argument parsing right now, so comment out things in the ```main.py```\nscript and launch it as in ```main.py path/to/file.luac```\n\nTODO\n---\n\nThere is a lot of work to do, in the order of priority\n\n0. Logical subexpressions in while statements:\n\t```lua\n\t\twhile x < (xi and 2 or 3) do\n\t\t\tprint (\"Hello crazy world!\")\n\t\tend\n\t```\n\n\tLogical subexpressions (the subexpressions used as operands in\n\tariphmetic or comparison operations inside other exrpressions) are\n\tcurrently supported only for ifs. To support them for whiles and\n\trepeat untils an expression unwarping logic should be moved at the\n\tvery beginning. But it won't work without all fixes being done in\n\ta loop unwarping logic. So we need to split that and move the fixes \n\tbefore expressions before loops before ifs. That's not that easy...\n\n1. AST Mutations:\n\t1. Use the line information (or common sense if there is no line\n\t   information) to squash similar expressions into a single expression.\n\n2. Formatting improvements\n\t1. Use the line information (or common sense) to preserve empty lines\n\t   and break long statements like in the original code.\n\t   \n\t   This is mostly done, but only in the \"common sense\" part.\n\n\t2. Use method-style calls and definitions for tables.\n\n3. Features not supported:\n\t1. GOTO statement (from lua 5.2). All the required functionality is\n\t\tnow in place, but that's rather a low-priority task right now.\n\n\t2. Local sub-blocks:\n\t```lua\n\tdo\n\t\t...\n\tend\n\t```\n\t   These subblocks are not reflected anyhow directly in the bytecode.\n\t   The only way to guess them is to watch local variable scopes, which\n\t   is simple enough in case of non-stripped bytecode and a bit\n\t   harder otherwise.\n"
  },
  {
    "path": "gconfig.py",
    "content": "\n#zzw 20180714 support str encode\ngFlagDic = {'strEncode' : 'ascii'}"
  },
  {
    "path": "ljd/__init__.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n"
  },
  {
    "path": "ljd/ast/__init__.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n"
  },
  {
    "path": "ljd/ast/builder.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport ljd.bytecode.instructions as ins\n\nfrom ljd.bytecode.helpers import get_jump_destination\nfrom ljd.bytecode.constants import T_NIL, T_FALSE, T_TRUE\n\nimport ljd.ast.nodes as nodes\n\n\nclass _State():\n\tdef __init__(self):\n\t\tself.constants = None\n\t\tself.debuginfo = None\n\t\tself.block = None\n\t\tself.blocks = []\n\t\tself.block_starts = {}\n\n\tdef _warp_in_block(self, addr):\n\t\t#print (self.block_starts)\n\t\t#print (addr)\n\t\tblock = self.block_starts[addr]\n\t\tblock.warpins_count += 1\n\t\treturn block\n\n\ndef build(prototype):\n\treturn _build_function_definition(prototype)\n\n\ndef _build_function_definition(prototype):\n\tnode = nodes.FunctionDefinition()\n\n\tstate = _State()\n\n\tstate.constants = prototype.constants\n\tstate.debuginfo = prototype.debuginfo\n\n\tnode._upvalues = prototype.constants.upvalue_references\n\tnode._debuginfo = prototype.debuginfo\n\tnode._instructions_count = len(prototype.instructions)\n\n\tnode.arguments.contents = _build_function_arguments(state, prototype)\n\n\tif prototype.flags.is_variadic:\n\t\tnode.arguments.contents.append(nodes.Vararg())\n\n\tinstructions = prototype.instructions\n\t#print (len(instructions))\n\tnode.statements.contents = _build_function_blocks(state, instructions)\n\n\treturn node\n\n\ndef _build_function_arguments(state, prototype):\n\targuments = []\n\n\tcount = prototype.arguments_count\n\n\tslot = 0\n\twhile slot < count:\n\t\tvariable = _build_slot(state, 0, slot)\n\n\t\targuments.append(variable)\n\t\tslot += 1\n\n\treturn arguments\n\n\ndef _build_function_blocks(state, instructions):\n\t_blockenize(state, instructions)\n\t_establish_warps(state, instructions)\n\n\tstate.blocks[0].warpins_count = 1\n\n\tfor block in state.blocks:\n\t\taddr = block.first_address\n\t\tstate.block = block\n\n\t\twhile addr <= block._last_body_addr:\n\t\t\tinstruction = instructions[addr]\n\n\t\t\tstatement = _build_statement(state, addr, instruction)\n\n\t\t\tif statement is not None:\n\t\t\t\tline = state.debuginfo.lookup_line_number(addr)\n\n\t\t\t\tsetattr(statement, \"_addr\", addr)\n\t\t\t\tsetattr(statement, \"_line\", line)\n\n\t\t\t\tblock.contents.append(statement)\n\n\t\t\taddr += 1\n\n\treturn state.blocks\n\n\n_JUMP_WARP_INSTRUCTIONS = set((\n\tins.UCLO.opcode,\n\tins.ISNEXT.opcode,\n\tins.JMP.opcode,\n\tins.FORI.opcode,\n\tins.JFORI.opcode\n))\n\n\n_WARP_INSTRUCTIONS = _JUMP_WARP_INSTRUCTIONS | set((\n\tins.FORL.opcode, ins.IFORL.opcode, ins.JFORL.opcode,\n\tins.ITERL.opcode, ins.IITERL.opcode, ins.JITERL.opcode,\n\tins.LOOP.opcode\n))\n\n\ndef _blockenize(state, instructions):\n\taddr = 1\n\n\t# Duplicates are possible and ok, but we need to sort them out\n\tlast_addresses = set()\n\n\twhile addr < len(instructions):\n\t\tinstruction = instructions[addr]\n\t\topcode = instruction.opcode\n\n\t\tif opcode not in _WARP_INSTRUCTIONS:\n\t\t\taddr += 1\n\t\t\tcontinue\n\n\t\tif opcode in _JUMP_WARP_INSTRUCTIONS:\n\t\t\tdestination = get_jump_destination(addr, instruction)\n\n\t\t\tif opcode != ins.UCLO.opcode or destination != addr + 1:\n\t\t\t\tlast_addresses.add(destination - 1)\n\t\t\t\tlast_addresses.add(addr)\n\t\telse:\n\t\t\tlast_addresses.add(addr)\n\n\t\taddr += 1\n\n\tlast_addresses = sorted(list(last_addresses))\n\tlast_addresses.append(len(instructions) - 1)\n\n\t# This could happen if something jumps to the first instruction\n\t# We don't need \"zero block\" with function header, so simply ignore\n\t# this\n\tif last_addresses[0] == 0:\n\t\tlast_addresses.pop(0)\n\n\tprevious_last_address = 0\n\n\tindex = 0\n\tfor last_address in last_addresses:\n\t\tblock = nodes.Block()\n\t\tblock.index = index\n\t\tblock.first_address = previous_last_address + 1\n\t\tblock.last_address = last_address\n\n\t\tstate.blocks.append(block)\n\t\tstate.block_starts[block.first_address] = block\n\n\t\tprevious_last_address = last_address\n\n\t\tindex += 1\n\n\ndef _establish_warps(state, instructions):\n\tstate.blocks[0].warpins_count = 1\n\n\tfor block in state.blocks[:-1]:\n\t\tstate.block = block\n\n\t\tend_addr = block.last_address + 1\n\t\tstart_addr = max(block.last_address - 1, block.first_address)\n\n\t\twarp = instructions[start_addr:end_addr]\n\t\t#print (block.first_address)\n\t\tblock.warp, shift = _build_warp(state, block.last_address, warp)\n\n\t\tsetattr(block, \"_last_body_addr\", block.last_address - shift)\n\t\tsetattr(block.warp, \"_addr\", block.last_address - shift + 1)\n\n\tlast_block = state.blocks[-1]\n\tlast_block.warp = nodes.EndWarp()\n\n\tsetattr(last_block, \"_last_body_addr\", last_block.last_address)\n\tsetattr(last_block.warp, \"_addr\", last_block.last_address)\n\n\ndef _build_warp(state, last_addr, instructions):\n\tlast = instructions[-1]\n\t#print (\"%x\"%(last.opcode))\n\tif last.opcode in (ins.JMP.opcode, ins.UCLO.opcode, ins.ISNEXT.opcode):\n\t\treturn _build_jump_warp(state, last_addr, instructions)\n\n\telif last.opcode >= ins.ITERL.opcode and last.opcode <= ins.JITERL.opcode:\n\t\tassert len(instructions) == 2\n\t\treturn _build_iterator_warp(state, last_addr, instructions)\n\n\telif last.opcode >= ins.FORL.opcode and last.opcode <= ins.JFORL.opcode:\n\t\treturn _build_numeric_loop_warp(state, last_addr, last)\n\n\telse:\n\t\treturn _build_flow_warp(state, last_addr, last)\n\n\ndef _build_jump_warp(state, last_addr, instructions):\n\tlast = instructions[-1]\n\topcode = 256 if len(instructions) == 1 else instructions[-2].opcode\n\n\tif opcode <= ins.ISF.opcode:\n\t\tassert last.opcode != ins.ISNEXT.opcode\n\t\treturn _build_conditional_warp(state, last_addr, instructions)\n\telse:\n\t\treturn _build_unconditional_warp(state, last_addr, last)\n\n\ndef _build_conditional_warp(state, last_addr, instructions):\n\tcondition = instructions[-2]\n\tcondition_addr = last_addr - 1\n\n\twarp = nodes.ConditionalWarp()\n\n\tif condition.opcode in (ins.ISTC.opcode, ins.ISFC.opcode):\n\t\texpression = _build_unary_expression(state,\n\t\t\t\t\t\t\tcondition_addr,\n\t\t\t\t\t\t\tcondition)\n\n\t\tsetattr(warp, \"_slot\", condition.A)\n\telif condition.opcode >= ins.IST.opcode:\n\t\texpression = _build_unary_expression(state,\n\t\t\t\t\t\t\tcondition_addr,\n\t\t\t\t\t\t\tcondition)\n\n\t\tsetattr(warp, \"_slot\", condition.CD)\n\telse:\n\t\texpression = _build_comparison_expression(state,\n\t\t\t\t\t\t\tcondition_addr,\n\t\t\t\t\t\t\tcondition)\n\n\twarp.condition = expression\n\n\tjump = instructions[-1]\n\tjump_addr = last_addr\n\n\tdestination = get_jump_destination(jump_addr, jump)\n\n\t# A condition is inverted during the preparation phase above\n\twarp.false_target = state._warp_in_block(destination)\n\twarp.true_target = state._warp_in_block(jump_addr + 1)\n\n\treturn warp, 2\n\n\ndef _build_unconditional_warp(state, addr, instruction):\n\twarp = nodes.UnconditionalWarp()\n\twarp.type = nodes.UnconditionalWarp.T_JUMP\n\n\topcode = instruction.opcode\n\n\twarp.is_uclo = opcode == ins.UCLO.opcode\n\n\tif warp.is_uclo and instruction.CD == 0:\n\t\t# Not a jump\n\t\treturn _build_flow_warp(state, addr, instruction)\n\telse:\n\t\tdestination = get_jump_destination(addr, instruction)\n\t\twarp.target = state._warp_in_block(destination)\n\n\treturn warp, 1\n\n\ndef _build_iterator_warp(state, last_addr, instructions):\n\titerator = instructions[-2]\n\titerator_addr = last_addr - 1\n\n\tassert iterator.opcode in (ins.ITERC.opcode, ins.ITERN.opcode)\n\n\twarp = nodes.IteratorWarp()\n\n\tbase = iterator.A\n\n\twarp.controls.contents = [\n\t\t_build_slot(state, iterator_addr, base - 3),  # generator\n\t\t_build_slot(state, iterator_addr, base - 2),  # state\n\t\t_build_slot(state, iterator_addr, base - 1)  # control\n\t]\n\n\tlast_slot = base + iterator.B - 2\n\n\tslot = base\n\n\twhile slot <= last_slot:\n\t\tvariable = _build_slot(state, iterator_addr - 1, slot)\n\t\twarp.variables.contents.append(variable)\n\t\tslot += 1\n\n\tjump = instructions[-1]\n\tjump_addr = last_addr\n\n\tdestination = get_jump_destination(jump_addr, jump)\n\twarp.way_out = state._warp_in_block(jump_addr + 1)\n\twarp.body = state._warp_in_block(destination)\n\n\treturn warp, 2\n\n\ndef _build_numeric_loop_warp(state, addr, instruction):\n\twarp = nodes.NumericLoopWarp()\n\n\tbase = instruction.A\n\n\twarp.index = _build_slot(state, addr, base + 3)\n\twarp.controls.contents = [\n\t\t_build_slot(state, addr, base + 0),  # start\n\t\t_build_slot(state, addr, base + 1),  # limit\n\t\t_build_slot(state, addr, base + 2)  # step\n\t]\n\t#print (\"%x\" % instruction.A)\n\t#print (\"%x\" %instruction.CD)\n\tdestination = get_jump_destination(addr, instruction)\n\twarp.body = state._warp_in_block(destination)\n\twarp.way_out = state._warp_in_block(addr + 1)\n\n\treturn warp, 1\n\n\ndef _build_flow_warp(state, addr, instruction):\n\twarp = nodes.UnconditionalWarp()\n\twarp.type = nodes.UnconditionalWarp.T_FLOW\n\twarp.target = state._warp_in_block(addr + 1)\n\n\topcode = instruction.opcode\n\tshift = 1 if opcode in (ins.FORI.opcode, ins.UCLO.opcode) else 0\n\n\treturn warp, shift\n\n\ndef _build_statement(state, addr, instruction):\n\topcode = instruction.opcode\n\tA_type = instruction.A_type\n\n\t# Generic assignments - handle the ASSIGNMENT stuff below\n\tif A_type == ins.T_DST or A_type == ins.T_UV:\n\t\treturn _build_var_assignment(state, addr, instruction)\n\n\t# ASSIGNMENT starting from MOV and ending at KPRI\n\n\telif opcode == ins.KNIL.opcode:\n\t\treturn _build_knil(state, addr, instruction)\n\n\t# ASSIGNMENT starting from UGET and ending at USETP\n\n\t# SKIP UCL0 is handled below\n\n\t# ASSIGNMENT starting from FNEW and ending at GGET\n\n\telif opcode == ins.GSET.opcode:\n\t\treturn _build_global_assignment(state, addr, instruction)\n\n\t# ASSIGNMENT starting from TGETV and ending at TGETB\n\n\telif opcode >= ins.TSETV.opcode and opcode <= ins.TSETB.opcode:\n\t\treturn _build_table_assignment(state, addr, instruction)\n\n\telif opcode == ins.TSETM.opcode:\n\t\treturn _build_table_mass_assignment(state, addr, instruction)\n\n\telif opcode >= ins.CALLM.opcode and opcode <= ins.CALLT.opcode:\n\t\treturn _build_call(state, addr, instruction)\n\n\telif opcode == ins.VARG.opcode:\n\t\treturn _build_vararg(state, addr, instruction)\n\n\telif opcode >= ins.RETM.opcode and opcode <= ins.RET1.opcode:\n\t\treturn _build_return(state, addr, instruction)\n\n\telse:\n\t\tassert opcode == ins.UCLO.opcode or (\n\t\t\t\topcode >= ins.LOOP.opcode\n\t\t\t\t\t\tand opcode <= ins.JLOOP.opcode)\n\t\t# Noop\n\t\treturn None\n\n\ndef _build_var_assignment(state, addr, instruction):\n\topcode = instruction.opcode\n\n\tassignment = nodes.Assignment()\n\n\t# Unary assignment operators (A = op D)\n\tif opcode == ins.MOV.opcode\t\t\t\\\n\t\t\tor opcode == ins.NOT.opcode\t\\\n\t\t\tor opcode == ins.UNM.opcode\t\\\n\t\t\tor opcode == ins.LEN.opcode:\n\t\texpression = _build_unary_expression(state, addr, instruction)\n\n\t# Binary assignment operators (A = B op C)\n\telif opcode <= ins.POW.opcode:\n\t\texpression = _build_binary_expression(state, addr, instruction)\n\n\t# Concat assignment type (A = B .. B + 1 .. ... .. C - 1 .. C)\n\telif opcode == ins.CAT.opcode:\n\t\texpression = _build_concat_expression(state, addr, instruction)\n\n\t# Constant assignment operators except KNIL, which is weird anyway\n\telif opcode <= ins.KPRI.opcode:\n\t\texpression = _build_const_expression(state, addr, instruction)\n\n\telif opcode == ins.UGET.opcode:\n\t\texpression = _build_upvalue(state, addr, instruction.CD)\n\n\telif opcode == ins.USETV.opcode:\n\t\texpression = _build_slot(state, addr, instruction.CD)\n\n\telif opcode <= ins.USETP.opcode:\n\t\texpression = _build_const_expression(state, addr, instruction)\n\n\telif opcode == ins.FNEW.opcode:\n\t\texpression = _build_function(state, instruction.CD)\n\n\telif opcode == ins.TNEW.opcode:\n\t\texpression = nodes.TableConstructor()\n\n\telif opcode == ins.TDUP.opcode:\n\t\texpression = _build_table_copy(state, instruction.CD)\n\n\telif opcode == ins.GGET.opcode:\n\t\texpression = _build_global_variable(state, addr, instruction.CD)\n\n\telse:\n\t\tassert opcode <= ins.TGETB.opcode\n\t\texpression = _build_table_element(state, addr, instruction)\n\n\tassignment.expressions.contents.append(expression)\n\n\tif instruction.A_type == ins.T_DST:\n\t\tdestination = _build_slot(state, addr, instruction.A)\n\telse:\n\t\tassert instruction.A_type == ins.T_UV\n\n\t\tdestination = _build_upvalue(state, addr, instruction.A)\n\n\tassignment.destinations.contents.append(destination)\n\n\treturn assignment\n\n\ndef _build_knil(state, addr, instruction):\n\tnode = _build_range_assignment(state, addr, instruction.A, instruction.CD)\n\n\tnode.expressions.contents = [_build_primitive(state, None)]\n\n\treturn node\n\n\ndef _build_global_assignment(state, addr, instruction):\n\tassignment = nodes.Assignment()\n\n\tvariable = _build_global_variable(state, addr, instruction.CD)\n\texpression = _build_slot(state, addr, instruction.A)\n\n\tassignment.destinations.contents.append(variable)\n\tassignment.expressions.contents.append(expression)\n\n\treturn assignment\n\n\ndef _build_table_assignment(state, addr, instruction):\n\tassignment = nodes.Assignment()\n\n\tdestination = _build_table_element(state, addr, instruction)\n\texpression = _build_slot(state, addr, instruction.A)\n\n\tassignment.destinations.contents.append(destination)\n\tassignment.expressions.contents.append(expression)\n\n\treturn assignment\n\n\ndef _build_table_mass_assignment(state, addr, instruction):\n\tassignment = nodes.Assignment()\n\n\tbase = instruction.A\n\n\tdestination = nodes.TableElement()\n\tdestination.key = nodes.MULTRES()\n\tdestination.table = _build_slot(state, addr, base - 1)\n\n\tassignment.destinations.contents = [destination]\n\tassignment.expressions.contents = [nodes.MULTRES()]\n\n\treturn assignment\n\n\ndef _build_call(state, addr, instruction):\n\tcall = nodes.FunctionCall()\n\tcall.function = _build_slot(state, addr, instruction.A)\n\tcall.arguments.contents = _build_call_arguments(state, addr, instruction)\n\n\tif instruction.opcode <= ins.CALL.opcode:\n\t\tif instruction.B == 0:\n\t\t\tnode = nodes.Assignment()\n\t\t\tnode.destinations.contents.append(nodes.MULTRES())\n\t\t\tnode.expressions.contents.append(call)\n\t\telif instruction.B == 1:\n\t\t\tnode = call\n\t\telse:\n\t\t\tfrom_slot = instruction.A\n\t\t\tto_slot = instruction.A + instruction.B - 2\n\t\t\tnode = _build_range_assignment(state, addr, from_slot,\n\t\t\t\t\t\t\t\t\tto_slot)\n\t\t\tnode.expressions.contents.append(call)\n\telse:\n\t\tassert instruction.opcode <= ins.CALLT.opcode\n\t\tnode = nodes.Return()\n\t\tnode.returns.contents.append(call)\n\n\treturn node\n\n\ndef _build_vararg(state, addr, instruction):\n\tbase = instruction.A\n\tlast_slot = base + instruction.B - 2\n\n\tif last_slot < base:\n\t\tnode = nodes.Assignment()\n\t\tnode.destinations.contents.append(nodes.MULTRES())\n\t\tnode.expressions.contents.append(nodes.Vararg())\n\telse:\n\t\tnode = _build_range_assignment(state, addr, base, last_slot)\n\t\tnode.expressions.contents.append(nodes.Vararg())\n\n\treturn node\n\n\ndef _build_return(state, addr, instruction):\n\tnode = nodes.Return()\n\n\tbase = instruction.A\n\tlast_slot = base + instruction.CD - 1\n\n\tif instruction.opcode != ins.RETM.opcode:\n\t\tlast_slot -= 1\n\n\tslot = base\n\n\t# Negative count for the RETM is OK\n\twhile slot <= last_slot:\n\t\tvariable = _build_slot(state, addr, slot)\n\t\tnode.returns.contents.append(variable)\n\t\tslot += 1\n\n\tif instruction.opcode == ins.RETM.opcode:\n\t\tnode.returns.contents.append(nodes.MULTRES())\n\n\treturn node\n\n\ndef _build_call_arguments(state, addr, instruction):\n\tbase = instruction.A\n\tlast_argument_slot = base + instruction.CD\n\n\tis_variadic = (instruction.opcode == ins.CALLM.opcode\t\\\n\t\t\tor instruction.opcode == ins.CALLMT.opcode)\n\n\tif not is_variadic:\n\t\tlast_argument_slot -= 1\n\n\targuments = []\n\n\tslot = base + 1\n\n\twhile slot <= last_argument_slot:\n\t\targument = _build_slot(state, addr, slot)\n\t\targuments.append(argument)\n\t\tslot += 1\n\n\tif is_variadic:\n\t\targuments.append(nodes.MULTRES())\n\n\treturn arguments\n\n\ndef _build_range_assignment(state, addr, from_slot, to_slot):\n\tassignment = nodes.Assignment()\n\n\tslot = from_slot\n\n\tassert from_slot <= to_slot\n\n\twhile slot <= to_slot:\n\t\tdestination = _build_slot(state, addr, slot)\n\n\t\tassignment.destinations.contents.append(destination)\n\n\t\tslot += 1\n\n\treturn assignment\n\n\n_BINARY_OPERATOR_MAP = [None] * 255\n\n_BINARY_OPERATOR_MAP[ins.ADDVN.opcode] = nodes.BinaryOperator.T_ADD\n_BINARY_OPERATOR_MAP[ins.SUBVN.opcode] = nodes.BinaryOperator.T_SUBTRACT\n_BINARY_OPERATOR_MAP[ins.MULVN.opcode] = nodes.BinaryOperator.T_MULTIPLY\n_BINARY_OPERATOR_MAP[ins.DIVVN.opcode] = nodes.BinaryOperator.T_DIVISION\n_BINARY_OPERATOR_MAP[ins.MODVN.opcode] = nodes.BinaryOperator.T_MOD\n\n\ndef _build_binary_expression(state, addr, instruction):\n\toperator = nodes.BinaryOperator()\n\topcode = instruction.opcode\n\n\tif opcode == ins.POW.opcode:\n\t\toperator.type = nodes.BinaryOperator.T_POW\n\telse:\n\t\tmap_index = opcode - ins.ADDVN.opcode\n\t\tmap_index %= 5\n\t\tmap_index += ins.ADDVN.opcode\n\n\t\toperator.type = _BINARY_OPERATOR_MAP[map_index]\n\n\tif instruction.B_type == ins.T_VAR and instruction.CD_type == ins.T_VAR:\n\t\toperator.left = _build_slot(state, addr, instruction.B)\n\t\toperator.right = _build_slot(state, addr, instruction.CD)\n\telif instruction.B_type == ins.T_VAR:\n\t\toperator.left = _build_slot(state, addr, instruction.B)\n\t\toperator.right = _build_numeric_constant(state, instruction.CD)\n\telse:\n\t\tassert instruction.CD_type == ins.T_VAR\n\n\t\toperator.right = _build_slot(state, addr, instruction.B)\n\t\toperator.left = _build_numeric_constant(state, instruction.CD)\n\n\treturn operator\n\n\ndef _build_concat_expression(state, addr, instruction):\n\toperator = nodes.BinaryOperator()\n\toperator.type = nodes.BinaryOperator.T_CONCAT\n\n\tslot = instruction.B\n\n\toperator.left = _build_slot(state, addr, slot)\n\toperator.right = _build_slot(state, addr, slot + 1)\n\n\tslot += 2\n\n\twhile slot <= instruction.CD:\n\t\tupper_operator = nodes.BinaryOperator()\n\t\tupper_operator.left = operator\n\t\tupper_operator.right = _build_slot(state, addr, slot)\n\t\tupper_operator.type = nodes.BinaryOperator.T_CONCAT\n\n\t\toperator = upper_operator\n\n\t\tslot += 1\n\n\treturn operator\n\n\ndef _build_const_expression(state, addr, instruction):\n\tCD_type = instruction.CD_type\n\n\tif CD_type == ins.T_STR:\n\t\treturn _build_string_constant(state, instruction.CD)\n\telif CD_type == ins.T_CDT:\n\t\treturn _build_cdata_constant(state, instruction.CD)\n\telif CD_type == ins.T_SLIT:\n\t\tvalue = instruction.CD\n\n\t\tif value & 0x8000:\n\t\t\tvalue = -0x10000 + value\n\n\t\treturn _build_literal(state, value)\n\telif CD_type == ins.T_LIT:\n\t\treturn _build_literal(state, instruction.CD)\n\telif CD_type == ins.T_NUM:\n\t\treturn _build_numeric_constant(state, instruction.CD)\n\telse:\n\t\tassert CD_type == ins.T_PRI\n\t\treturn _build_primitive(state, instruction.CD)\n\n\ndef _build_table_element(state, addr, instruction):\n\tnode = nodes.TableElement()\n\tnode.table = _build_slot(state, addr, instruction.B)\n\n\tif instruction.CD_type == ins.T_VAR:\n\t\tnode.key = _build_slot(state, addr, instruction.CD)\n\telse:\n\t\tnode.key = _build_const_expression(state, addr, instruction)\n\n\treturn node\n\n\ndef _build_function(state, slot):\n\tprototype = state.constants.complex_constants[slot]\n\n\treturn _build_function_definition(prototype)\n\n\ndef _build_table_copy(state, slot):\n\tnode = nodes.TableConstructor()\n\n\ttable = state.constants.complex_constants[slot]\n\n\ti = 0\n\n\tfor value in table.array:\n\t\trecord = nodes.ArrayRecord()\n\t\trecord.value = _build_table_record_item(value)\n\n\t\tnode.array.contents.append(record)\n\n\t\ti += 1\n\n\tfor key, value in table.dictionary:\n\t\trecord = nodes.TableRecord()\n\t\trecord.key = _build_table_record_item(key)\n\t\trecord.value = _build_table_record_item(value)\n\n\t\tnode.records.contents.append(record)\n\n\treturn node\n\n\ndef _build_table_record_item(value):\n\tif value is None:\n\t\titem = nodes.Primitive()\n\t\titem.type = nodes.Primitive.T_NIL\n\telif value is True:\n\t\titem = nodes.Primitive()\n\t\titem.type = nodes.Primitive.T_TRUE\n\telif value is False:\n\t\titem = nodes.Primitive()\n\t\titem.type = nodes.Primitive.T_FALSE\n\telif isinstance(value, int):\n\t\titem = nodes.Constant()\n\t\titem.value = value\n\t\titem.type = nodes.Constant.T_INTEGER\n\telif isinstance(value, float):\n\t\titem = nodes.Constant()\n\t\titem.value = value\n\t\titem.type = nodes.Constant.T_FLOAT\n\telif isinstance(value, str):\n\t\titem = nodes.Constant()\n\t\titem.value = value\n\t\titem.type = nodes.Constant.T_STRING\n\n\treturn item\n\n\n_COMPARISON_MAP = [None] * 255\n\n# Mind the inversion - comparison operators are affecting JMP to the next block\n# So in the normal code a comparison will be inverted\n_COMPARISON_MAP[ins.ISLT.opcode] = nodes.BinaryOperator.T_GREATER_OR_EQUAL\n_COMPARISON_MAP[ins.ISGE.opcode] = nodes.BinaryOperator.T_LESS_THEN\n_COMPARISON_MAP[ins.ISLE.opcode] = nodes.BinaryOperator.T_GREATER_THEN\n_COMPARISON_MAP[ins.ISGT.opcode] = nodes.BinaryOperator.T_LESS_OR_EQUAL\n\n_COMPARISON_MAP[ins.ISEQV.opcode] = nodes.BinaryOperator.T_NOT_EQUAL\n_COMPARISON_MAP[ins.ISNEV.opcode] = nodes.BinaryOperator.T_EQUAL\n\n_COMPARISON_MAP[ins.ISEQS.opcode] = nodes.BinaryOperator.T_NOT_EQUAL\n_COMPARISON_MAP[ins.ISNES.opcode] = nodes.BinaryOperator.T_EQUAL\n\n_COMPARISON_MAP[ins.ISEQN.opcode] = nodes.BinaryOperator.T_NOT_EQUAL\n_COMPARISON_MAP[ins.ISNEN.opcode] = nodes.BinaryOperator.T_EQUAL\n\n_COMPARISON_MAP[ins.ISEQP.opcode] = nodes.BinaryOperator.T_NOT_EQUAL\n_COMPARISON_MAP[ins.ISNEP.opcode] = nodes.BinaryOperator.T_EQUAL\n\n\ndef _build_comparison_expression(state, addr, instruction):\n\toperator = nodes.BinaryOperator()\n\n\toperator.left = _build_slot(state, addr, instruction.A)\n\n\topcode = instruction.opcode\n\n\tif opcode == ins.ISEQS.opcode or opcode == ins.ISNES.opcode:\n\t\toperator.right = _build_string_constant(state, instruction.CD)\n\telif opcode == ins.ISEQN.opcode\tor opcode == ins.ISNEN.opcode:\n\t\toperator.right = _build_numeric_constant(state, instruction.CD)\n\telif opcode == ins.ISEQP.opcode or opcode == ins.ISNEP.opcode:\n\t\toperator.right = _build_primitive(state, instruction.CD)\n\telse:\n\t\toperator.right = _build_slot(state, addr, instruction.CD)\n\n\toperator.type = _COMPARISON_MAP[instruction.opcode]\n\tassert operator.type is not None\n\n\treturn operator\n\n\ndef _build_unary_expression(state, addr, instruction):\n\topcode = instruction.opcode\n\n\tvariable = _build_slot(state, addr, instruction.CD)\n\n\t# Mind the inversion\n\tif opcode == ins.ISFC.opcode\t\t\t\\\n\t\t\tor opcode == ins.ISF.opcode\t\\\n\t\t\tor opcode == ins.MOV.opcode:\n\t\treturn variable\n\n\toperator = nodes.UnaryOperator()\n\toperator.operand = variable\n\n\tif opcode == ins.ISTC.opcode\t\t\t\\\n\t\t\tor opcode == ins.IST.opcode\t\\\n\t\t\tor opcode == ins.NOT.opcode:\n\t\toperator.type = nodes.UnaryOperator.T_NOT\n\telif opcode == ins.UNM.opcode:\n\t\toperator.type = nodes.UnaryOperator.T_MINUS\n\telse:\n\t\tassert opcode == ins.LEN.opcode\n\t\toperator.type = nodes.UnaryOperator.T_LENGTH_OPERATOR\n\n\treturn operator\n\n\ndef _build_slot(state, addr, slot):\n\treturn _build_identifier(state, addr, slot, nodes.Identifier.T_LOCAL)\n\n\ndef _build_upvalue(state, addr, slot):\n\treturn _build_identifier(state, addr, slot, nodes.Identifier.T_UPVALUE)\n\n\ndef _build_identifier(state, addr, slot, want_type):\n\tnode = nodes.Identifier()\n\tsetattr(node, \"_addr\", addr)\n\n\tnode.slot = slot\n\tnode.type = nodes.Identifier.T_SLOT\n\n\tif want_type == nodes.Identifier.T_UPVALUE:\n\t\tname = state.debuginfo.lookup_upvalue_name(slot)\n\n\t\tif name is not None:\n\t\t\tnode.name = name\n\t\t\tnode.type = want_type\n\n\treturn node\n\n\ndef _build_global_variable(state, addr, slot):\n\tnode = nodes.TableElement()\n\tnode.table = nodes.Identifier()\n\tnode.table.type = nodes.Identifier.T_BUILTIN\n\tnode.table.name = \"_env\"\n\n\tnode.key = _build_string_constant(state, slot)\n\n\treturn node\n\n\ndef _build_string_constant(state, index):\n\tnode = nodes.Constant()\n\tnode.type = nodes.Constant.T_STRING\n\tnode.value = state.constants.complex_constants[index]\n\n\treturn node\n\n\ndef _build_cdata_constant(state, index):\n\tnode = nodes.Constant()\n\tnode.type = nodes.Constant.T_CDATA\n\tnode.value = state.constants.complex_constants[index]\n\n\treturn node\n\n\ndef _build_numeric_constant(state, index):\n\tnumber = state.constants.numeric_constants[index]\n\n\tnode = nodes.Constant()\n\tnode.value = number\n\n\tif isinstance(number, int):\n\t\tnode.type = nodes.Constant.T_INTEGER\n\telse:\n\t\tnode.type = nodes.Constant.T_FLOAT\n\n\treturn node\n\n\ndef _build_primitive(state, value):\n\tnode = nodes.Primitive()\n\n\tif value is True or value == T_TRUE:\n\t\tnode.type = nodes.Primitive.T_TRUE\n\telif value is False or value == T_FALSE:\n\t\tnode.type = nodes.Primitive.T_FALSE\n\telse:\n\t\tassert value is None or value == T_NIL\n\n\t\tnode.type = nodes.Primitive.T_NIL\n\n\treturn node\n\n\ndef _build_literal(state, value):\n\tnode = nodes.Constant()\n\tnode.value = value\n\tnode.type = nodes.Constant.T_INTEGER\n\n\treturn node\n"
  },
  {
    "path": "ljd/ast/helpers.py",
    "content": "import ljd.ast.nodes as nodes\nimport ljd.ast.traverse as traverse\n\n\ndef insert_table_record(constructor, key, value):\n\tarray = constructor.array.contents\n\trecords = constructor.records.contents\n\n\tif isinstance(key, nodes.MULTRES):\n\t\tassert len(records) == 0 \\\n\t\t\tor isinstance(records[-1], nodes.TableRecord)\n\n\t\trecords.append(value)\n\t\treturn\n\n\twhile isinstance(key, nodes.Constant)\t\t\t\\\n\t\t\t\tand key.type == key.T_INTEGER\t\\\n\t\t\t\tand key.value >= 0:\n\t\tindex = key.value\n\n\t\tif index == 1 and len(array) == 0:\n\t\t\trecord = nodes.ArrayRecord()\n\t\t\trecord.value = nodes.Primitive()\n\t\t\trecord.value.type = nodes.Primitive.T_NIL\n\n\t\t\tarray.append(record)\n\n\t\tif (index > len(array)):\n\t\t\tbreak\n\n\t\trecord = nodes.ArrayRecord()\n\t\trecord.value = value\n\n\t\tif len(array) == 0 or index == len(array):\n\t\t\tarray.append(record)\n\t\telse:\n\t\t\tarray[index] = record\n\n\t\treturn\n\n\trecord = nodes.TableRecord()\n\trecord.key = key\n\trecord.value = value\n\n\tif len(records) == 0:\n\t\trecords.append(record)\n\t\treturn\n\n\tlast = records[-1]\n\n\tif isinstance(last, (nodes.FunctionCall, nodes.Vararg)):\n\t\trecords.insert(-1, record)\n\telse:\n\t\trecords.append(record)\n\n\ndef has_same_table(node, table):\n\tclass Checker(traverse.Visitor):\n\t\tdef __init__(self, table):\n\t\t\tself.found = False\n\t\t\tself.table = table\n\n\t\tdef visit_table_element(self, node):\n\t\t\tif is_equal(self.table, node):\n\t\t\t\tself.found = True\n\n\t\tdef _visit(self, node):\n\t\t\tif not self.found:\n\t\t\t\ttraverse.Visitor._visit(self, node)\n\n\t\tdef _visit_list(self, nodes_list):\n\t\t\tif not self.found:\n\t\t\t\ttraverse.Visitor._visit_list(self, nodes_list)\n\n\tchecker = Checker(table)\n\ttraverse.traverse(checker, node)\n\n\treturn checker.found\n\n\ndef is_equal(a, b):\n\tif type(a) != type(b):\n\t\treturn False\n\n\tif isinstance(a, nodes.Identifier):\n\t\treturn a.type == b.type and a.slot == b.slot\n\telif isinstance(a, nodes.TableElement):\n\t\treturn is_equal(a.table, b.table)\t\t\\\n\t\t\tand is_equal(a.key, b.key)\n\telse:\n\t\tassert isinstance(a, nodes.Constant)\n\t\treturn a.type == b.type and a.value == b.value\n"
  },
  {
    "path": "ljd/ast/locals.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n\nimport ljd.ast.nodes as nodes\nimport ljd.ast.traverse as traverse\n\n\ndef mark_locals(ast):\n\ttraverse.traverse(_LocalsMarker(), ast)\n\n\ndef mark_local_definitions(ast):\n\ttraverse.traverse(_LocalDefinitionsMarker(), ast)\n\n\nclass _LocalsMarker(traverse.Visitor):\n\tclass _State():\n\t\tdef __init__(self):\n\t\t\tself.pending_slots = {}\n\t\t\tself.debuginfo = None\n\t\t\tself.addr = -1\n\n\tdef __init__(self):\n\t\tself._states = []\n\n\t# ##\n\n\tdef _push_state(self):\n\t\tself._states.append(_LocalsMarker._State())\n\n\tdef _pop_state(self):\n\t\tself._states.pop()\n\n\tdef _state(self):\n\t\treturn self._states[-1]\n\n\tdef _process_slots(self, addr):\n\t\tdebuginfo = self._state().debuginfo\n\n\t\tcleanup = []\n\n\t\tfor slot, nodes in self._state().pending_slots.items():\n\t\t\tvarinfo = debuginfo.lookup_local_name(addr, slot)\n\n\t\t\tif varinfo is None:\n\t\t\t\tcontinue\n\n\t\t\tcleanup.append(slot)\n\n\t\t\tif varinfo.type == varinfo.T_INTERNAL:\n\t\t\t\tcontinue\n\n\t\t\tfor node in nodes:\n\t\t\t\tnode.name = varinfo.name\n\t\t\t\tnode.type = node.T_LOCAL\n\n                #zzw.20180712\n\t\t\t\tsetattr(node, \"_varinfo\", varinfo)\n\n\t\tfor slot in cleanup:\n\t\t\tdel self._state().pending_slots[slot]\n\n\tdef _reset_slot(self, slot):\n\t\tself._state().pending_slots.pop(slot, None)\n\n\tdef _reset_all(self, slots):\n\t\tfor slot in slots:\n\t\t\tif isinstance(slot, nodes.Identifier):\n\t\t\t\tself._reset_slot(slot.slot)\n\n\t# ##\n\n\tdef visit_function_definition(self, node):\n\t\tself._push_state()\n\t\tself._state().debuginfo = node._debuginfo\n\n\tdef leave_function_definition(self, node):\n\t\taddr = node._instructions_count\n\t\tself._process_slots(addr)\n\n\t\tself._pop_state()\n\n\t# ##\n\n\tdef visit_variables_list(self, node):\n\t\t# Last chance for a local = local + 1 type assignments\n\t\tself._process_slots(self._state().addr)\n\t\tself._reset_all(node.contents)\n\n\tdef visit_identifiers_list(self, node):\n\t\tself._reset_all(node.contents)\n\n\tdef visit_numeric_loop_warp(self, node):\n\t\tself._reset_slot(node.index.slot)\n\n\tdef visit_identifier(self, node):\n\t\tif node.type == nodes.Identifier.T_SLOT:\n\t\t\tqueue = self._state().pending_slots\n\t\t\tslots = queue.setdefault(node.slot, [])\n\n\t\t\tslots.append(node)\n\n\t# ##\n\n\tdef _process_worthy_node(self, node):\n\t\taddr = getattr(node, \"_addr\", None)\n\n\t\tif not isinstance(node, nodes.Identifier) and addr is not None:\n\t\t\tassert self._state().addr <= addr\n\t\t\tself._state().addr = addr\n\t\t\tself._process_slots(addr)\n\n\t# We need to process slots twice as it could be the last\n\t# statement in the function/block and it could be anassignment\n\t# as well so we need to process slots before the reset\n\n\tdef _leave_node(self, handler, node):\n\t\ttraverse.Visitor._leave_node(self, handler, node)\n\n\t\tself._process_worthy_node(node)\n\n\tdef _visit_node(self, handler, node):\n\t\tself._process_worthy_node(node)\n\n\t\ttraverse.Visitor._visit_node(self, handler, node)\n\n\nclass _LocalDefinitionsMarker(traverse.Visitor):\n\tclass _State():\n\t\tdef __init__(self):\n\t\t\tself.known_locals = [None] * 255\n\t\t\tself.addr = 0\n\n\tdef __init__(self):\n\t\tself._states = []\n\n\tdef _push_state(self):\n\t\tself._states.append(_LocalDefinitionsMarker._State())\n\n\tdef _pop_state(self):\n\t\tself._states.pop()\n\n\tdef _state(self):\n\t\treturn self._states[-1]\n\n\tdef _update_known_locals(self, local, addr):\n\t\tvarinfo = self._state().known_locals[local.slot]\n\t\t#zzw 20180712\n\t\tself._state().known_locals[local.slot] = getattr(local, \"_varinfo\", None)#local._varinfo\n\n\t\tif varinfo is None:\n\t\t\treturn False\n\n\t\tif varinfo.end_addr <= addr:\n\t\t\treturn False\n\n\t\treturn True\n\n\t# ##\n\n\tdef visit_function_definition(self, node):\n\t\tself._push_state()\n\n\t\tfor local in node.arguments.contents:\n\t\t\tif not isinstance(local, nodes.Vararg):\n\t\t\t\tself._update_known_locals(local, 1)\n\n\tdef leave_function_definition(self, node):\n\t\tself._pop_state()\n\n\tdef visit_iterator_for(self, node):\n\t\taddr = node._addr\n\n\t\tfor local in node.identifiers.contents:\n\t\t\tif local.type == nodes.Identifier.T_LOCAL:\n\t\t\t\tself._update_known_locals(local, addr)\n\n\tdef visit_numeric_for(self, node):\n\t\taddr = node._addr\n\n\t\tif node.variable.type == nodes.Identifier.T_LOCAL:\n\t\t\tself._update_known_locals(node.variable, addr)\n\n\t# ##\n\n\tdef visit_assignment(self, node):\n\t\tdst = node.destinations.contents[0]\n\t\taddr = self._state().addr\n\n\t\tif not isinstance(dst, nodes.Identifier):\n\t\t\treturn\n\n\t\tif dst.type != nodes.Identifier.T_LOCAL:\n\t\t\treturn\n\n\t\tknown_slot = self._update_known_locals(dst, addr)\n\n\t\tfor slot in node.destinations.contents[1:]:\n\t\t\tif not isinstance(slot, nodes.Identifier):\n\t\t\t\treturn\n\n\t\t\tif slot.type != nodes.Identifier.T_LOCAL:\n\t\t\t\treturn\n\n\t\t\talso_known = self._update_known_locals(slot, addr)\n\n\t\t\tassert known_slot == also_known\n\n\t\tif not known_slot:\n\t\t\tnode.type = nodes.Assignment.T_LOCAL_DEFINITION\n\n\tdef _visit(self, node):\n\t\tnode_addr = getattr(node, \"_addr\", -1)\n\n\t\tif node_addr >= 0:\n\t\t\tself._state().addr = node_addr\n\n\t\ttraverse.Visitor._visit(self, node)\n"
  },
  {
    "path": "ljd/ast/mutator.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport copy\n\nfrom ljd.ast.helpers import *\n\n\nclass SimpleLoopWarpSwapper(traverse.Visitor):\n\tdef visit_statements_list(self, node):\n\t\tblocks = node.contents\n\n\t\tfixed = []\n\t\tindex_shift = 0\n\n\t\tfor i, block in enumerate(node.contents):\n\t\t\twarp = block.warp\n\t\t\tfixed.append(block)\n\n\t\t\tblock.index += index_shift\n\n\t\t\tif isinstance(warp, nodes.IteratorWarp):\n\t\t\t\tself._swap_iterator_warps(blocks, block)\n\t\t\t\tcontinue\n\n\t\t\tif isinstance(warp, nodes.NumericLoopWarp):\n\t\t\t\tself._swap_numeric_loop_warps(blocks, block)\n\t\t\t\tcontinue\n\n\t\t\tif isinstance(warp, nodes.UnconditionalWarp)\t\\\n\t\t\t\t\t\t\tand warp.is_uclo:\n\t\t\t\tassert block != node.contents[-1]\n\t\t\t\tnext_block = node.contents[i + 1]\n\t\t\t\tself._fix_uclo_return(block, next_block)\n\n\t\t\tif not isinstance(warp, nodes.ConditionalWarp):\n\t\t\t\tcontinue\n\n\t\t\tif warp.true_target != warp.false_target:\n\t\t\t\tcontinue\n\n\t\t\tslot = getattr(warp, \"_slot\", -1)\n\n\t\t\tif slot < 0:\n\t\t\t\tcontinue\n\n\t\t\tnext_index = block.index - index_shift + 1\n\t\t\tassert block.warp.false_target.index == next_index\n\n\t\t\tnew_block = self._create_dummy_block(block, slot)\n\n\t\t\tfixed.append(new_block)\n\n\t\t\tindex_shift += 1\n\n\t\tnode.contents = fixed\n\n\tdef _create_dummy_block(self, block, slot):\n\t\tnew_block = nodes.Block()\n\t\tnew_block.first_address = block.last_address\n\t\tnew_block.last_address = new_block.first_address\n\t\tnew_block.index = block.index + 1\n\t\tnew_block.warpins_count = 1\n\n\t\tnew_block.warp = nodes.UnconditionalWarp()\n\t\tnew_block.warp.type = nodes.UnconditionalWarp.T_FLOW\n\t\tnew_block.warp.target = block.warp.false_target\n\n\t\tstatement = nodes.Assignment()\n\n\t\tidentifier = nodes.Identifier()\n\t\tidentifier.type = nodes.Identifier.T_SLOT\n\t\tidentifier.slot = slot\n\n\t\tstatement.destinations.contents.append(identifier)\n\t\tstatement.expressions.contents.append(copy.copy(identifier))\n\n\t\tnew_block.contents.append(statement)\n\n\t\tblock.warp.true_target = new_block\n\n\t\treturn new_block\n\n\tdef _fix_uclo_return(self, block, next_block):\n\t\twarp = block.warp\n\t\ttarget = warp.target\n\n\t\tif len(target.contents) != 1:\n\t\t\treturn\n\n\t\tstatement = target.contents[0]\n\n\t\tif not isinstance(statement, nodes.Return):\n\t\t\treturn\n\n\t\tblock.contents.append(statement)\n\t\tstatement._addr = block.last_address\n\t\ttarget.contents = []\n\n\t\twarp.type = nodes.UnconditionalWarp.T_FLOW\n\t\twarp.target = next_block\n\n\tdef _swap_iterator_warps(self, blocks, end):\n\t\twarp = end.warp\n\t\tindex = blocks.index(warp.body)\n\n\t\tassert index > 0\n\n\t\tstart = blocks[index - 1]\n\n\t\tassert isinstance(start.warp, nodes.UnconditionalWarp)\n\t\tassert start.warp.type == nodes.UnconditionalWarp.T_JUMP\n\t\tassert start.warp.target == end\n\n\t\tend_addr = end.warp._addr\n\t\tstart_addr = start.warp._addr\n\n\t\tnew_end_warp = start.warp\n\t\tnew_end_warp._addr = end_addr\n\n\t\tnew_start_warp = end.warp\n\t\tnew_start_warp._addr = start_addr\n\n\t\tend.warp = new_end_warp\n\t\tstart.warp = new_start_warp\n\n\t\tnew_end_warp.target = start\n\n\tdef _swap_numeric_loop_warps(self, blocks, end):\n\t\twarp = end.warp\n\t\tindex = blocks.index(warp.body)\n\n\t\tassert index > 0\n\n\t\tstart = blocks[index - 1]\n\n\t\tassert isinstance(start.warp, nodes.UnconditionalWarp)\n\t\tassert start.warp.type == nodes.UnconditionalWarp.T_FLOW\n\t\tassert start.warp.target == warp.body\n\n\t\tend_addr = end.warp._addr\n\t\tstart_addr = start.warp._addr\n\n\t\tnew_end_warp = start.warp\n\t\tnew_end_warp._addr = end_addr\n\n\t\tnew_start_warp = end.warp\n\t\tnew_start_warp._addr = start_addr\n\n\t\tend.warp = new_end_warp\n\t\tstart.warp = new_start_warp\n\n\t\tnew_end_warp.type = nodes.UnconditionalWarp.T_JUMP\n\t\tnew_end_warp.target = start\n\n\nclass MutatorVisitor(traverse.Visitor):\n\t# ##\n\n\tdef leave_if(self, node):\n\t\tif len(node.else_block.contents) != 1:\n\t\t\treturn\n\n\t\tsubif = node.else_block.contents[0]\n\n\t\tif not isinstance(subif, nodes.If):\n\t\t\treturn\n\n\t\telseif = nodes.ElseIf()\n\t\telseif.expression = subif.expression\n\t\telseif.then_block = subif.then_block\n\n\t\tnode.elseifs.append(elseif)\n\t\tnode.elseifs += subif.elseifs\n\t\tnode.else_block = subif.else_block\n\n\tdef visit_statements_list(self, node):\n\t\tpatched = []\n\n\t\ti = -1\n\n\t\twhile i < len(node.contents) - 1:\n\t\t\ti += 1\n\t\t\tstatement = node.contents[i]\n\n\t\t\tpatched.append(statement)\n\n\t\t\tif not isinstance(statement, nodes.Assignment):\n\t\t\t\tcontinue\n\n\t\t\tsrc = statement.expressions.contents[0]\n\n\t\t\tif not isinstance(src, nodes.TableConstructor):\n\t\t\t\tcontinue\n\n\t\t\tassert len(statement.destinations.contents) == 1\n\n\t\t\tdst = statement.destinations.contents[0]\n\n\t\t\ti += self._fill_constructor(dst, src, node.contents[i + 1:])\n\n\t\tnode.contents = patched\n\n\tdef _fill_constructor(self, table, constructor, statements):\n\t\tconsumed = 0\n\n\t\tfor statement in statements:\n\t\t\tif not isinstance(statement, nodes.Assignment):\n\t\t\t\tbreak\n\n\t\t\tif len(statement.destinations.contents) > 1:\n\t\t\t\tbreak\n\n\t\t\tdst = statement.destinations.contents[0]\n\n\t\t\tif not isinstance(dst, nodes.TableElement):\n\t\t\t\tbreak\n\n\t\t\tif not is_equal(dst.table, table):\n\t\t\t\tbreak\n\n\t\t\tassert len(statement.expressions.contents) == 1\n\n\t\t\tsrc = statement.expressions.contents[0]\n\n\t\t\tif has_same_table(src, table):\n\t\t\t\tbreak\n\n\t\t\tinsert_table_record(constructor, dst.key, src)\n\t\t\tconsumed += 1\n\n\t\treturn consumed\n\n\ndef pre_pass(ast):\n\ttraverse.traverse(SimpleLoopWarpSwapper(), ast)\n\n\treturn ast\n\n\ndef primary_pass(ast):\n\ttraverse.traverse(MutatorVisitor(), ast)\n\n\treturn ast\n"
  },
  {
    "path": "ljd/ast/nodes.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n\n# We should visit stuff in it's execution order. That's important\n\n\nclass FunctionDefinition():\n\tdef __init__(self):\n\t\tself.arguments = IdentifiersList()\n\t\tself.statements = StatementsList()\n\n\t\tself._upvalues = None\n\t\tself._debuginfo = None\n\t\tself._instructions_count = 0\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_function_definition, self)\n\n\t\tvisitor._visit(self.arguments)\n\t\tvisitor._visit(self.statements)\n\n\t\tvisitor._leave_node(visitor.leave_function_definition, self)\n\n\nclass TableConstructor():\n\tdef __init__(self):\n\t\tself.array = RecordsList()\n\t\tself.records = RecordsList()\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_table_constructor, self)\n\n\t\tvisitor._visit(self.array)\n\t\tvisitor._visit(self.records)\n\n\t\tvisitor._leave_node(visitor.leave_table_constructor, self)\n\n\nclass ArrayRecord():\n\tdef __init__(self):\n\t\tself.value = None\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_array_record, self)\n\n\t\tvisitor._visit(self.value)\n\n\t\tvisitor._leave_node(visitor.leave_array_record, self)\n\n\nclass TableRecord():\n\tdef __init__(self):\n\t\tself.key = None\n\t\tself.value = None\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_table_record, self)\n\n\t\tvisitor._visit(self.key)\n\t\tvisitor._visit(self.value)\n\n\t\tvisitor._leave_node(visitor.leave_table_record, self)\n\n\nclass Assignment():\n\tT_LOCAL_DEFINITION = 0\n\tT_NORMAL = 1\n\n\tdef __init__(self):\n\t\tself.expressions = ExpressionsList()\n\t\tself.destinations = VariablesList()\n\t\tself.type = -1\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_assignment, self)\n\n\t\tvisitor._visit(self.expressions)\n\t\tvisitor._visit(self.destinations)\n\n\t\tvisitor._leave_node(visitor.leave_assignment, self)\n\n\nclass BinaryOperator():\n\tT_LOGICAL_OR = 0  # left or right\n\tT_LOGICAL_AND = 10  # left and right\n\n\tT_LESS_THEN = 20  # left < right\n\tT_GREATER_THEN = 21  # left > right\n\tT_LESS_OR_EQUAL = 22  # left <= right\n\tT_GREATER_OR_EQUAL = 23  # left >= right\n\n\tT_NOT_EQUAL = 24  # left ~= right\n\tT_EQUAL = 25  # left == right\n\n\tT_CONCAT = 30  # left .. right\n\n\tT_ADD = 40  # left + right\n\tT_SUBTRACT = 41  # left - right\n\n\tT_MULTIPLY = 50  # left * right\n\tT_DIVISION = 51  # left / right\n\tT_MOD = 52  # left % right\n\n\tT_POW = 70  # left ^ right\n\n\tdef __init__(self):\n\t\tself.type = -1\n\t\tself.left = None\n\t\tself.right = None\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_binary_operator, self)\n\n\t\tvisitor._visit(self.left)\n\t\tvisitor._visit(self.right)\n\n\t\tvisitor._leave_node(visitor.leave_binary_operator, self)\n\n\nclass UnaryOperator():\n\tT_NOT = 60  # not operand\n\tT_LENGTH_OPERATOR = 61  # #operand\n\tT_MINUS = 62  # -operand\n\n\tdef __init__(self):\n\t\tself.type = -1\n\t\tself.operand = None\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_unary_operator, self)\n\n\t\tvisitor._visit(self.operand)\n\n\t\tvisitor._leave_node(visitor.leave_unary_operator, self)\n\n\nclass StatementsList():\n\tdef __init__(self):\n\t\tself.contents = []\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_statements_list, self)\n\n\t\tvisitor._visit_list(self.contents)\n\n\t\tvisitor._leave_node(visitor.leave_statements_list, self)\n\n\nclass IdentifiersList():\n\tdef __init__(self):\n\t\tself.contents = []\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_identifiers_list, self)\n\n\t\tvisitor._visit_list(self.contents)\n\n\t\tvisitor._leave_node(visitor.leave_identifiers_list, self)\n\n\nclass RecordsList():\n\tdef __init__(self):\n\t\tself.contents = []\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_records_list, self)\n\n\t\tvisitor._visit_list(self.contents)\n\n\t\tvisitor._leave_node(visitor.leave_records_list, self)\n\n\nclass VariablesList():\n\tdef __init__(self):\n\t\tself.contents = []\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_variables_list, self)\n\n\t\tvisitor._visit_list(self.contents)\n\n\t\tvisitor._leave_node(visitor.leave_variables_list, self)\n\n\nclass ExpressionsList():\n\tdef __init__(self):\n\t\tself.contents = []\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_expressions_list, self)\n\n\t\tvisitor._visit_list(self.contents)\n\n\t\tvisitor._leave_node(visitor.leave_expressions_list, self)\n\n\n# Called Name in the Lua 5.1 reference\nclass Identifier():\n\tT_SLOT = 0\n\tT_LOCAL = 1\n\tT_UPVALUE = 2\n\tT_BUILTIN = 3\n\n\tdef __init__(self):\n\t\tself.name = None\n\t\tself.type = -1\n\t\tself.slot = -1\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_identifier, self)\n\t\tvisitor._leave_node(visitor.leave_identifier, self)\n\n\n# helper vararg/varreturn\n\nclass MULTRES():\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_multres, self)\n\t\tvisitor._leave_node(visitor.leave_multres, self)\n\n\nclass TableElement():\n\tdef __init__(self):\n\t\tself.table = None\n\t\tself.key = None\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_table_element, self)\n\n\t\tvisitor._visit(self.key)\n\t\tvisitor._visit(self.table)\n\n\t\tvisitor._leave_node(visitor.leave_table_element, self)\n\n\nclass Vararg():\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_vararg, self)\n\t\tvisitor._leave_node(visitor.leave_vararg, self)\n\n\nclass FunctionCall():\n\tdef __init__(self):\n\t\tself.function = None\n\t\tself.arguments = ExpressionsList()\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_function_call, self)\n\n\t\tvisitor._visit(self.arguments)\n\t\tvisitor._visit(self.function)\n\n\t\tvisitor._leave_node(visitor.leave_function_call, self)\n\n\nclass If():\n\tdef __init__(self):\n\t\tself.expression = None\n\t\tself.then_block = StatementsList()\n\t\tself.elseifs = []\n\t\tself.else_block = StatementsList()\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_if, self)\n\n\t\tvisitor._visit(self.expression)\n\t\tvisitor._visit(self.then_block)\n\n\t\tvisitor._visit_list(self.elseifs)\n\n\t\tvisitor._visit(self.else_block)\n\n\t\tvisitor._leave_node(visitor.leave_if, self)\n\n\nclass ElseIf():\n\tdef __init__(self):\n\t\tself.expression = None\n\t\tself.then_block = StatementsList()\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_elseif, self)\n\n\t\tvisitor._visit(self.expression)\n\t\tvisitor._visit(self.then_block)\n\n\t\tvisitor._leave_node(visitor.leave_elseif, self)\n\n# ##\n\n\nclass Block():\n\tdef __init__(self):\n\t\tself.index = -1\n\t\tself.warp = None\n\t\tself.contents = []\n\t\tself.first_address = 0\n\t\tself.last_address = 0\n\t\tself.warpins_count = 0\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_block, self)\n\n\t\tvisitor._visit_list(self.contents)\n\t\tvisitor._visit(self.warp)\n\n\t\tvisitor._leave_node(visitor.leave_block, self)\n\n\nclass UnconditionalWarp():\n\tT_JUMP = 0\n\tT_FLOW = 1\n\n\tdef __init__(self):\n\t\tself.type = -1\n\t\tself.target = None\n\t\tself.is_uclo = False\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_unconditional_warp, self)\n\n\t\t# DO NOT VISIT self.target - warps are not part of the tree\n\n\t\tvisitor._leave_node(visitor.leave_unconditional_warp, self)\n\n\nclass ConditionalWarp():\n\tdef __init__(self):\n\t\tself.condition = None\n\t\tself.true_target = None\n\t\tself.false_target = None\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_conditional_warp, self)\n\n\t\tvisitor._visit(self.condition)\n\t\t# DO NOT VISIT self.true_target - warps are not part of the tree\n\t\t# DO NOT VISIT self.false_target - warps are not part of the tree\n\n\t\tvisitor._leave_node(visitor.leave_conditional_warp, self)\n\n\nclass IteratorWarp():\n\tdef __init__(self):\n\t\tself.variables = VariablesList()\n\t\tself.controls = ExpressionsList()\n\t\tself.body = None\n\t\tself.way_out = None\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_iterator_warp, self)\n\n\t\tvisitor._visit(self.variables)\n\t\tvisitor._visit(self.controls)\n\t\t# DO NOT VISIT self.body - warps are not part of the tree\n\t\t# DO NOT VISIT self.way_out - warps are not part of the tree\n\n\t\tvisitor._leave_node(visitor.leave_iterator_warp, self)\n\n\nclass NumericLoopWarp():\n\tdef __init__(self):\n\t\tself.index = Identifier()\n\t\tself.controls = ExpressionsList()\n\t\tself.body = None\n\t\tself.way_out = None\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_numeric_loop_warp, self)\n\n\t\tvisitor._visit(self.index)\n\t\tvisitor._visit(self.controls)\n\t\t# DO NOT VISIT self.body - warps are not part of the tree\n\t\t# DO NOT VISIT self.way_out - warps are not part of the tree\n\n\t\tvisitor._leave_node(visitor.leave_numeric_loop_warp, self)\n\n\nclass EndWarp():\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_end_warp, self)\n\t\tvisitor._leave_node(visitor.leave_end_warp, self)\n\n\n# ##\n\n\nclass Return():\n\tdef __init__(self):\n\t\tself.returns = ExpressionsList()\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_return, self)\n\n\t\tvisitor._visit(self.returns)\n\n\t\tvisitor._leave_node(visitor.leave_return, self)\n\n\nclass Break():\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_break, self)\n\t\tvisitor._leave_node(visitor.leave_break, self)\n\n\nclass While():\n\tdef __init__(self):\n\t\tself.expression = None\n\t\tself.statements = StatementsList()\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_while, self)\n\n\t\tvisitor._visit(self.expression)\n\t\tvisitor._visit(self.statements)\n\n\t\tvisitor._leave_node(visitor.leave_while, self)\n\n\nclass RepeatUntil():\n\tdef __init__(self):\n\t\tself.expression = None\n\t\tself.statements = StatementsList()\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_repeat_until, self)\n\n\t\tvisitor._visit(self.statements)\n\t\tvisitor._visit(self.expression)\n\n\t\tvisitor._leave_node(visitor.leave_repeat_until, self)\n\n\nclass NumericFor():\n\tdef __init__(self):\n\t\tself.variable = None\n\t\tself.expressions = ExpressionsList()\n\t\tself.statements = StatementsList()\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_numeric_for, self)\n\n\t\tvisitor._visit(self.variable)\n\t\tvisitor._visit(self.expressions)\n\t\tvisitor._visit(self.statements)\n\n\t\tvisitor._leave_node(visitor.leave_numeric_for, self)\n\n\nclass IteratorFor():\n\tdef __init__(self):\n\t\tself.expressions = ExpressionsList()\n\t\tself.identifiers = VariablesList()\n\t\tself.statements = StatementsList()\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_iterator_for, self)\n\n\t\tvisitor._visit(self.expressions)\n\t\tvisitor._visit(self.identifiers)\n\t\tvisitor._visit(self.statements)\n\n\t\tvisitor._leave_node(visitor.leave_iterator_for, self)\n\n\nclass Constant():\n\tT_INTEGER = 0\n\tT_FLOAT = 1\n\tT_STRING = 2\n\tT_CDATA = 3\n\n\tdef __init__(self):\n\t\tself.type = -1\n\t\tself.value = None\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_constant, self)\n\t\tvisitor._leave_node(visitor.leave_constant, self)\n\n\nclass Primitive():\n\tT_NIL = 0\n\tT_TRUE = 1\n\tT_FALSE = 2\n\n\tdef __init__(self):\n\t\tself.type = -1\n\n\tdef _accept(self, visitor):\n\t\tvisitor._visit_node(visitor.visit_primitive, self)\n\t\tvisitor._leave_node(visitor.leave_primitive, self)\n"
  },
  {
    "path": "ljd/ast/slotworks.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport ljd.ast.nodes as nodes\nimport ljd.ast.traverse as traverse\nfrom ljd.ast.helpers import insert_table_record\n\n\ndef eliminate_temporary(ast):\n\t_eliminate_multres(ast)\n\n\tslots, unused = _collect_slots(ast)\n\t_eliminate_temporary(slots)\n\n\t# _remove_unused(unused)\n\n\t_cleanup_invalid_nodes(ast)\n\n\treturn ast\n\n\ndef _eliminate_temporary(slots):\n\tsimple = []\n\tmassive = []\n\ttables = []\n\titerators = []\n\n\tfor info in slots:\n\t\tassignment = info.assignment\n\n\t\tif not isinstance(assignment, nodes.Assignment):\n\t\t\tassert isinstance(assignment, (nodes.IteratorWarp,\n\t\t\t\t\t\t\tnodes.NumericLoopWarp,\n\t\t\t\t\t\t\tnodes.FunctionDefinition))\n\n\t\t\tsrc = info.references[1].identifier\n\t\t\tsimple.append((info.references, src))\n\t\t\tcontinue\n\n\t\tassert len(assignment.expressions.contents) == 1\n\n\t\tis_massive = len(assignment.destinations.contents) > 1\n\n\t\tif is_massive:\n\t\t\t_fill_massive_refs(info, simple, massive, iterators)\n\t\telse:\n\t\t\t_fill_simple_refs(info, simple, tables)\n\n\t_eliminate_simple_cases(simple)\n\t_eliminate_into_table_constructors(tables)\n\t_eliminate_mass_assignments(massive)\n\t_eliminate_iterators(iterators)\n\n\ndef _fill_massive_refs(info, simple, massive, iterators):\n\tref = info.references[1]\n\tholder = _get_holder(ref.path)\n\n\tsrc = info.assignment.expressions.contents[0]\n\n\tassert isinstance(src, (nodes.FunctionCall,\n\t\t\t\tnodes.Vararg,\n\t\t\t\tnodes.Primitive))\n\tif isinstance(holder, nodes.Assignment):\n\t\tdst = holder.destinations.contents[0]\n\n\t\tassert len(info.references) == 2\n\t\torig = info.references[0].identifier\n\n\t\tassignment = ref.path[-3]\n\n\t\tassert isinstance(assignment, nodes.Assignment)\n\n\t\tmassive.append((orig, info.assignment, assignment, dst))\n\telif isinstance(holder, nodes.IteratorWarp):\n\t\tassert len(info.references) == 2\n\t\titerators.append((info.assignment, src, holder))\n\telif isinstance(src, nodes.Primitive) and src.type == src.T_NIL:\n\t\tassert len(info.references) == 2\n\n\t\t# Create a new primitive, so it won't mess with the\n\t\t# writer's ignore list\n\t\tsrc = nodes.Primitive()\n\t\tsrc.type = nodes.Primitive.T_NIL\n\n\t\tsimple.append((info, ref, src))\n\n\ndef _fill_simple_refs(info, simple, tables):\n\tsrc = info.assignment.expressions.contents[0]\n\n\tif isinstance(src, nodes.FunctionCall) and len(info.references) > 3:\n\t\treturn\n\n\tsrc_is_table = isinstance(src, nodes.TableConstructor)\n\n\tfor ref in info.references[1:]:\n\t\tholder = _get_holder(ref.path)\n\n\t\tis_element = isinstance(holder, nodes.TableElement)\n\n\t\tpath_index = ref.path.index(holder)\n\n\t\tstatement = _get_holder(ref.path[:path_index])\n\n\t\tstatement_is_assignment = isinstance(statement, nodes.Assignment)\n\n\t\tif statement_is_assignment:\n\t\t\tis_dst = statement.destinations.contents[0] == holder\n\t\telse:\n\t\t\tis_dst = False\n\n\t\t# Could be more then one reference here\n\t\tif src_is_table and is_element and is_dst:\n\t\t\tassert holder.table == ref.identifier\n\t\t\ttables.append((info, ref))\n\t\telse:\n\t\t\tsimple.append((info, ref, None))\n\n\nLIST_TYPES = (nodes.VariablesList,\n\t\tnodes.IdentifiersList,\n\t\tnodes.ExpressionsList,\n\t\tnodes.StatementsList)\n\n\ndef _get_holder(path):\n\tfor node in reversed(path[:-1]):\n\t\tif not isinstance(node, LIST_TYPES):\n\t\t\treturn node\n\n\treturn None\n\n\ndef _eliminate_simple_cases(simple):\n\tfor info, ref, src in simple:\n\t\tholder = ref.path[-2]\n\t\tdst = ref.identifier\n\n\t\tif src is None:\n\t\t\tsrc = info.assignment.expressions.contents[0]\n\n\t\t_mark_invalidated(info.assignment)\n\n\t\tif isinstance(holder, LIST_TYPES):\n\t\t\tnodes = holder.contents\n\t\t\tfound = _replace_node_in_list(nodes, dst, src)\n\t\telse:\n\t\t\tfound = _replace_node(holder, dst, src)\n\n\t\tif found == None:\n\t\t\tprint(\"err: slotworks.py assert found\")\n\n\ndef _eliminate_into_table_constructors(tables):\n\tfor info, ref in tables:\n\t\tconstructor = info.assignment.expressions.contents[0]\n\t\ttable_element = ref.path[-2]\n\t\tassignment = ref.path[-4]\n\n\t\tassert isinstance(assignment, nodes.Assignment)\n\n\t\tassert len(assignment.expressions.contents) == 1\n\n\t\t_mark_invalidated(assignment)\n\n\t\tkey = table_element.key\n\t\tvalue = assignment.expressions.contents[0]\n\n\t\tinsert_table_record(constructor, key, value)\n\n\ndef _eliminate_mass_assignments(massive):\n\tfor identifier, assignment, base_assignment, globalvar in massive:\n\t\tdestinations = assignment.destinations.contents\n\t\tfound = _replace_node_in_list(destinations, identifier, globalvar)\n\n\t\t_mark_invalidated(base_assignment)\n\n\t\tassert found\n\n\ndef _replace_node(holder, original, replacement):\n\tfor key, value in holder.__dict__.items():\n\t\tif value == original:\n\t\t\tsetattr(holder, key, replacement)\n\t\t\treturn True\n\n\treturn False\n\n\ndef _replace_node_in_list(nodes, original, replacement):\n\ttry:\n\t\tindex = nodes.index(original)\n\texcept ValueError:\n\t\treturn False\n\n\tnodes[index] = replacement\n\treturn True\n\n\ndef _eliminate_iterators(iterators):\n\tprocessed_warps = set()\n\n\tfor assignment, src, warp in iterators:\n\t\tif warp in processed_warps:\n\t\t\tcontinue\n\n\t\tfor i, slot in enumerate(assignment.destinations.contents):\n\t\t\tif hasattr(warp.controls.contents[i], 'slot') and hasattr(slot, 'slot'):\n\t\t\t\t#assert warp.controls.contents[i].slot == slot.slot\n\t\t\t\tif warp.controls.contents[i].slot != slot.slot:\n\t\t\t\t\tprint (\"err: slotworks.py assert warp.controls.contents[i].slot == slot.slot\")\n\n\t\twarp.controls.contents = [src]\n\t\tprocessed_warps.add(warp)\n\n\t\t_mark_invalidated(assignment)\n\n\ndef _mark_invalidated(node):\n\tsetattr(node, \"_invalidated\", True)\n\n\ndef _is_invalidated(node):\n\treturn getattr(node, \"_invalidated\", False)\n\n\ndef _remove_unused(unused):\n\tpass\n\n\ndef _collect_slots(ast):\n\tcollector = _SlotsCollector()\n\ttraverse.traverse(collector, ast)\n\n\treturn collector.slots, collector.unused\n\n\ndef _eliminate_multres(ast):\n\ttraverse.traverse(_MultresEliminator(), ast)\n\t_cleanup_invalid_nodes(ast)\n\n\nclass _MultresEliminator(traverse.Visitor):\n\tdef __init__(self):\n\t\tself._last_multres_value = None\n\n\tdef leave_assignment(self, node):\n\t\tsrc = node.expressions.contents[0]\n\t\tdst = node.destinations.contents[0]\n\n\t\tif isinstance(dst, nodes.MULTRES):\n\t\t\tassert len(node.destinations.contents) == 1\n\t\t\tassert len(node.expressions.contents) == 1\n\n\t\t\tassert isinstance(src, (nodes.FunctionCall, nodes.Vararg))\n\n\t\t\tassert self._last_multres_value is None\n\n\t\t\tself._last_multres_value = src\n\n\t\t\t_mark_invalidated(node)\n\t\telse:\n\t\t\tfor i, src in enumerate(node.expressions.contents):\n\t\t\t\tif isinstance(src, nodes.MULTRES):\n\t\t\t\t\tbreak\n\t\t\telse:\n\t\t\t\treturn\n\n\t\t\tassert self._last_multres_value is not None\n\n\t\t\tnode.expressions.contents[i] = self._last_multres_value\n\t\t\tself._last_multres_value = None\n\n\tdef _process_multres_in_list(self, nodes_list):\n\t\tfor i, node in enumerate(nodes_list):\n\t\t\tif isinstance(node, nodes.MULTRES):\n\t\t\t\tbreak\n\t\telse:\n\t\t\treturn\n\n\t\tassert self._last_multres_value is not None\n\n\t\tnodes_list[i] = self._last_multres_value\n\t\tself._last_multres_value = None\n\n\tdef visit_function_call(self, node):\n\t\tself._process_multres_in_list(node.arguments.contents)\n\n\tdef visit_return(self, node):\n\t\tself._process_multres_in_list(node.returns.contents)\n\n\nclass _SlotReference():\n\tdef __init__(self):\n\t\tself.path = []\n\t\tself.identifier = None\n\n\nclass _SlotInfo():\n\tdef __init__(self):\n\t\tself.slot = 0\n\n\t\tself.assignment = None\n\t\tself.references = []\n\t\tself.termination = None\n\n\t\tself.function = None\n\n\nclass _SlotsCollector(traverse.Visitor):\n\tclass _State():\n\t\tdef __init__(self):\n\t\t\tself.known_slots = {}\n\t\t\tself.function = None\n\n\t# ##\n\n\tdef __init__(self):\n\t\tself._states = []\n\t\tself._path = []\n\t\tself._skip = None\n\n\t\tself.slots = []\n\t\tself.unused = []\n\n\t\tself._push_state()\n\n\t# ##\n\n\tdef _state(self):\n\t\treturn self._states[-1]\n\n\tdef _push_state(self):\n\t\tself._states.append(_SlotsCollector._State())\n\n\tdef _pop_state(self):\n\t\tself._states.pop()\n\n\tdef _commit_info(self, info):\n\t\tassert len(info.references) > 0\n\n\t\tif len(info.references) == 1:\n\t\t\tself.unused.append(info)\n\t\telse:\n\t\t\tself.slots.append(info)\n\n\tdef _commit_slot(self, slot, node):\n\t\tinfo = self._state().known_slots.get(slot)\n\n\t\tif info is None:\n\t\t\treturn\n\n\t\tinfo.termination = node\n\n\t\tdel self._state().known_slots[slot]\n\n\t\tself._commit_info(info)\n\n\tdef _register_slot(self, slot, node):\n\t\tself._commit_slot(slot, node)\n\n\t\tinfo = _SlotInfo()\n\t\tinfo.slot = slot\n\t\tinfo.assignment = node\n\t\tinfo.function = self._state().function\n\n\t\tself._state().known_slots[slot] = info\n\n\tdef _register_all_slots(self, node, slots):\n\t\tfor slot in slots:\n\t\t\tif not isinstance(slot, nodes.Identifier):\n\t\t\t\tcontinue\n\n\t\t\tif slot.type != nodes.Identifier.T_SLOT:\n\t\t\t\tcontinue\n\n\t\t\tself._register_slot(slot.slot, node)\n\n\tdef _commit_all_slots(self, slots, node):\n\t\tfor slot in slots:\n\t\t\tif not isinstance(slot, nodes.Identifier):\n\t\t\t\tcontinue\n\n\t\t\tself._commit_slot(slot.slot, node)\n\n\tdef _register_slot_reference(self, slot, node):\n\t\tinfo = self._state().known_slots.get(slot)\n\n\t\tif info is None:\n\t\t\treturn\n\n\t\treference = _SlotReference()\n\t\treference.identifier = node\n\n\t\t# Copy the list, but not contents\n\t\treference.path = self._path[:]\n\n\t\tinfo.references.append(reference)\n\n\t# ##\n\n\tdef visit_assignment(self, node):\n\t\tself._visit(node.expressions)\n\t\tself._skip = node.expressions\n\n\t\tself._register_all_slots(node, node.destinations.contents)\n\n\tdef leave_assignment(self, node):\n\t\tself._skip = None\n\n\tdef visit_identifier(self, node):\n\t\tif node.type == nodes.Identifier.T_SLOT:\n\t\t\tself._register_slot_reference(node.slot, node)\n\n\t# ##\n\n\tdef visit_function_definition(self, node):\n\t\tself._push_state()\n\t\tself._state().function = node\n\n\tdef leave_function_definition(self, node):\n\t\tself._pop_state()\n\n\tdef leave_block(self, node):\n\t\tfor info in self._state().known_slots.values():\n\t\t\tself._commit_info(info)\n\n\t\tself._state().known_slots = {}\n\n\tdef visit_iterator_warp(self, node):\n\t\tself._commit_all_slots(node.variables.contents, node)\n\n\tdef visit_numeric_loop_warp(self, node):\n\t\tself._commit_slot(node.index.slot, node)\n\n\t# ##\n\n\tdef _visit_node(self, handler, node):\n\t\tself._path.append(node)\n\n\t\ttraverse.Visitor._visit_node(self, handler, node)\n\n\tdef _leave_node(self, handler, node):\n\t\tself._path.pop()\n\n\t\ttraverse.Visitor._leave_node(self, handler, node)\n\n\tdef _visit(self, node):\n\t\tif self._skip == node:\n\t\t\treturn\n\n\t\ttraverse.Visitor._visit(self, node)\n\n\ndef _cleanup_invalid_nodes(ast):\n\ttraverse.traverse(_TreeCleanup(), ast)\n\n\nclass _TreeCleanup(traverse.Visitor):\n\tdef visit_block(self, node):\n\t\tpatched = []\n\n\t\tfor subnode in node.contents:\n\t\t\tif not _is_invalidated(subnode):\n\t\t\t\tpatched.append(subnode)\n\n\t\tnode.contents = patched\n"
  },
  {
    "path": "ljd/ast/traverse.py",
    "content": "class Visitor():\n\tdef __init__(self):\n\t\tpass\n\n\t# ##\n\n\tdef visit_function_definition(self, node):\n\t\tpass\n\n\tdef leave_function_definition(self, node):\n\t\tpass\n\n\t# ##\n\n\tdef visit_table_constructor(self, node):\n\t\tpass\n\n\tdef leave_table_constructor(self, node):\n\t\tpass\n\n\tdef visit_table_record(self, node):\n\t\tpass\n\n\tdef leave_table_record(self, node):\n\t\tpass\n\n\tdef visit_array_record(self, node):\n\t\tpass\n\n\tdef leave_array_record(self, node):\n\t\tpass\n\n\t# ##\n\n\tdef visit_assignment(self, node):\n\t\tpass\n\n\tdef leave_assignment(self, node):\n\t\tpass\n\n\t# ##\n\n\tdef visit_binary_operator(self, node):\n\t\tpass\n\n\tdef leave_binary_operator(self, node):\n\t\tpass\n\n\tdef visit_unary_operator(self, node):\n\t\tpass\n\n\tdef leave_unary_operator(self, node):\n\t\tpass\n\n\t# ##\n\n\tdef visit_statements_list(self, node):\n\t\tpass\n\n\tdef leave_statements_list(self, node):\n\t\tpass\n\n\tdef visit_identifiers_list(self, node):\n\t\tpass\n\n\tdef leave_identifiers_list(self, node):\n\t\tpass\n\n\tdef visit_records_list(self, node):\n\t\tpass\n\n\tdef leave_records_list(self, node):\n\t\tpass\n\n\tdef visit_variables_list(self, node):\n\t\tpass\n\n\tdef leave_variables_list(self, node):\n\t\tpass\n\n\tdef visit_expressions_list(self, node):\n\t\tpass\n\n\tdef leave_expressions_list(self, node):\n\t\tpass\n\n\t# ##\n\n\tdef visit_identifier(self, node):\n\t\tpass\n\n\tdef leave_identifier(self, node):\n\t\tpass\n\n\tdef visit_multres(self, node):\n\t\tpass\n\n\tdef leave_multres(self, node):\n\t\tpass\n\n\tdef visit_table_element(self, node):\n\t\tpass\n\n\tdef leave_table_element(self, node):\n\t\tpass\n\n\tdef visit_vararg(self, node):\n\t\tpass\n\n\tdef leave_vararg(self, node):\n\t\tpass\n\n\tdef visit_function_call(self, node):\n\t\tpass\n\n\tdef leave_function_call(self, node):\n\t\tpass\n\n\t# ##\n\n\tdef visit_if(self, node):\n\t\tpass\n\n\tdef leave_if(self, node):\n\t\tpass\n\n\tdef visit_elseif(self, node):\n\t\tpass\n\n\tdef leave_elseif(self, node):\n\t\tpass\n\n\t# ##\n\n\tdef visit_block(self, node):\n\t\tpass\n\n\tdef leave_block(self, node):\n\t\tpass\n\n\tdef visit_unconditional_warp(self, node):\n\t\tpass\n\n\tdef leave_unconditional_warp(self, node):\n\t\tpass\n\n\tdef visit_conditional_warp(self, node):\n\t\tpass\n\n\tdef leave_conditional_warp(self, node):\n\t\tpass\n\n\tdef visit_iterator_warp(self, node):\n\t\tpass\n\n\tdef leave_iterator_warp(self, node):\n\t\tpass\n\n\tdef visit_numeric_loop_warp(self, node):\n\t\tpass\n\n\tdef leave_numeric_loop_warp(self, node):\n\t\tpass\n\n\tdef visit_end_warp(self, node):\n\t\tpass\n\n\tdef leave_end_warp(self, node):\n\t\tpass\n\n\t# ##\n\n\tdef visit_return(self, node):\n\t\tpass\n\n\tdef leave_return(self, node):\n\t\tpass\n\n\tdef visit_break(self, node):\n\t\tpass\n\n\tdef leave_break(self, node):\n\t\tpass\n\n\t# ##\n\n\tdef visit_while(self, node):\n\t\tpass\n\n\tdef leave_while(self, node):\n\t\tpass\n\n\tdef visit_repeat_until(self, node):\n\t\tpass\n\n\tdef leave_repeat_until(self, node):\n\t\tpass\n\n\tdef visit_numeric_for(self, node):\n\t\tpass\n\n\tdef leave_numeric_for(self, node):\n\t\tpass\n\n\tdef visit_iterator_for(self, node):\n\t\tpass\n\n\tdef leave_iterator_for(self, node):\n\t\tpass\n\n\t# ##\n\n\tdef visit_constant(self, node):\n\t\tpass\n\n\tdef leave_constant(self, node):\n\t\tpass\n\n\tdef visit_primitive(self, node):\n\t\tpass\n\n\tdef leave_primitive(self, node):\n\t\tpass\n\n\t# ##\n\n\tdef _visit_node(self, handler, node):\n\t\thandler(node)\n\n\tdef _leave_node(self, handler, node):\n\t\thandler(node)\n\n\t# ##\n\n\tdef _visit(self, node):\n\t\tassert node is not None\n\n\t\tnode._accept(self)\n\n\tdef _visit_list(self, nodes_list):\n\t\tassert isinstance(nodes_list, list)\n\n\t\tfor node in nodes_list:\n\t\t\tself._visit(node)\n\n\ndef traverse(visitor, node):\n\tif isinstance(node, list):\n\t\tvisitor._visit_list(node)\n\telse:\n\t\tvisitor._visit(node)\n"
  },
  {
    "path": "ljd/ast/unwarper.py",
    "content": "import copy\n\nimport ljd.ast.nodes as nodes\nimport ljd.ast.traverse as traverse\nimport ljd.ast.slotworks as slotworks\n\nbinop = nodes.BinaryOperator\n\n\n# ##\n# ## REMEMBER\n# ##\n# ## Block indices are unreliable while you are mangling them!\n# ##\n# ## P.S. Probably they should not be named indices... But they ARE used as indices during other phases. Sometimes.\n# ## \n# ##\n\n\nclass _StatementsCollector(traverse.Visitor):\n\tdef __init__(self):\n\t\tself.result = []\n\n\tdef visit_statements_list(self, node):\n\t\tif len(node.contents) > 0:\n\t\t\tself.result.append(node)\n\n\ndef unwarp(node):\n\t# There could be many negative jumps within while conditions, so\n\t# filter them first\n\t_run_step(_unwarp_loops, node, repeat_until=False)\n\n\t_run_step(_unwarp_loops, node, repeat_until=True)\n\t_run_step(_unwarp_expressions, node)\n\t_run_step(_unwarp_ifs, node)\n\n\t_glue_flows(node)\n\n\ndef _run_step(step, node, **kargs):\n\tfor statements in _gather_statements_lists(node):\n\t\tstatements.contents = step(statements.contents, **kargs)\n\n\t# Fix block indices in case anything was moved\n\tfor statements in _gather_statements_lists(node):\n\t\tfor i, block in enumerate(statements.contents):\n\t\t\tblock.index = i\n\n\ndef _gather_statements_lists(node):\n\tcollector = _StatementsCollector()\n\ttraverse.traverse(collector, node)\n\treturn collector.result\n\n\ndef _glue_flows(node):\n\tfor statements in _gather_statements_lists(node):\n\t\tblocks = statements.contents\n\n\t\tif hasattr(blocks[-1], 'warp'):\n\t\t\tassert isinstance(blocks[-1].warp, nodes.EndWarp)\n\n\t\t\tfor i, block in enumerate(blocks[:-1]):\n\t\t\t\twarp = block.warp\n\n\t\t\t\tassert _is_flow(warp)\n\n\t\t\t\ttarget = warp.target\n\n\t\t\t\tassert target == blocks[i + 1]\n\n\t\t\t\ttarget.contents = block.contents + target.contents\n\t\t\t\tblock.contents = []\n\n\t\t\tstatements.contents = blocks[-1].contents\n\n\n# ##\n# ## IFs AND EXPRESSIONs PROCESSING\n# ##\n\ndef _unwarp_expressions(blocks):\n\tpack = []\n\tpack_set = set()\n\n\tstart_index = 0\n\twhile start_index < len(blocks) - 1:\n\t\tstart = blocks[start_index]\n\t\twarp = start.warp\n\n\t\tif isinstance(warp, nodes.UnconditionalWarp):\n\t\t\tif warp.type == nodes.UnconditionalWarp.T_FLOW:\n\t\t\t\tstart_index += 1\n\t\t\t\tcontinue\n\n\t\tbody, end, end_index = _extract_if_body(start_index,\n\t\t\t\t\t\t\tblocks, None)\n\n\t\tif body is None:\n\t\t\traise NotImplementedError(\"GOTO statements are not\"\n\t\t\t\t\t\t\t\t\" supported\")\n\n\t\texpressions = _find_expressions(start, body, end)\n\n\t\tassert pack_set.isdisjoint(expressions)\n\n\t\texpressions_set = set(expressions)\n\n\t\tassert len(expressions_set) == len(expressions)\n\n\t\tif len(expressions) == 0:\n\t\t\tstart_index += 1\n\t\t\tcontinue\n\n\t\tpack += list(reversed(expressions))\n\t\tpack_set |= expressions_set\n\n\t\tendest_end = _find_endest_end(expressions)\n\n\t\tif endest_end != end:\n\t\t\tend_index = blocks.index(endest_end)\n\n\t\tstart_index = end_index\n\n\treturn _unwarp_expressions_pack(blocks, pack)\n\n\ndef _find_endest_end(expressions):\n\tendest_end = expressions[0][1]\n\n\tfor _start, exp_end, _slot, _slot_type in expressions[1:]:\n\t\tif exp_end.index > endest_end.index:\n\t\t\tendest_end = exp_end\n\n\treturn endest_end\n\n\ndef _unwarp_ifs(blocks, top_end=None, topmost_end=None):\n\tboundaries = []\n\n\tstart_index = 0\n\n\twhile start_index < len(blocks) - 1:\n\t\tstart = blocks[start_index]\n\t\twarp = start.warp\n\n\t\tif isinstance(warp, nodes.UnconditionalWarp):\n\t\t\tif warp.type == nodes.UnconditionalWarp.T_FLOW:\n\t\t\t\tstart_index += 1\n\t\t\t\tcontinue\n\n\t\tbody, end, end_index = _extract_if_body(start_index,\n\t\t\t\t\t\t\tblocks, topmost_end)\n\n\t\tif body is None:\n\t\t\traise NotImplementedError(\"GOTO statements are not\"\n\t\t\t\t\t\t\t\t\" supported\")\n\n\t\tis_end = isinstance(body[-1].warp, nodes.EndWarp)\n\n\t\t_unwarp_if_statement(start, body, end, end)\n\n\t\tif is_end:\n\t\t\t_set_end(start)\n\t\telse:\n\t\t\t_set_flow_to(start, end)\n\n\t\tboundaries.append((start_index, end_index - 1))\n\n\t\tstart_index = end_index\n\n\treturn _remove_processed_blocks(blocks, boundaries)\n\n\ndef _extract_if_body(start_index, blocks, topmost_end):\n\tend = _find_branching_end(blocks[start_index:], topmost_end)\n\n\ttry:\n\t\tend_index = blocks.index(end)\n\texcept ValueError:\n\t\tif end == topmost_end:\n\t\t\tend_index = len(blocks)\n\t\telse:\n\t\t\treturn None, None, None\n\n\tbody = blocks[start_index + 1:end_index]\n\n\treturn body, end, end_index\n\n\ndef _unwarp_expressions_pack(blocks, pack):\n\treplacements = {}\n\n\tfor start, end, slot, slot_type in reversed(pack):\n\t\tend = replacements.get(end, end)\n\n\t\tstart_index = blocks.index(start)\n\t\tend_index = blocks.index(end)\n\n\t\tbody = blocks[start_index + 1:end_index]\n\n\t\t_unwarp_logical_expression(start, end, body)\n\n\t\tstatements = start.contents + end.contents\n\n\t\tif slot_type == nodes.Identifier.T_SLOT:\n\t\t\tmin_i = len(start.contents)\n\t\t\tsplit_i = _split_by_slot_use(statements, min_i,\n\t\t\t\t\t\t\tend.warp, slot)\n\t\telse:\n\t\t\tsplit_i = len(start.contents)\n\n\t\tmax_i = len(statements)\n\n\t\tif split_i > max_i:\n\t\t\tend.contents = start.contents + end.contents\n\t\t\tstart.contents = []\n\n\t\t\tblocks = blocks[:start_index] + blocks[end_index:]\n\n\t\t\t_replace_targets(blocks, start, end)\n\n\t\t\treplacements[start] = end\n\n\t\t\tslotworks.eliminate_temporary(end)\n\n\t\t\t_set_flow_to(start, end)\n\t\telse:\n\t\t\tblocks = blocks[:start_index + 1] + blocks[end_index:]\n\n\t\t\tstart.contents = statements[:split_i]\n\t\t\tend.contents = statements[split_i:]\n\n\t\t\t# We need to kill the start's warp before slot\n\t\t\t# elimination or it could result in a cycled AST.\n\t\t\t_set_flow_to(start, end)\n\n\t\t\tslotworks.eliminate_temporary(start)\n\n\treturn blocks\n\n\ndef _split_by_slot_use(statements, min_i, warp, slot):\n\tknown_slots = set([slot])\n\n\tsplit_i = min_i\n\n\tfor i, statement in enumerate(statements):\n\t\tif isinstance(statement, nodes.Assignment):\n\t\t\tsets = _extract_destination_slots(statement)\n\n\t\t\tif i < min_i:\n\t\t\t\tknown_slots |= sets\n\t\t\telse:\n\t\t\t\tknown_slots -= sets\n\n\t\t\tif len(known_slots) == 0:\n\t\t\t\tbreak\n\n\t\tsplit_i = i + 1\n\n\tif split_i < len(statements):\n\t\treturn split_i\n\n\tif isinstance(warp, nodes.ConditionalWarp):\n\t\tknown_slots -= _gather_slots(warp)\n\n\t\tif len(known_slots) == 0:\n\t\t\tsplit_i += 1\n\n\treturn split_i\n\n\ndef _extract_destination_slots(statement):\n\tsets = set()\n\n\tfor node in statement.destinations.contents:\n\t\tif not isinstance(node, nodes.Identifier):\n\t\t\tcontinue\n\n\t\tif node.type == nodes.Identifier.T_SLOT:\n\t\t\tsets.add(node.slot)\n\n\treturn sets\n\n\ndef _gather_slots(node):\n\tclass Collector(traverse.Visitor):\n\t\tdef __init__(self):\n\t\t\tself.slots = set()\n\n\t\tdef visit_identifier(self, node):\n\t\t\tif node.type == nodes.Identifier.T_SLOT:\n\t\t\t\tself.slots.add(node.slot)\n\n\tcollector = Collector()\n\n\ttraverse.traverse(collector, node)\n\n\treturn collector.slots\n\n\ndef _find_expressions(start, body, end):\n\t# Explicitly allow the local a = x ~= \"b\" case\n\tslot, slot_type = _get_simple_local_assignment_slot(start, body, end)\n\n\tif slot >= 0:\n\t\treturn [(start, end, slot, slot_type)]\n\n\texpressions = []\n\n\t# We have something at the end, but not the true/false?\n\n\ti = 0\n\textbody = [start] + body\n\n\tis_local = False\n\tsure_expression = False\n\n\twhile i < len(extbody):\n\t\tblock = extbody[i]\n\n\t\tsubs = _find_subexpressions(block, body[i:])\n\n\t\tif len(subs) != 0:\n\t\t\tendest_end = _find_endest_end(subs)\n\t\t\tnew_i = extbody.index(endest_end)\n\n\t\t\t# Loop? No way!\n\t\t\tif new_i <= i:\n\t\t\t\treturn expressions\n\n\t\t\t# It should end with a conditional warp if that's\n\t\t\t# really a subexpression-as-operand\n\t\t\tend_warp = endest_end.warp\n\n\t\t\tif not isinstance(end_warp, nodes.ConditionalWarp):\n\t\t\t\treturn expressions\n\n\t\t\texpressions = subs + expressions\n\t\t\ti = new_i\n\t\t\tcontinue\n\n\t\tif isinstance(block.warp, nodes.ConditionalWarp):\n\t\t\tcondition = block.warp.condition\n\n\t\t\tis_end = block.warp.false_target == end\n\t\t\tis_binop = isinstance(condition, nodes.BinaryOperator)\n\t\t\tblock_slot = getattr(block.warp, \"_slot\", slot)\n\n\t\t\tif is_end:\n\t\t\t\tif is_binop:\n\t\t\t\t\treturn expressions\n\t\t\t\telif slot < 0 and block_slot >= 0:\n\t\t\t\t\tslot = block_slot\n\t\t\t\t\tslot_type = nodes.Identifier.T_SLOT\n\t\t\t\t\tsure_expression = True\n\t\t\t\telif slot != block_slot:\n\t\t\t\t\treturn expressions\n\t\t\t\telse:\n\t\t\t\t\tsure_expression = True\n\t\telif isinstance(block.warp, nodes.UnconditionalWarp):\n\t\t\tif block == start and len(block.contents) == 0:\n\t\t\t\treturn []\n\n\t\tif len(block.contents) == 0:\n\t\t\ti += 1\n\t\t\tcontinue\n\n\t\tif block != start and len(block.contents) > 1:\n\t\t\treturn expressions\n\n\t\tassignment = block.contents[-1]\n\n\t\tif not isinstance(assignment, nodes.Assignment):\n\t\t\tif block == start:\n\t\t\t\ti += 1\n\t\t\t\tcontinue\n\n\t\t\treturn expressions\n\n\t\tdestinations = assignment.destinations.contents\n\n\t\tif len(destinations) != 1:\n\t\t\tif block == start:\n\t\t\t\ti += 1\n\t\t\t\tcontinue\n\n\t\t\treturn expressions\n\n\t\tdst = destinations[0]\n\n\t\tif not isinstance(dst, nodes.Identifier):\n\t\t\tif block == start:\n\t\t\t\ti += 1\n\t\t\t\tcontinue\n\n\t\t\treturn expressions\n\n\t\tif isinstance(block.warp, nodes.ConditionalWarp):\n\t\t\tif block == start:\n\t\t\t\ti += 1\n\t\t\t\tcontinue\n\n\t\t\treturn expressions\n\n\t\tif slot < 0:\n\t\t\t# If all encounters are locals, which means\n\t\t\t# that the first encounter is a local\n\t\t\tif dst.type == nodes.Identifier.T_LOCAL:\n\t\t\t\tis_local = True\n\t\t\telif dst.type == nodes.Identifier.T_UPVALUE:\n\t\t\t\treturn []\n\n\t\t\tslot = dst.slot\n\t\t\tslot_type = dst.type\n\t\telif slot == dst.slot:\n\t\t\tslot_type = dst.type\n\n\t\t\tif dst.type == nodes.Identifier.T_UPVALUE:\n\t\t\t\treturn []\n\t\telse:\n\t\t\tassert block != start\n\n\t\t\treturn []\n\n\t\ti += 1\n\n\tif slot < 0:\n\t\treturn []\n\n\ttrue, _false, body = _get_terminators(body)\n\n\tif true is not None:\n\t\tsure_expression = True\n\n\tif len(expressions) > 0:\n\t\tsure_expression = True\n\n\tif not sure_expression and is_local:\n\t\treturn expressions\n\n\treturn expressions + [(start, end, slot, slot_type)]\n\n\ndef _find_subexpressions(start, body):\n\ttry:\n\t\tbody, end, _end_index = _extract_if_body(0, [start] + body, None)\n\texcept ValueError:\n\t\t# a warp target is not in a list\n\t\treturn []\n\n\tif body is None:\n\t\treturn []\n\n\treturn _find_expressions(start, body, end)\n\n\ndef _get_simple_local_assignment_slot(start, body, end):\n\tif len(body) != 2:\n\t\treturn -1, None\n\n\ttrue, _false, body = _get_terminators(body)\n\n\tif true is None:\n\t\treturn -1, None\n\telse:\n\t\tslot = true.contents[0].destinations.contents[0]\n\t\treturn slot.slot, slot.type\n\n\ndef _find_expression_slot(body):\n\tslot = None\n\n\tfor block in reversed(body):\n\t\tif len(block.contents) != 1:\n\t\t\tcontinue\n\n\t\tslot = block.contents[0].destinations.contents[0]\n\t\tbreak\n\n\treturn slot\n\n\ndef _unwarp_logical_expression(start, end, body):\n\tslot = _find_expression_slot(body)\n\n\tassert slot is not None\n\n\ttrue, false, body = _get_terminators(body)\n\n\texpression = _compile_expression([start] + body, end, true, false)\n\n\tdst = copy.deepcopy(slot)\n\n\tassignment = nodes.Assignment()\n\tassignment.destinations.contents.append(dst)\n\tassignment.expressions.contents.append(expression)\n\n\tstart.contents.append(assignment)\n\n\ndef _compile_expression(body, end, true, false):\n\tparts = _unwarp_expression(body, end, true, false)\n\n\tif len(parts) < 3:\n\t\tassert len(parts) == 1\n\t\treturn parts[0]\n\n\texplicit_parts = _make_explicit_subexpressions(parts)\n\treturn _assemble_expression(explicit_parts)\n\n\n#\n# The logical expressions:\n#\n# There are terminators: a true, a false and an end\n#\n# For an if case the true will be a \"then\" clause and the false - an \"else\" or\n# \"after-the-if\" clause. The end is required for a single-variable (unary)\n# components and is only used at during topmost phase.\n#\n# The last block in expression is always \"double terminal\" - both ends are\n# pointing at terminators. It's rather useless so we just append it's condition\n# (inverted if needed - it's easy to see if true end targets the false\n# terminator) at the end of processing.\n#\n# Then we need to pack all other blocks into subexpressions. Subexpressions\n# always end with a _terminal block_, i.e. the block which warp points to a\n# terminator. Idea is that we can guess the operator only right of a\n# terminal block, because we can check if the block's warp condition is\n# inverted or not.\n#\n# If that's an \"OR\" clause then it will jump out of the current expression if\n# the condition is true, so the condition is inverted and the false branch is\n# pointing at the way out (at the TRUE terminator - because the result of the\n# expression level will be true). (because in the bytecode there\n# is only one JMP, so a ConditionalWarp's true branch is actually a fake and\n# always points to the next block - in the bytecode a \"positive\" jump\n# will be represented by a normal negative jump with inverted condition).\n#\n# Otherwise, if that's an \"AND\" clause then it will jump out of the current\n# expression level if a condition is false, so the condition is not inverted\n# and a false branch points to the false.\n#\n# This way we can understand which operators go just right of terminal blocks.\n# Everything in-between these block is considered a subexpression. And just\n# because we don't know where exactly the subexpression ends we are using\n# greedy approach and trying to pack into a subexpression as much blocks as\n# possible, including any terminal blocks pointing at the same terminator\n# with the same inversion status (that is - we are always using the\n# rightmost block if there are consequitive similar terminal blocks, ignoring\n# all the blocks to the left).\n#\n# Then comes the trick: the subexpression is a component of this expression and\n# we know the operator to the right of it. We can guess now what will\n# be evaluated if the subexpression evaluates to \"false\" and what - if it's\n# \"true\". If the operator is \"AND\" then the subexpression failure will cause\n# the expression failure too, i.e. the \"FALSE\" target remains the same and the\n# true terminator is set to the next block (after the \"AND\").\n#\n# If the operator is \"OR\" the the subexpression success will cause the success\n# of the expression, so the \"TRUE\" target remains the same, but the false\n# target is set to the next block (after the \"OR\").\n#\n# Now we have a subexpression and both TRUE and FALSE terminators for it.\n# Recurse and repeat.\n#\ndef _unwarp_expression(body, end, true, false):\n\tparts = []\n\n\tif true is not None:\n\t\tterminator_index = min(true.index, false.index)\n\n\t\tif end is not None:\n\t\t\tterminator_index = min(end.index, terminator_index)\n\telse:\n\t\tassert end is not None\n\n\t\tterminator_index = end.index\n\n\tterminators = set((true, false, end))\n\n\tsubexpression_start = 0\n\n\ti = 0\n\twhile i < len(body) - 1:\n\t\tblock = body[i]\n\t\twarp = block.warp\n\n\t\ttarget = _get_target(warp)\n\n\t\t#\n\t\t# A chance for\n\t\t# (foo and (bar and y or z)) or x\n\t\t# type expressions, because the first \"foo and ... )) or\" part\n\t\t# will be broken by the \"or z))\" part in the code below.\n\t\t#\n\t\t# So we are going to intercept subexpressions by it's start\n\t\t# instead of an end, but only if we are already at the\n\t\t# subexpression start (so nothing formally changes, but creates\n\t\t# a bit more correct execution order)\n\t\t#\n\t\tif target.index < terminator_index:\n\t\t\tif i != subexpression_start:\n\t\t\t\ti += 1\n\t\t\t\tcontinue\n\n\t\t\ttarget_index = body.index(target)\n\t\t\tlast_block = body[target_index - 1]\n\n\t\t\tlast_block_target = _get_target(last_block.warp)\n\n\t\t\tif last_block_target.index < terminator_index:\n\t\t\t\ti += 1\n\t\t\t\tcontinue\n\n\t\t\tassert last_block_target in terminators\n\n\t\t\tsubexpression = body[i:target_index]\n\t\telse:\n\t\t\tassert target in terminators\n\n\t\t\twhile i < len(body) - 2:\n\t\t\t\tnext_block = body[i + 1]\n\t\t\t\tnext_target = _get_target(next_block.warp)\n\n\t\t\t\tif next_target != target:\n\t\t\t\t\tbreak\n\n\t\t\t\tnext_inv = _is_inverted(next_block.warp, true, end)\n\n\t\t\t\tthis_inv = _is_inverted(warp, true, end)\n\n\t\t\t\t# Special hack for unary expressions (x, not x)...\n\t\t\t\tif next_inv != this_inv:\n\t\t\t\t\tbreak\n\n\t\t\t\tblock = next_block\n\t\t\t\twarp = next_block.warp\n\t\t\t\ti += 1\n\n\t\t\tsubexpression = body[subexpression_start:i + 1]\n\n\t\tlast_block = subexpression[-1]\n\t\tlast_block_index = body.index(last_block)\n\n\t\tnext_block = body[last_block_index + 1]\n\n\t\toperator = _get_operator(last_block, true, end)\n\n\t\tsubexpression = _compile_subexpression(subexpression, operator,\n\t\t\t\t\t\t\tlast_block, next_block,\n\t\t\t\t\t\t\ttrue, end)\n\n\t\tparts.append(subexpression)\n\t\tparts.append(operator)\n\n\t\ti = last_block_index + 1\n\t\tsubexpression_start = i\n\n\tlast = body[-1]\n\n\tif isinstance(last.warp, nodes.ConditionalWarp):\n\t\tif _is_inverted(last.warp, true, end):\n\t\t\tlast = _invert(last.warp.condition)\n\t\telse:\n\t\t\tlast = last.warp.condition\n\n\t\tparts.append(last)\n\telse:\n\t\tassert isinstance(last.warp, (nodes.EndWarp,\n\t\t\t\t\t\tnodes.UnconditionalWarp))\n\n\t\tsrc = _get_last_assignment_source(last)\n\n\t\tif src is None:\n\t\t\tsrc = nodes.Primitive()\n\n\t\t\tif last.warp.target == true:\n\t\t\t\tsrc.type = nodes.Primitive.T_TRUE\n\t\t\telse:\n\t\t\t\tsrc.type = nodes.Primitive.T_FALSE\n\n\t\tparts.append(src)\n\n\treturn parts\n\n\ndef _get_target(warp, allow_end=False):\n\tif isinstance(warp, nodes.ConditionalWarp):\n\t\treturn warp.false_target\n\telse:\n\t\tif allow_end and isinstance(warp, nodes.EndWarp):\n\t\t\treturn getattr(warp, \"_target\", None)\n\n\t\tassert isinstance(warp, nodes.UnconditionalWarp)\n\t\treturn warp.target\n\n\ndef _set_target(warp, target):\n\tif isinstance(warp, nodes.ConditionalWarp):\n\t\twarp.false_target = target\n\telse:\n\t\tassert isinstance(warp, nodes.UnconditionalWarp)\n\t\twarp.target = target\n\n\ndef _get_operator(block, true, end):\n\tif isinstance(block.warp, nodes.UnconditionalWarp):\n\t\tsrc = _get_last_assignment_source(block)\n\n\t\tif isinstance(src, nodes.Constant):\n\t\t\tis_true = src.value != 0\n\t\telif isinstance(src, nodes.BinaryOperator):\n\t\t\tis_true = True\n\t\telif isinstance(src, nodes.Primitive):\n\t\t\tis_true = src.type == nodes.Primitive.T_TRUE\n\t\telif isinstance(src, nodes.Identifier):\n\t\t\tis_true = True\n\t\telse:\n\t\t\t#assert src is None\n\n\t\t\tis_true = block.warp.target == true\n\n\t\tif is_true:\n\t\t\treturn binop.T_LOGICAL_OR\n\t\telse:\n\t\t\treturn binop.T_LOGICAL_AND\n\telse:\n\t\tis_inverted = _is_inverted(block.warp, true, end)\n\n\t\tif is_inverted:\n\t\t\treturn binop.T_LOGICAL_OR\n\t\telse:\n\t\t\treturn binop.T_LOGICAL_AND\n\n\ndef _get_last_assignment_source(block):\n\tif len(block.contents) == 0:\n\t\treturn None\n\n\tassignment = block.contents[-1]\n\tassert isinstance(assignment, nodes.Assignment)\n\treturn assignment.expressions.contents[0]\n\n\ndef _get_and_remove_last_assignment_source(block):\n\tassignment = block.contents.pop()\n\tassert isinstance(assignment, nodes.Assignment)\n\treturn assignment.expressions.contents[0]\n\n\ndef _compile_subexpression(subexpression, operator,\n\t\t\t\t\t\tblock, next_block, true, end):\n\twarp = block.warp\n\n\tif len(subexpression) == 1:\n\t\tif isinstance(warp, nodes.UnconditionalWarp):\n\t\t\treturn _get_and_remove_last_assignment_source(block)\n\t\telif _is_inverted(warp, true, end):\n\t\t\treturn _invert(warp.condition)\n\t\telse:\n\t\t\treturn warp.condition\n\telse:\n\t\tif isinstance(warp, nodes.UnconditionalWarp):\n\t\t\tif operator == binop.T_LOGICAL_OR:\n\t\t\t\tsubtrue = warp.target\n\t\t\t\tsubfalse = next_block\n\t\t\telse:\n\t\t\t\tsubtrue = next_block\n\t\t\t\tsubfalse = warp.target\n\t\telse:\n\t\t\tif operator == binop.T_LOGICAL_OR:\n\t\t\t\tsubtrue = warp.false_target\n\t\t\t\tsubfalse = warp.true_target\n\t\t\telse:\n\t\t\t\tsubtrue = warp.true_target\n\t\t\t\tsubfalse = warp.false_target\n\n\t\treturn _unwarp_expression(subexpression, None, subtrue, subfalse)\n\n\ndef _is_inverted(warp, true, end):\n\tif isinstance(warp, nodes.UnconditionalWarp):\n\t\treturn warp.target == end\n\n\tif warp.false_target == true:\n\t\treturn True\n\telif warp.false_target == end:\n\t\tassert not isinstance(warp.condition, nodes.BinaryOperator)\n\n\t\tif not isinstance(warp.condition, nodes.UnaryOperator):\n\t\t\treturn False\n\n\t\treturn warp.condition.type == nodes.UnaryOperator.T_NOT\n\n\treturn False\n\n\n_NEGATION_MAP = [None] * 100\n\n_NEGATION_MAP[binop.T_LESS_THEN] = binop.T_GREATER_OR_EQUAL\n_NEGATION_MAP[binop.T_GREATER_THEN] = binop.T_LESS_OR_EQUAL\n_NEGATION_MAP[binop.T_LESS_OR_EQUAL] = binop.T_GREATER_THEN\n_NEGATION_MAP[binop.T_GREATER_OR_EQUAL] = binop.T_LESS_THEN\n\n_NEGATION_MAP[binop.T_NOT_EQUAL] = binop.T_EQUAL\n_NEGATION_MAP[binop.T_EQUAL] = binop.T_NOT_EQUAL\n\n\ndef _invert(expression):\n\tif isinstance(expression, nodes.UnaryOperator):\n\t\treturn expression.operand\n\n\tif not isinstance(expression, nodes.BinaryOperator):\n\t\tnode = nodes.UnaryOperator()\n\t\tnode.type = nodes.UnaryOperator.T_NOT\n\t\tnode.operand = expression\n\n\t\treturn node\n\n\t# Just in case\n\texpression = copy.deepcopy(expression)\n\n\tnew_type = _NEGATION_MAP[expression.type]\n\n\tassert new_type is not None\n\n\texpression.type = new_type\n\n\treturn expression\n\n\ndef _get_terminators(body):\n\tif len(body) < 2:\n\t\treturn None, None, body\n\n\tlast = body[-1]\n\n\tif len(last.contents) != 1:\n\t\treturn None, None, body\n\n\tassignment = last.contents[0]\n\n\tif not isinstance(assignment, nodes.Assignment):\n\t\treturn None, None, body\n\n\tsrc = assignment.expressions.contents[0]\n\n\tif not isinstance(src, nodes.Primitive) or src.type != src.T_TRUE:\n\t\treturn None, None, body\n\n\tprev = body[-2]\n\n\tif len(prev.contents) != 1:\n\t\treturn None, None, body\n\n\tsrc = prev.contents[0].expressions.contents[0]\n\n\tif not isinstance(src, nodes.Primitive) or src.type != src.T_FALSE:\n\t\treturn None, None, body\n\n\treturn last, prev, body[:-2]\n\n\ndef _assemble_expression(parts):\n\tif not isinstance(parts, list):\n\t\treturn parts\n\n\tnode = nodes.BinaryOperator()\n\tnode.left = _assemble_expression(parts[-3])\n\n\tnode.type = parts[-2]\n\tassert isinstance(node.type, int)\n\n\tnode.right = _assemble_expression(parts[-1])\n\n\ti = len(parts) - 4\n\n\twhile i > 0:\n\t\toperator = parts[i]\n\t\tcomponent = parts[i - 1]\n\n\t\tupper_node = nodes.BinaryOperator()\n\t\tupper_node.right = node\n\t\tupper_node.left = _assemble_expression(component)\n\n\t\tupper_node.type = operator\n\n\t\tnode = upper_node\n\n\t\ti -= 2\n\n\treturn node\n\n\n# Split the topmost expression into smaller subexpressions at each\n# operator change to simplify the assembly phase\ndef _make_explicit_subexpressions(parts):\n\tpatched = []\n\n\ti = 0\n\n\tlast_operator = parts[1]\n\tsubexpression_start = -1\n\n\twhile i < len(parts) - 1:\n\t\tcomponent = parts[i]\n\t\toperator = parts[i + 1]\n\n\t\tif operator < last_operator:\n\t\t\tsubexpression_start = i\n\t\t\tlast_operator = operator\n\t\telif subexpression_start > 0:\n\t\t\tif operator > last_operator\t\t\t\t\\\n\t\t\t\t\tand (i - subexpression_start) % 2 != 0:\n\t\t\t\tsubexpression = parts[subexpression_start:i]\n\n\t\t\t\tpatched.append(subexpression)\n\t\t\t\tsubexpression_start = -1\n\t\telse:\n\t\t\tpatched += [component, operator]\n\n\t\ti += 2\n\n\tif subexpression_start >= 0:\n\t\tpatched.append(parts[subexpression_start:])\n\telse:\n\t\tpatched.append(parts[-1])\n\n\treturn patched\n\n\ndef _unwarp_if_statement(start, body, end, topmost_end):\n\texpression, body, false = _extract_if_expression(start, body, end,\n\t\t\t\t\t\t\t\ttopmost_end)\n\n\tnode = nodes.If()\n\tnode.expression = expression\n\n\t# has an else branch\n\tif false != end and false != topmost_end:\n\t\telse_start = false\n\n\t\telse_start_index = body.index(else_start)\n\n\t\tthen_body = body[:else_start_index]\n\n\t\tthen_warp_out = then_body[-1].warp\n\n\t\tassert _is_jump(then_warp_out)\n\t\tassert then_warp_out.target in (end, topmost_end)\n\n\t\telse_body = body[else_start_index:]\n\n\t\telse_warp_out = else_body[-1].warp\n\n\t\tif isinstance(else_warp_out, nodes.UnconditionalWarp):\n\t\t\tif else_warp_out.type == nodes.UnconditionalWarp.T_JUMP:\n\t\t\t\tassert else_warp_out.target in (end, topmost_end)\n\t\t\telse:\n\t\t\t\tassert else_warp_out.target == end\n\t\telse:\n\t\t\tprint (\"err: unwarper.py assert isinstance(else_warp_out, nodes.EndWarp), Block indices are unreliable while you are mangling them! P.S. Probably they should not be named indices... But they ARE used as indices during other phases. Sometimes.\")\n\n\t\t_set_end(then_body[-1])\n\t\tthen_blocks = _unwarp_ifs(then_body, then_body[-1], topmost_end)\n\t\tnode.then_block.contents = then_blocks\n\n\t\t_set_end(else_body[-1])\n\t\telse_blocks = _unwarp_ifs(else_body, else_body[-1], topmost_end)\n\t\tnode.else_block.contents = else_blocks\n\telse:\n\t\twarp_out = body[-1].warp\n\n\t\tif not isinstance(warp_out, nodes.EndWarp):\n\t\t\tassert isinstance(warp_out, nodes.UnconditionalWarp)\n\t\t\tassert warp_out.target in (end, topmost_end)\n\n\t\t_set_end(body[-1])\n\t\tthen_blocks = _unwarp_ifs(body, body[-1], topmost_end)\n\t\tnode.then_block.contents = then_blocks\n\n\tstart.contents.append(node)\n\n\ndef _extract_if_expression(start, body, end, topmost_end):\n\tfor i, block in enumerate(body):\n\t\tif len(block.contents) != 0:\n\t\t\tbreak\n\n\tassert i < len(body)\n\n\texpression = [start] + body[:i]\n\tbody = body[i:]\n\n\tfalses = set()\n\n\tfor i, block in enumerate(body[:-1]):\n\t\tif not isinstance(block.warp, nodes.UnconditionalWarp):\n\t\t\tcontinue\n\n\t\tif block.warp.type != nodes.UnconditionalWarp.T_JUMP:\n\t\t\tcontinue\n\n\t\tif block.warp.target != end and block.warp.target != topmost_end:\n\t\t\tcontinue\n\n\t\tfalses.add(body[i + 1])\n\n\tfalses.add(end)\n\n\tif topmost_end is not None:\n\t\tfalses.add(topmost_end)\n\n\tfalse, end_i = _search_expression_end(expression, falses)\n\n\tassert end_i >= 0\n\n\tbody = expression[end_i:] + body\n\texpression = expression[:end_i]\n\n\tassert len(expression) > 0\n\n\ttrue = body[0]\n\n\texpression = _compile_expression(expression, None, true, false)\n\n\treturn expression, body, false\n\n\ndef _search_expression_end(expression, falses):\n\texpression_end = -1\n\tfalse = None\n\n\tfor i, block in enumerate(expression):\n\t\ttarget = _get_target(block.warp)\n\n\t\tif target not in falses:\n\t\t\tcontinue\n\n\t\tif false is None or target == false:\n\t\t\tfalse = target\n\t\t\texpression_end = i + 1\n\t\telse:\n\t\t\tbreak\n\n\tassert false is not None\n\n\treturn false, expression_end\n\n\ndef _find_branching_end(blocks, topmost_end):\n\tend = blocks[0]\n\n\tfor block in blocks:\n\t\twarp = block.warp\n\n\t\ttarget = _get_target(warp, allow_end=True)\n\n\t\tif isinstance(warp, nodes.EndWarp) and target is None:\n\t\t\tassert block == end\n\t\t\treturn block\n\n\t\tif isinstance(warp, nodes.UnconditionalWarp) and target == end:\n\t\t\treturn end\n\n\t\tif target.index > end.index:\n\t\t\tend = target\n\n\treturn end\n\n\ndef _remove_processed_blocks(blocks, boundaries):\n\tremains = []\n\tlast_end_index = -1\n\n\tfor start, end in boundaries:\n\t\tif start == end:\n\t\t\tup_to_index = start\n\t\telse:\n\t\t\tup_to_index = start + 1\n\n\t\tremains += blocks[last_end_index + 1:up_to_index]\n\t\tlast_end_index = end\n\n\tremains += blocks[last_end_index + 1:]\n\n\treturn remains\n\n\n# ##\n# ## LOOPS PROCESSING\n# ##\n\n\ndef _unwarp_loops(blocks, repeat_until):\n\tloops = _find_all_loops(blocks, repeat_until)\n\n\tif len(loops) == 0:\n\t\treturn blocks\n\n\tfixed = _cleanup_breaks_and_if_ends(loops, blocks)\n\n\tfor start, end in fixed:\n\t\tstart_index = blocks.index(start)\n\t\tend_index = blocks.index(end)\n\n\t\tif repeat_until:\n\t\t\tbody = blocks[start_index:end_index]\n\t\telse:\n\t\t\tbody = blocks[start_index + 1:end_index]\n\n\t\tloop = _unwarp_loop(start, end, body)\n\t\tbody = loop.statements.contents\n\n\t\tblock = nodes.Block()\n\t\tblock.first_address = body[0].first_address\n\t\tblock.last_address = body[-1].last_address\n\t\tblock.index = start.index + 1\n\t\tblock.contents.append(loop)\n\n\t\tblock.warp = nodes.UnconditionalWarp()\n\t\tblock.warp.type = nodes.UnconditionalWarp.T_FLOW\n\t\tblock.warp.target = end\n\n\t\t_replace_targets(blocks, body[0], block)\n\n\t\t_set_end(body[-1])\n\t\t_unwarp_breaks(start, body, end)\n\n\t\tblocks = blocks[:start_index + 1] + [block] + blocks[end_index:]\n\n\treturn blocks\n\n\ndef _cleanup_breaks_and_if_ends(loops, blocks):\n\touter_start_index = -1\n\touter_end = None\n\n\tcurrent_start_index = -1\n\tcurrent_end = None\n\n\tfixed = []\n\n\tfor start, end in loops:\n\t\tif start.index in (outer_start_index, current_start_index):\n\t\t\tend_i = blocks.index(end)\n\t\t\tlast_in_body = blocks[end_i - 1]\n\t\t\twarp = last_in_body.warp\n\n\t\t\tassert isinstance(warp, nodes.UnconditionalWarp)\n\t\t\tassert warp.target == start\n\n\t\t\t# Break\n\t\t\tif start.index == outer_start_index:\n\t\t\t\tassert outer_end is not None\n\n\t\t\t\touter_end_i = blocks.index(outer_end)\n\t\t\t\twarp.target = blocks[outer_end_i - 1]\n\n\t\t\t\tassert blocks[outer_end_i - 2] != end\n\t\t\telse:\n\t\t\t\tassert current_end is not None\n\t\t\t\tassert start.index == current_start_index\n\n\t\t\t\tcurrent_end_i = blocks.index(current_end)\n\n\t\t\t\tlast = blocks[current_end_i - 1]\n\n\t\t\t\tif last == end:\n\t\t\t\t\tlast = _create_next_block(end)\n\t\t\t\t\tlast.warp = end.warp\n\n\t\t\t\t\t_set_flow_to(end, last)\n\n\t\t\t\t\tblocks.insert(current_end_i, last)\n\n\t\t\t\twarp.target = last\n\t\telse:\n\t\t\tfixed.append((start, end))\n\n\t\t\tif current_end is not None\t\t\t\t\\\n\t\t\t\t\tand current_start_index < start.index\t\\\n\t\t\t\t\tand current_end.index >= end.index:\n\t\t\t\touter_start_index = current_start_index\n\t\t\t\touter_end = current_end\n\t\t\telse:\n\t\t\t\touter_start_index = -1\n\t\t\t\touter_end = None\n\n\t\t\tcurrent_start_index = start.index\n\t\t\tcurrent_end = end\n\n\treturn fixed\n\n\ndef _replace_targets(blocks, original, replacement):\n\tfor block in blocks:\n\t\twarp = block.warp\n\n\t\tif isinstance(warp, nodes.UnconditionalWarp):\n\t\t\tif warp.target == original:\n\t\t\t\twarp.target = replacement\n\t\telif isinstance(warp, nodes.ConditionalWarp):\n\t\t\tif warp.true_target == original:\n\t\t\t\twarp.true_target = replacement\n\n\t\t\tif warp.false_target == original:\n\t\t\t\twarp.false_target = replacement\n\t\telif isinstance(warp, nodes.EndWarp):\n\t\t\tpass\n\t\telse:\n\t\t\tif warp.way_out == original:\n\t\t\t\twarp.way_out = replacement\n\n\t\t\tif warp.body == original:\n\t\t\t\twarp.body = replacement\n\n\ndef _unwarp_loop(start, end, body):\n\tif len(body) > 0:\n\t\tlast = body[-1]\n\telse:\n\t\tlast = start\n\n\tif isinstance(start.warp, nodes.IteratorWarp):\n\t\tassert isinstance(last.warp, nodes.UnconditionalWarp)\n\t\tassert last.warp.target == start\n\n\t\tloop = nodes.IteratorFor()\n\t\tloop.statements.contents = body\n\t\tloop.identifiers = start.warp.variables\n\t\tloop.expressions = start.warp.controls\n\t\tloop._addr = body[0].first_address\n\n\t\t_set_flow_to(start, body[0])\n\n\telif isinstance(start.warp, nodes.NumericLoopWarp):\n\t\tassert isinstance(last.warp, nodes.UnconditionalWarp)\n\t\tassert last.warp.target == start\n\n\t\tloop = nodes.NumericFor()\n\t\tloop.statements.contents = body\n\t\tloop.variable = start.warp.index\n\t\tloop.expressions = start.warp.controls\n\t\tloop._addr = body[0].first_address\n\t\t_set_flow_to(start, body[0])\n\n\t# While (including \"while true\" and \"repeat until false\" which will be\n\t# while true)\n\telif isinstance(last.warp, nodes.UnconditionalWarp):\n\t\tassert last.warp.target == start\n\n\t\t# while true\n\t\tif _is_flow(start.warp):\n\t\t\tloop = nodes.While()\n\t\t\tloop.expression = nodes.Primitive()\n\t\t\tloop.expression.type = nodes.Primitive.T_TRUE\n\n\t\t\tloop.statements.contents = body\n\t\telse:\n\t\t\t# There shouldn't be many problems similar to ifs, as\n\t\t\t# we are processing loops in the order from innermost\n\t\t\t# to outermost\n\t\t\tfor i, block in enumerate(body):\n\t\t\t\tassert len(block.contents) == 0\n\n\t\t\t\tif _is_flow(block.warp):\n\t\t\t\t\tbreak\n\n\t\t\tassert i < len(body)\n\n\t\t\texpression = [start] + body[:i]\n\t\t\tbody = body[i:]\n\n\t\t\t# Sometimes expression may decide to jump to the\n\t\t\t# outer loop start instead\n\t\t\t_fix_expression(expression, start, end)\n\n\t\t\ttrue = body[0]\n\t\t\tfalse = end\n\n\t\t\texpression = _compile_expression(expression, None,\n\t\t\t\t\t\t\t\ttrue, false)\n\n\t\t\t# If something jumps to the start (instead of the end)\n\t\t\t# - that's a nested if\n\t\t\tloop = nodes.While()\n\t\t\tloop.expression = expression\n\t\t\tloop.statements.contents = body\n\n\t\t_fix_nested_ifs(body, start)\n\n\t\t_set_flow_to(start, body[0])\n\n\t# Repeat until\n\telse:\n\t\tassert isinstance(last.warp, nodes.ConditionalWarp)\n\t\tassert last.warp.false_target == start\n\n\t\ti = len(body) - 1\n\n\t\twhile i >= 0:\n\t\t\tblock = body[i]\n\t\t\twarp = block.warp\n\n\t\t\tif _is_flow(warp):\n\t\t\t\ti += 1\n\t\t\t\tbreak\n\n\t\t\tif len(block.contents) != 0:\n\t\t\t\tbreak\n\n\t\t\ti -= 1\n\n\t\texpression = body[i:]\n\t\tbody = body[:i + 1]\n\n\t\tassert len(expression) > 0\n\n\t\tfirst = expression[0]\n\t\tif _is_jump(first.warp):\n\t\t\t# Don't append to the body - it already has it\n\t\t\texpression.pop(0)\n\t\t\tbody[-1].contents.append(nodes.Break())\n\n\t\tfalse = body[0]\n\t\t# Don't use end as it could be broken by a previous\n\t\t# repeat until pass\n\t\ttrue = expression[-1].warp.true_target\n\n\t\tloop = nodes.RepeatUntil()\n\t\tloop.expression = _compile_expression(expression, None,\n\t\t\t\t\t\t\t\ttrue, false)\n\n\t\tstart_copy = copy.copy(start)\n\t\tstart.contents = []\n\n\t\tif len(body) > 1:\n\t\t\t_set_flow_to(start_copy, body[1])\n\t\telse:\n\t\t\t_set_end(start_copy)\n\n\t\t_set_flow_to(start, start_copy)\n\n\t\tbody[0] = start_copy\n\n\t\tloop.statements.contents = body\n\n\treturn loop\n\n\ndef _create_next_block(original):\n\tblock = nodes.Block()\n\tblock.first_address = original.last_address + 1\n\tblock.last_address = block.first_address\n\tblock.index = original.index + 1\n\tblock.warpins_count = original.warpins_count\n\n\treturn block\n\n\ndef _set_flow_to(block, target):\n\tblock.warp = nodes.UnconditionalWarp()\n\tblock.warp.type = nodes.UnconditionalWarp.T_FLOW\n\tblock.warp.target = target\n\n\ndef _set_end(block):\n\ttarget = None\n\n\tif block.warp is not None:\n\t\ttarget = _get_target(block.warp, allow_end=True)\n\n\tblock.warp = nodes.EndWarp()\n\n\tsetattr(block.warp, \"_target\", target)\n\n\ndef _is_flow(warp):\n\treturn isinstance(warp, nodes.UnconditionalWarp)\t\\\n\t\tand warp.type == nodes.UnconditionalWarp.T_FLOW\n\n\ndef _is_jump(warp):\n\treturn isinstance(warp, nodes.UnconditionalWarp)\t\\\n\t\tand warp.type == nodes.UnconditionalWarp.T_JUMP\n\n\ndef _fix_nested_ifs(blocks, start):\n\t# We can't point both targets of a conditional warp to the\n\t# same block. We will have to create a new block\n\tlast = _create_next_block(blocks[-1])\n\n\tif isinstance(blocks[-1].warp, nodes.ConditionalWarp):\n\t\tblocks[-1].warp.false_target = last\n\telse:\n\t\t_set_flow_to(blocks[-1], last)\n\n\tblocks.append(last)\n\t_set_end(last)\n\n\tfor block in blocks[:-1]:\n\t\ttarget = _get_target(block.warp)\n\n\t\tif target == start:\n\t\t\t_set_target(block.warp, last)\n\n\ndef _fix_expression(blocks, start, end):\n\tfor block in blocks:\n\t\tif len(block.contents) != 0:\n\t\t\tbreak\n\n\t\ttarget = _get_target(block.warp)\n\n\t\tif target.index < start.index:\n\t\t\t_set_target(block.warp, end)\n\n\ndef _gather_possible_ends(block):\n\twarp = block.warp\n\n\tends = set((block,))\n\n\twhile _is_jump(warp):\n\t\tblock = warp.target\n\t\twarp = block.warp\n\n\t\tends.add(block)\n\n\treturn ends\n\n\nBREAK_INFINITE = 0\nBREAK_ONE_USE = 1\n\n\ndef _unwarp_breaks(start, blocks, next_block):\n\tblocks_set = set([start] + blocks)\n\n\tends = _gather_possible_ends(next_block)\n\n\tbreaks = set()\n\n\tpatched = []\n\n\tfor i, block in enumerate(blocks):\n\t\twarp = block.warp\n\n\t\tif not isinstance(warp, nodes.UnconditionalWarp):\n\t\t\tpatched.append(block)\n\t\t\tcontinue\n\n\t\ttarget = _get_target(warp)\n\n\t\tif target in blocks_set:\n\t\t\tpatched.append(block)\n\t\t\tcontinue\n\n\t\tassert target in ends, \"GOTO statements are not supported\"\n\n\t\tif block.warpins_count != 0:\n\t\t\tnew_block = _create_next_block(block)\n\t\t\tnew_block.warpins_count = block.warpins_count\n\t\t\t_set_flow_to(block, new_block)\n\n\t\t\tpatched.append(block)\n\t\t\tpatched.append(new_block)\n\n\t\t\tblock = new_block\n\t\telse:\n\t\t\tpatched.append(block)\n\n\t\tblock.contents.append(nodes.Break())\n\n\t\tif i + 1 == len(blocks):\n\t\t\t_set_end(block)\n\t\telse:\n\t\t\t_set_flow_to(block, blocks[i + 1])\n\n\t\tbreaks.add(block)\n\n\tblocks[:] = patched\n\n\tif len(breaks) == 0:\n\t\treturn\n\n\tbreaks_stack = []\n\twarpsout = []\n\tpending_break = None\n\n\tfor i, block in enumerate(reversed(blocks)):\n\t\tif block in breaks:\n\t\t\tpending_break = None\n\n\t\t\tif block.warpins_count == 0:\n\t\t\t\tbreaks_stack.append((BREAK_ONE_USE, block))\n\t\t\telse:\n\t\t\t\tbreaks_stack.append((BREAK_INFINITE, block))\n\n\t\t\tcontinue\n\n\t\twarp = block.warp\n\n\t\tif not isinstance(warp, nodes.ConditionalWarp):\n\t\t\tif _is_flow(warp):\n\t\t\t\tpending_break = None\n\n\t\t\tcontinue\n\n\t\ttarget = _get_target(warp)\n\n\t\tif target in blocks_set:\n\t\t\tcontinue\n\n\t\tassert target in ends, \"GOTO statements are not supported\"\n\n\t\tif pending_break is None:\n\t\t\tassert len(breaks_stack) > 0\n\n\t\t\ttop_break = breaks_stack[-1]\n\n\t\t\t_set_target(warp, top_break[1])\n\n\t\t\tif top_break[0] == BREAK_ONE_USE:\n\t\t\t\tpending_break = breaks_stack.pop()\n\n\t\t\t\twarpsout = []\n\t\t\telse:\n\t\t\t\twarpsout.append(block)\n\t\telse:\n\t\t\t_set_target(warp, pending_break[1])\n\t\t\twarpsout.append(block)\n\n\t\tif len(block.contents) > 0:\n\t\t\tpending_break = None\n\n\twhile len(breaks_stack) > 0 and breaks_stack[-1][0] == BREAK_INFINITE:\n\t\tbreaks_stack.pop()\n\n\t# And pray for the best...\n\twhile len(warpsout) > 0 and len(breaks_stack) > 0:\n\t\t_set_target(warpsout.pop().warp, breaks_stack.pop()[1])\n\n\n#\n# We don't need any complex checks here.\n#\n# Just search for any negative jump - that's a loop and what it's jumping to is\n# a loop start.\n#\ndef _find_all_loops(blocks, repeat_until):\n\t# Duplicates are NOT possible\n\tloops = []\n\n\ti = 0\n\n\twhile i < len(blocks):\n\t\tblock = blocks[i]\n\t\twarp = block.warp\n\n\t\tif isinstance(warp, nodes.UnconditionalWarp):\n\t\t\tif warp.type == nodes.UnconditionalWarp.T_FLOW:\n\t\t\t\ti += 1\n\t\t\t\tcontinue\n\n\t\t\tif warp.target.index <= block.index:\n\t\t\t\tassert not repeat_until\n\t\t\t\tassert i < len(blocks) - 1\n\t\t\t\tloops.append((warp.target, blocks[i + 1]))\n\n\t\telif repeat_until and isinstance(warp, nodes.ConditionalWarp):\n\t\t\tif warp.false_target.index > block.index:\n\t\t\t\ti += 1\n\t\t\t\tcontinue\n\n\t\t\tstart = warp.false_target\n\t\t\tfirst = block\n\t\t\tend = block\n\t\t\tlast_i = i\n\n\t\t\t# Find the end of the expression\n\t\t\twhile i < len(blocks):\n\t\t\t\tblock = blocks[i]\n\t\t\t\twarp = block.warp\n\n\t\t\t\tif block != first and len(block.contents) != 0:\n\t\t\t\t\tbreak\n\n\t\t\t\tif isinstance(warp, nodes.EndWarp):\n\t\t\t\t\tbreak\n\n\t\t\t\t# Go up to a first negative jump of an\n\t\t\t\t# another loop\n\n\t\t\t\ttarget = _get_target(warp)\n\t\t\t\tif target.index < block.index:\n\t\t\t\t\tif target == start:\n\t\t\t\t\t\tstart = target\n\t\t\t\t\t\tend = block\n\t\t\t\t\t\tlast_i = i\n\t\t\t\t\telse:\n\t\t\t\t\t\tbreak\n\n\t\t\t\ti += 1\n\n\t\t\t# And then rollback to the last known negative jump\n\t\t\t# of our loop\n\t\t\ti = last_i\n\n\t\t\t# There always should be at least one return block\n\t\t\tend_index = blocks.index(end)\n\t\t\tend = blocks[end_index + 1]\n\n\t\t\tloops.append((start, end))\n\n\t\ti += 1\n\n\t# Reverse the order so inner \"while\" loops are processed before\n\t# outer loops\n\treturn list(reversed(sorted(loops, key=lambda x: x[0].index)))\n\n\ndef _get_previous_block(block, blocks):\n\tblock_index = blocks.index(block)\n\n\tassert block_index > 0\n\n\treturn blocks[block_index - 1]\n"
  },
  {
    "path": "ljd/ast/validator.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport ljd.ast.nodes as nodes\nimport ljd.ast.traverse as traverse\n\n\nclass TypeRestriction():\n\tdef __init__(self, default, specific):\n\t\tif isinstance(default, dict) and specific == {}:\n\t\t\tspecific = default\n\t\t\tdefault = None\n\n\t\tself.default = default\n\t\tself.specific = specific\n\n\tdef check(self, node):\n\t\ttry:\n\t\t\ttypespec = self.specific[node]\n\t\texcept KeyError:\n\t\t\ttypespec = self.default\n\n\t\t#assert typespec, \"Unknown node: {0}\".format(node)\n\n\t\t#assert isinstance(node, typespec),\"Invalid node type: {0} should be: {1}\".format(type(node), typespec)\n\n\nSTATEMENT_TYPES = (\n\tnodes.Assignment,\n\tnodes.If,\n\tnodes.IteratorFor,\n\tnodes.NumericFor,\n\tnodes.RepeatUntil,\n\tnodes.Return,\n\tnodes.Break,\n\tnodes.FunctionCall,\n\tnodes.While\n)\n\nEXPRESSION_TYPES = (\n\tnodes.FunctionCall,\n\tnodes.Primitive,\n\tnodes.Constant,\n\tnodes.Identifier,\n\tnodes.FunctionDefinition,\n\tnodes.TableConstructor,\n\tnodes.Vararg,\n\tnodes.BinaryOperator,\n\tnodes.UnaryOperator,\n\tnodes.MULTRES,\n\tnodes.TableElement,\n)\n\nVARIABLE_TYPES = (\n\tnodes.Identifier,\n\tnodes.TableElement,\n\tnodes.MULTRES  # It's not valid here, but it is a hack anyway...\n)\n\nWARP_TYPES = (\n\tnodes.UnconditionalWarp,\n\tnodes.ConditionalWarp,\n\tnodes.IteratorWarp,\n\tnodes.NumericLoopWarp,\n\tnodes.EndWarp\n)\n\n\nclass Visitor(traverse.Visitor):\n\tdef __init__(self, warped=True):\n\t\t# Restrictions for the upmost level\n\t\tself.restrictions = [None]\n\t\tself.warped = warped\n\n\tdef _set_restrictions(self, default, specific={}):\n\t\tself.restrictions[-1] = TypeRestriction(default, specific)\n\n\t# ##\n\n\tdef visit_function_definition(self, node):\n\t\tself._set_restrictions(nodes.Block, {\n\t\t\tnode.arguments: nodes.IdentifiersList,\n\t\t\tnode.statements: nodes.StatementsList\n\t\t})\n\n\t# ##\n\n\tdef visit_table_constructor(self, node):\n\t\tself._set_restrictions(nodes.RecordsList)\n\n\tdef visit_array_record(self, node):\n\t\tself._set_restrictions(EXPRESSION_TYPES)\n\n\tdef visit_table_record(self, node):\n\t\tself._set_restrictions(EXPRESSION_TYPES)\n\n\t# ##\n\n\tdef visit_assignment(self, node):\n\t\tself._set_restrictions({\n\t\t\tnode.destinations: nodes.VariablesList,\n\t\t\tnode.expressions: nodes.ExpressionsList\n\t\t})\n\n\t\tif not isinstance(node.destinations.contents[0], nodes.Identifier):\n\t\t\treturn\n\n\t\tif node.destinations.contents[0].type != nodes.Identifier.T_LOCAL:\n\t\t\treturn\n\n\t\t# Don't test type flag here\n\t# ##\n\n\tdef visit_binary_operator(self, node):\n\t\tself._set_restrictions(EXPRESSION_TYPES)\n\n\t\tassert\tnode.type == nodes.BinaryOperator.T_LOGICAL_OR\t\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_LOGICAL_AND\t\\\n\t\t\t\t\t\t\t\t\t\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_LESS_THEN\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_GREATER_THEN\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_LESS_OR_EQUAL\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_GREATER_OR_EQUAL\t\\\n\t\t\t\t\t\t\t\t\t\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_NOT_EQUAL\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_EQUAL\t\t\\\n\t\t\t\t\t\t\t\t\t\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_CONCAT\t\t\\\n\t\t\t\t\t\t\t\t\t\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_ADD\t\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_SUBTRACT\t\t\\\n\t\t\t\t\t\t\t\t\t\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_MULTIPLY\t\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_DIVISION\t\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_MOD\t\t\\\n\t\t\t\t\t\t\t\t\t\t\\\n\t\t\tor node.type == nodes.BinaryOperator.T_POW\n\n\tdef visit_unary_operator(self, node):\n\t\tself._set_restrictions(EXPRESSION_TYPES)\n\n\t\tassert node.type == nodes.UnaryOperator.T_NOT\t\t\t\\\n\t\t\tor node.type == nodes.UnaryOperator.T_LENGTH_OPERATOR\t\\\n\t\t\tor node.type == nodes.UnaryOperator.T_MINUS\n\n\t# ##\n\n\tdef visit_statements_list(self, node):\n\t\tif self.warped:\n\t\t\ttypes = nodes.Block\n\t\telse:\n\t\t\ttypes = STATEMENT_TYPES\n\n\t\tself._set_restrictions(types)\n\n\tdef visit_identifiers_list(self, node):\n\t\t# HACK\n\t\tself._set_restrictions((nodes.Identifier, nodes.Vararg))\n\n\tdef visit_records_list(self, node):\n\t\tself._set_restrictions((nodes.TableRecord,\n\t\t\t\t\tnodes.ArrayRecord,\n\t\t\t\t\tnodes.FunctionCall,\n\t\t\t\t\tnodes.Vararg))\n\n\t\tif len(node.contents) == 0:\n\t\t\treturn\n\n\t\tis_array = isinstance(node.contents[0], nodes.ArrayRecord)\n\n\t\tfor i, x in enumerate(node.contents):\n\t\t\tif is_array:\n\t\t\t\tassert isinstance(x, nodes.ArrayRecord)\n\t\t\telif not isinstance(x, nodes.TableRecord):\n\t\t\t\tassert i == (len(node.contents) - 1)\n\n\tdef visit_variables_list(self, node):\n\t\tself._set_restrictions(VARIABLE_TYPES)\n\n\tdef visit_expressions_list(self, node):\n\t\tself._set_restrictions(EXPRESSION_TYPES)\n\n\t# ##\n\n\tdef visit_identifier(self, node):\n\t\tassert node.type == nodes.Identifier.T_SLOT\t\t\\\n\t\t\tor node.type == nodes.Identifier.T_BUILTIN\t\\\n\t\t\tor node.type == nodes.Identifier.T_UPVALUE\t\\\n\t\t\tor (node.name is not None\t\t\t\\\n\t\t\t\tand node.type == nodes.Identifier.T_LOCAL)\n\n\t\tassert node.type == nodes.Identifier.T_BUILTIN or node.slot >= 0\n\n\tdef visit_table_element(self, node):\n\t\tself._set_restrictions(EXPRESSION_TYPES)\n\n\tdef visit_function_call(self, node):\n\t\tself._set_restrictions({\n\t\t\tnode.function: VARIABLE_TYPES,\n\t\t\tnode.arguments: nodes.ExpressionsList\n\t\t})\n\n\t# ##\n\n\tdef visit_if(self, node):\n\t\tself._set_restrictions(nodes.ElseIf, {\n\t\t\tnode.expression: EXPRESSION_TYPES,\n\t\t\tnode.then_block: nodes.StatementsList,\n\t\t\tnode.else_block: nodes.StatementsList\n\t\t})\n\n\tdef visit_elseif(self, node):\n\t\tself._set_restrictions({\n\t\t\tnode.expression: EXPRESSION_TYPES,\n\t\t\tnode.then_block: nodes.StatementsList\n\t\t})\n\n\t# ##\n\n\tdef visit_block(self, node):\n\t\tself._set_restrictions(STATEMENT_TYPES, {\n\t\t\tnode.warp: WARP_TYPES\n\t\t})\n\n\t\tassert node.index >= 0\n\n\t\tassert node.first_address >= 0\t\t\t\\\n\t\t\tand node.first_address <= node.last_address\n\n\t\t# if false produce a statements without warps in\n\t\t# assert node.warpins_count > 0\n\n\tdef visit_unconditional_warp(self, node):\n\t\tassert node.target is not None\n\n\t\tassert node.type == nodes.UnconditionalWarp.T_JUMP\t\\\n\t\t\tor node.type == nodes.UnconditionalWarp.T_FLOW\n\n\tdef visit_conditional_warp(self, node):\n\t\tself._set_restrictions({\n\t\t\tnode.condition: EXPRESSION_TYPES\n\t\t})\n\n\t\tassert node.true_target is not None\n\t\tassert node.false_target is not None\n\n\t\t# It might happen in case of if blabla or true stuff\n\t\t# or in case of a = a and foo(a) or a type expression\n\t\t# assert node.true_target != node.false_target\n\t\t# assert node.true_target.index != node.false_target.index\n\n\tdef visit_iterator_warp(self, node):\n\t\tassert node.body is not None\n\t\tassert node.way_out is not None\n\n\t\tassert node.way_out.index > node.body.index\n\n\t\tself._set_restrictions(nodes.Block, {\n\t\t\tnode.variables: nodes.VariablesList,\n\t\t\tnode.controls: nodes.ExpressionsList\n\t\t})\n\n\tdef visit_numeric_loop_warp(self, node):\n\t\tassert node.body is not None\n\t\tassert node.way_out is not None\n\n\t\tself._set_restrictions(nodes.Block, {\n\t\t\tnode.index: nodes.Identifier,\n\t\t\tnode.controls: nodes.ExpressionsList\n\t\t})\n\n\t# ##\n\n\tdef visit_return(self, node):\n\t\tself._set_restrictions(nodes.ExpressionsList)\n\n\t# ##\n\n\tdef visit_while(self, node):\n\t\tself._set_restrictions({\n\t\t\tnode.expression: EXPRESSION_TYPES,\n\t\t\tnode.statements: nodes.StatementsList\n\t\t})\n\n\tdef visit_repeat_until(self, node):\n\t\tself._set_restrictions({\n\t\t\tnode.expression: EXPRESSION_TYPES,\n\t\t\tnode.statements: nodes.StatementsList\n\t\t})\n\n\tdef visit_numeric_for(self, node):\n\t\tself._set_restrictions({\n\t\t\tnode.expressions: nodes.ExpressionsList,\n\t\t\tnode.statements: nodes.StatementsList,\n\t\t\tnode.variable: VARIABLE_TYPES\n\t\t})\n\n\tdef visit_iterator_for(self, node):\n\t\tself._set_restrictions({\n\t\t\tnode.expressions: nodes.ExpressionsList,\n\t\t\tnode.identifiers: nodes.VariablesList,\n\t\t\tnode.statements: nodes.StatementsList\n\t\t})\n\n\t# ##\n\n\tdef visit_constant(self, node):\n\t\tassert\tnode.type == nodes.Constant.T_CDATA\t\t\\\n\t\t\tor node.type == nodes.Constant.T_FLOAT\t\t\\\n\t\t\tor node.type == nodes.Constant.T_INTEGER\t\\\n\t\t\tor node.type == nodes.Constant.T_STRING\n\n\tdef visit_primitive(self, node):\n\t\tassert\tnode.type == nodes.Primitive.T_NIL\t\t\\\n\t\t\tor node.type == nodes.Primitive.T_TRUE\t\t\\\n\t\t\tor node.type == nodes.Primitive.T_FALSE\n\n\t# ##\n\n\tdef _visit(self, node):\n\t\trestrictions = self.restrictions[-1]\n\n\t\tif restrictions is not None:\n\t\t\trestrictions.check(node)\n\n\t\t# Add layer for the child node\n\t\tself.restrictions.append(None)\n\n\t\ttraverse.Visitor._visit(self, node)\n\n\t\t# And pop it back\n\t\tself.restrictions.pop()\n\n\ndef validate(ast, warped=True):\n\tvisitor = Visitor(warped)\n\ttraverse.traverse(visitor, ast)\n"
  },
  {
    "path": "ljd/bytecode/__init__.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n"
  },
  {
    "path": "ljd/bytecode/constants.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nT_NIL = 0\nT_FALSE = 1\nT_TRUE = 2\n\n\nclass Table():\n\tdef __init__(self):\n\t\tself.array = []\n\n\t\t# Use a list so we can keep the original items order in the\n\t\t# table\n\t\tself.dictionary = []\n\n\nclass Constants():\n\tdef __init__(self):\n\t\tself.upvalue_references = []\n\t\tself.numeric_constants = []\n\t\tself.complex_constants = []\n"
  },
  {
    "path": "ljd/bytecode/debuginfo.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n\nclass VariableInfo():\n\tT_VISIBILE = 0\n\tT_INTERNAL = 1\n\n\tdef __init__(self):\n\t\tself.start_addr = 0\n\t\tself.end_addr = 0\n\t\tself.type = -1\n\t\tself.name = \"\"\n\n\nclass DebugInformation():\n\tdef __init__(self):\n\t\tself.addr_to_line_map = []\n\t\tself.upvalue_variable_names = []\n\t\tself.variable_info = []\n\n\tdef lookup_line_number(self, addr):\n\t\ttry:\n\t\t\treturn self.addr_to_line_map[addr]\n\t\texcept IndexError:\n\t\t\treturn 0\n\n\tdef lookup_local_name(self, addr, slot):\n\t\tfor info in self.variable_info:\n\t\t\tif info.start_addr > addr:\n\t\t\t\tbreak\n\t\t\tif info.end_addr <= addr:\n\t\t\t\tcontinue\n\t\t\telif slot == 0:\n\t\t\t\treturn info\n\t\t\telse:\n\t\t\t\tslot -= 1\n\n\t\treturn None\n\n\tdef lookup_upvalue_name(self, slot):\n\t\ttry:\n\t\t\treturn self.upvalue_variable_names[slot]\n\t\texcept IndexError:\n\t\t\treturn None\n"
  },
  {
    "path": "ljd/bytecode/helpers.py",
    "content": "def get_jump_destination(addr, instruction):\n\treturn addr + instruction.CD + 1\n\n\ndef set_jump_destination(addr, instruction, value):\n\tinstruction.CD = value - addr - 1\n"
  },
  {
    "path": "ljd/bytecode/instructions.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n#\n# Almost direct wiki-to-code from\n# http://wiki.luajit.org/Bytecode-2.0\n#\n\n\n# What the hell is an upvalue?\n# It is value from the upper prototype, i.e. a variable stored in a closure.\n\n# What the hell is the MULTRES thing?\n# The magical VM's variable that counts the CALL* or VARG returns.\n# I.e. it's used to speed-up things like foo(var1, var2, bar(var3, var4)) or\n#\n# function foo(...)\n# \tbla-bla\n# \tbar(...)\n#\n\n# Argument types\n\nT_VAR = 0  # variable slot number\nT_DST = 1  # variable slot number, used as a destination\n\nT_BS = 2  # base slot number, read-write\nT_RBS = 3  # base slot number, read-only\n\nT_UV = 4  # upvalue number (slot number, but specific to upvalues)\n\nT_LIT = 5  # literal\nT_SLIT = 6  # signed literal\n\nT_PRI = 7  # primitive type (0 = nil, 1 = false, 2 = true)\nT_NUM = 8  # numeric constant, index into constant table\nT_STR = 9  # string constant, negated index into constant table\n\nT_TAB = 10  # template table, negated index into constant table\nT_FUN = 11  # function prototype, negated index into constant table\nT_CDT = 12  # cdata constant, negated index into constant table\nT_JMP = 13  # branch target, relative to next instruction, biased with 0x8000\n\n\nclass _Instruction():\n\tdef __init__(self, definition):\n\t\tfor key, value in definition.__dict__.items():\n\t\t\tsetattr(self, key, value)\n\n\t\tif self.A_type is not None:\n\t\t\tself.A = 0\n\n\t\tif self.B_type is not None:\n\t\t\tself.B = 0\n\n\t\tif self.CD_type is not None:\n\t\t\tself.CD = 0\n\n\nclass _IDef():\n\t_LAST_OPCODE = 0\n\n\tdef __init__(self, name, A_type, B_type, CD_type, description):\n\t\tself.name = name\n\t\tself.opcode = _IDef._LAST_OPCODE\n\t\tself.A_type = A_type\n\t\tself.B_type = B_type\n\t\tself.CD_type = CD_type\n\t\tself.description = description\n\n\t\tself.args_count = (self.A_type is not None)\t\\\n\t\t\t\t+ (self.B_type is not None)\t\\\n\t\t\t\t+ (self.CD_type is not None)\n\n\t\t_IDef._LAST_OPCODE += 1\n\n\tdef __call__(self):\n\t\treturn _Instruction(self)\n\n\n# Names and order are in sync with luaJIT bytecode for ease of changing\n\n# class = name\t\t\tA\tB\tC\tdescription\n# Comparison ops\n\nISLT = _IDef(\"ISLT\", \t\tT_VAR, \tNone, \tT_VAR, \t\"if {A} < {D}\")\nISGE = _IDef(\"ISGE\", \t\tT_VAR, \tNone, \tT_VAR, \t\"if {A} >= {D}\")\nISLE = _IDef(\"ISLE\", \t\tT_VAR, \tNone, \tT_VAR, \t\"if {A} <= {D}\")\nISGT = _IDef(\"ISGT\", \t\tT_VAR, \tNone, \tT_VAR, \t\"if {A} > {D}\")\n\nISEQV = _IDef(\"ISEQV\", \t\tT_VAR, \tNone, \tT_VAR, \t\"if {A} == {D}\")\nISNEV = _IDef(\"ISNEV\", \t\tT_VAR, \tNone, \tT_VAR, \t\"if {A} ~= {D}\")\n\nISEQS = _IDef(\"ISEQS\", \t\tT_VAR, \tNone, \tT_STR, \t\"if {A} == {D}\")\nISNES = _IDef(\"ISNES\", \t\tT_VAR, \tNone, \tT_STR, \t\"if {A} ~= {D}\")\n\nISEQN = _IDef(\"ISEQN\", \t\tT_VAR, \tNone, \tT_NUM, \t\"if {A} == {D}\")\nISNEN = _IDef(\"ISNEN\", \t\tT_VAR, \tNone, \tT_NUM, \t\"if {A} ~= {D}\")\n\nISEQP = _IDef(\"ISEQP\", \t\tT_VAR, \tNone, \tT_PRI, \t\"if {A} == {D}\")\nISNEP = _IDef(\"ISNEP\", \t\tT_VAR, \tNone, \tT_PRI, \t\"if {A} ~= {D}\")\n\n# Unary test and copy ops\n\nISTC = _IDef(\"ISTC\", \t\tT_DST, \tNone, \tT_VAR, \t\"{A} = {D}; if {D}\")\nISFC = _IDef(\"ISFC\", \t\tT_DST, \tNone, \tT_VAR, \t\"{A} = {D}; if not {D}\")\n\nIST = _IDef(\"IST\", \t\tNone, \tNone, \tT_VAR, \t\"if {D}\")\nISF = _IDef(\"ISF\", \t\tNone, \tNone, \tT_VAR, \t\"if not {D}\")\n\nISTYPE = _IDef(\"ISTYPE\", \tT_VAR, \tNone, \tT_LIT, \t\"ISTYPE unknow\")\nISNUM = _IDef(\"ISNUM\", \t\tT_VAR, \tNone, \tT_LIT, \t\"ISNUM unknow\")\n# Unary ops\n\nMOV = _IDef(\"MOV\", \t\tT_DST, \tNone, \tT_VAR, \t\"{A} = {D}\")\nNOT = _IDef(\"NOT\", \t\tT_DST, \tNone, \tT_VAR, \t\"{A} = not {D}\")\nUNM = _IDef(\"UNM\", \t\tT_DST, \tNone, \tT_VAR, \t\"{A} = -{D}\")\nLEN = _IDef(\"LEN\", \t\tT_DST, \tNone, \tT_VAR, \t\"{A} = #{D}\")\n\n# Binary ops\n\nADDVN = _IDef(\"ADDVN\", \t\tT_DST, \tT_VAR, \tT_NUM, \t\"{A} = {B} + {C}\")\nSUBVN = _IDef(\"SUBVN\", \t\tT_DST, \tT_VAR, \tT_NUM, \t\"{A} = {B} - {C}\")\nMULVN = _IDef(\"MULVN\", \t\tT_DST, \tT_VAR, \tT_NUM, \t\"{A} = {B} * {C}\")\nDIVVN = _IDef(\"DIVVN\", \t\tT_DST, \tT_VAR, \tT_NUM, \t\"{A} = {B} / {C}\")\nMODVN = _IDef(\"MODVN\", \t\tT_DST, \tT_VAR, \tT_NUM, \t\"{A} = {B} % {C}\")\n\nADDNV = _IDef(\"ADDNV\", \t\tT_DST, \tT_VAR, \tT_NUM, \t\"{A} = {C} + {B}\")\nSUBNV = _IDef(\"SUBNV\", \t\tT_DST, \tT_VAR, \tT_NUM, \t\"{A} = {C} - {B}\")\nMULNV = _IDef(\"MULNV\", \t\tT_DST, \tT_VAR, \tT_NUM, \t\"{A} = {C} * {B}\")\nDIVNV = _IDef(\"DIVNV\", \t\tT_DST, \tT_VAR, \tT_NUM, \t\"{A} = {C} / {B}\")\nMODNV = _IDef(\"MODNV\", \t\tT_DST, \tT_VAR, \tT_NUM, \t\"{A} = {C} % {B}\")\n\nADDVV = _IDef(\"ADDVV\", \t\tT_DST, \tT_VAR, \tT_VAR, \t\"{A} = {B} + {C}\")\nSUBVV = _IDef(\"SUBVV\", \t\tT_DST, \tT_VAR, \tT_VAR, \t\"{A} = {B} - {C}\")\nMULVV = _IDef(\"MULVV\", \t\tT_DST, \tT_VAR, \tT_VAR, \t\"{A} = {B} * {C}\")\nDIVVV = _IDef(\"DIVVV\", \t\tT_DST, \tT_VAR, \tT_VAR, \t\"{A} = {B} / {C}\")\nMODVV = _IDef(\"MODVV\", \t\tT_DST, \tT_VAR, \tT_VAR, \t\"{A} = {B} % {C}\")\n\nPOW = _IDef(\"POW\", \t\tT_DST, \tT_VAR, \tT_VAR, \t\"{A} = {B} ^ {C} (pow)\")\nCAT = _IDef(\"CAT\", \t\tT_DST, \tT_RBS, \tT_RBS,\n\t\t\"{A} = {concat_from_B_to_C}\")\n\n# Constant ops.\n\nKSTR = _IDef(\"KSTR\", \t\tT_DST, \tNone, \tT_STR, \t\"{A} = {D}\")\nKCDATA = _IDef(\"KCDATA\", \tT_DST, \tNone, \tT_CDT, \t\"{A} = {D}\")\nKSHORT = _IDef(\"KSHORT\", \tT_DST, \tNone, \tT_SLIT, \"{A} = {D}\")\nKNUM = _IDef(\"KNUM\", \t\tT_DST, \tNone, \tT_NUM, \t\"{A} = {D}\")\nKPRI = _IDef(\"KPRI\", \t\tT_DST, \tNone, \tT_PRI, \t\"{A} = {D}\")\n\nKNIL = _IDef(\"KNIL\", \t\tT_BS, \tNone, \tT_BS, \t\"{from_A_to_D} = nil\")\n\n# Upvalue and function ops.\n\nUGET = _IDef(\"UGET\", \t\tT_DST, \tNone, \tT_UV, \t\"{A} = {D}\")\n\nUSETV = _IDef(\"USETV\", \t\tT_UV, \tNone, \tT_VAR, \t\"{A} = {D}\")\nUSETS = _IDef(\"USETS\", \t\tT_UV, \tNone, \tT_STR, \t\"{A} = {D}\")\nUSETN = _IDef(\"USETN\", \t\tT_UV, \tNone, \tT_NUM, \t\"{A} = {D}\")\nUSETP = _IDef(\"USETP\", \t\tT_UV, \tNone, \tT_PRI, \t\"{A} = {D}\")\n\nUCLO = _IDef(\"UCLO\", \t\tT_RBS, \tNone, \tT_JMP,\n\t\t\"nil uvs >= {A}; goto {D}\")\n\nFNEW = _IDef(\"FNEW\", \t\tT_DST, \tNone, \tT_FUN, \t\"{A} = function {D}\")\n\n# Table ops.\n\nTNEW = _IDef(\"TNEW\", \t\tT_DST, \tNone, \tT_LIT, \t\"{A} = new table(\"\n\t\t\t\t\t\t\t\" array: {D_array},\"\n\t\t\t\t\t\t\t\" dict: {D_dict})\")\n\nTDUP = _IDef(\"TDUP\", \t\tT_DST, \tNone, \tT_TAB, \t\"{A} = copy {D}\")\n\nGGET = _IDef(\"GGET\", \t\tT_DST, \tNone, \tT_STR, \t\"{A} = _env[{D}]\")\nGSET = _IDef(\"GSET\", \t\tT_VAR, \tNone, \tT_STR, \t\"_env[{D}] = {A}\")\n\nTGETV = _IDef(\"TGETV\", \t\tT_DST, \tT_VAR, \tT_VAR, \t\"{A} = {B}[{C}]\")\nTGETS = _IDef(\"TGETS\", \t\tT_DST, \tT_VAR, \tT_STR, \t\"{A} = {B}.{C}\")\nTGETB = _IDef(\"TGETB\", \t\tT_DST, \tT_VAR, \tT_LIT, \t\"{A} = {B}[{C}]\")\nTGETR = _IDef(\"TGETR\", \t\tT_DST, \tT_VAR, \tT_VAR, \t\"unkown TGETR\")\n\nTSETV = _IDef(\"TSETV\", \t\tT_VAR, \tT_VAR, \tT_VAR, \t\"{B}[{C}] = {A}\")\nTSETS = _IDef(\"TSETS\", \t\tT_VAR, \tT_VAR, \tT_STR, \t\"{B}.{C} = {A}\")\nTSETB = _IDef(\"TSETB\", \t\tT_VAR, \tT_VAR, \tT_LIT, \t\"{B}[{C}] = {A}\")\n\nTSETM = _IDef(\"TSETM\", \t \tT_BS, \tNone, \tT_NUM,\n\t\t\"for i = 0, MULTRES, 1 do\"\n\t\t\" {A_minus_one}[{D_low} + i] = slot({A} + i)\")\n\nTSETR = _IDef(\"TSETR\", \t\tT_VAR, \tT_VAR, \tT_VAR, \t\"unkow TSETR\")\n# Calls and vararg handling. T = tail call.\n\nCALLM = _IDef(\"CALLM\", \t\tT_BS, \tT_LIT, \tT_LIT,\n\t\t\"{from_A_x_B_minus_two} = {A}({from_A_plus_one_x_C}, ...MULTRES)\")\n\nCALL = _IDef(\"CALL\", \t\tT_BS, \tT_LIT, \tT_LIT,\n\t\t\"{from_A_x_B_minus_two} = {A}({from_A_plus_one_x_C_minus_one})\")\n\nCALLMT = _IDef(\"CALLMT\", \tT_BS, \tNone, \tT_LIT,\n\t\t\"return {A}({from_A_plus_one_x_D}, ...MULTRES)\")\n\nCALLT = _IDef(\"CALLT\", \t\tT_BS, \tNone, \tT_LIT,\n\t\t\"return {A}({from_A_plus_one_x_D_minus_one})\")\n\nITERC = _IDef(\"ITERC\", \t\tT_BS, \tT_LIT, \tT_LIT,\n\t\t\"{A}, {A_plus_one}, {A_plus_two} =\"\n\t\t\t\" {A_minus_three}, {A_minus_two}, {A_minus_one};\"\n\t\t\" {from_A_x_B_minus_two} =\"\n\t\t\t\" {A_minus_three}({A_minus_two}, {A_minus_one})\")\n\nITERN = _IDef(\"ITERN\", \t\tT_BS, \tT_LIT, \tT_LIT,\n\t\t\"{A}, {A_plus_one}, {A_plus_two} =\"\n\t\t\t\" {A_minus_three}, {A_minus_two}, {A_minus_one};\"\n\t\t\" {from_A_x_B_minus_two} =\"\n\t\t\t\" {A_minus_three}({A_minus_two}, {A_minus_one})\")\n\nVARG = _IDef(\"VARG\", \t\tT_BS, \tT_LIT, \tT_LIT,\n\t\t\"{from_A_x_B_minus_two} = ...\")\n\nISNEXT = _IDef(\"ISNEXT\", \t T_BS, \tNone, \tT_JMP,\n\t\t\"Verify ITERN at {D}; goto {D}\")\n\n# Returns.\n\nRETM = _IDef(\"RETM\", \t\tT_BS, \tNone, \tT_LIT,\n\t\t\"return {from_A_x_D_minus_one}, ...MULTRES\")\n\nRET = _IDef(\"RET\", \t \tT_RBS, \tNone, \tT_LIT,\n\t\t\"return {from_A_x_D_minus_two}\")\n\nRET0 = _IDef(\"RET0\", \t\tT_RBS, \tNone, \tT_LIT, \t\"return\")\nRET1 = _IDef(\"RET1\", \t\tT_RBS, \tNone, \tT_LIT, \t\"return {A}\")\n\n# Loops and branches. I/J = interp/JIT, I/C/L = init/call/loop.\n\nFORI = _IDef(\"FORI\", \t\tT_BS, \tNone, \tT_JMP,\n\t\t\"for {A_plus_three} = {A},{A_plus_one},{A_plus_two}\"\n\t\t\" else goto {D}\")\n\nJFORI = _IDef(\"JFORI\", \t\tT_BS, \tNone, \tT_JMP,\n\t\t\"for {A_plus_three} = {A},{A_plus_one},{A_plus_two}\"\n\t\t\" else goto {D}\")\n\nFORL = _IDef(\"FORL\", \t\tT_BS, \tNone, \tT_JMP,\n\t\t\"{A} = {A} + {A_plus_two};\"\n\t\t\" if cmp({A}, sign {A_plus_two},  {A_plus_one}) goto {D}\")\n\nIFORL = _IDef(\"IFORL\", \t \tT_BS, \tNone, \tT_JMP,\n\t\t\"{A} = {A} + {A_plus_two};\"\n\t\t\" if cmp({A}, sign {A_plus_two}, {A_plus_one}) goto {D}\")\n\nJFORL = _IDef(\"JFORL\", \t\tT_BS, \tNone, \tT_JMP,\n\t\t\"{A} = {A} + {A_plus_two};\"\n\t\t\" if cmp({A}, sign {A_plus_two}, {A_plus_one}) goto {D}\")\n\nITERL = _IDef(\"ITERL\", \t\tT_BS, \tNone, \tT_JMP,\n\t\t\"{A_minus_one} = {A}; if {A} != nil goto {D}\")\n\nIITERL = _IDef(\"IITERL\", \tT_BS, \tNone, \tT_JMP,\n\t\t\"{A_minus_one} = {A}; if {A} != nil goto {D}\")\n\nJITERL = _IDef(\"JITERL\", \tT_BS, \tNone, \tT_LIT,\n\t\t\"{A_minus_one} = {A}; if {A} != nil goto {D}\")\n\nLOOP = _IDef(\"LOOP\", \t\tT_RBS, \tNone, \tT_JMP, \t\"Noop\")\nILOOP = _IDef(\"ILOOP\", \t\tT_RBS, \tNone, \tT_JMP, \t\"Noop\")\nJLOOP = _IDef(\"JLOOP\", \t\tT_RBS, \tNone, \tT_LIT, \t\"Noop\")\n\nJMP = _IDef(\"JMP\", \t\tT_RBS, \tNone, \tT_JMP, \t\"\tgoto {D}\")\n\n# Function headers. I/J = interp/JIT, F/V/C = fixarg/vararg/C func.\n# Shouldn't be ever seen - they are not stored in raw dump?\n\nFUNCF = _IDef(\"FUNCF\", \t\tT_RBS, \tNone, \tNone,\n\t\t\"Fixed-arg function with frame size {A}\")\n\nIFUNCF = _IDef(\"IFUNCF\", \tT_RBS, \tNone, \tNone,\n\t\t\"Interpreted fixed-arg function with frame size {A}\")\n\nJFUNCF = _IDef(\"JFUNCF\", \tT_RBS, \tNone, \tT_LIT,\n\t\t\"JIT compiled fixed-arg function with frame size {A}\")\n\nFUNCV = _IDef(\"FUNCV\", \t\tT_RBS, \tNone, \tNone,\n\t\t\"Var-arg function with frame size {A}\")\n\nIFUNCV = _IDef(\"IFUNCV\", \tT_RBS, \tNone, \tNone,\n\t\t\"Interpreted var-arg function with frame size {A}\")\n\nJFUNCV = _IDef(\"JFUNCV\", \tT_RBS, \tNone, \tT_LIT,\n\t\t\"JIT compiled var-arg function with frame size {A}\")\n\nFUNCC = _IDef(\"FUNCC\", \t\tT_RBS, \tNone, \tNone,\n\t\t\"C function with frame size {A}\")\nFUNCCW = _IDef(\"FUNCCW\", \tT_RBS, \tNone, \tNone,\n\t\t\"Wrapped C function with frame size {A}\")\n\nUNKNW = _IDef(\"UNKNW\", \t\tT_LIT, \tT_LIT, \tT_LIT, \"Unknown instruction\")\n"
  },
  {
    "path": "ljd/bytecode/prototype.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport ljd.bytecode.constants as constants\nimport ljd.bytecode.debuginfo as debug\n\n\nclass Flags():\n\tdef __init(self):\n\t\tself.has_sub_prototypes = False\n\t\tself.is_variadic = False\n\t\tself.has_ffi = False\n\t\tself.has_jit = True\n\t\tself.has_iloop = False\n\n\nclass Prototype():\n\tdef __init__(self):\n\t\tself.flags = Flags()\n\n\t\tself.arguments_count = 0\n\n\t\tself.framesize = 0\n\n\t\tself.first_line_number = 0\n\t\tself.lines_count = 0\n\n\t\tself.instructions = []\n\t\tself.constants = constants.Constants()\n\t\tself.debuginfo = debug.DebugInformation()\n"
  },
  {
    "path": "ljd/lua/__init__.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n"
  },
  {
    "path": "ljd/lua/writer.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport re\n\nimport ljd.ast.nodes as nodes\nimport ljd.ast.traverse as traverse\n\n\nCMD_START_STATEMENT = 0\nCMD_END_STATEMENT = 1\nCMD_END_LINE = 3\nCMD_START_BLOCK = 4\nCMD_END_BLOCK = 5\nCMD_WRITE = 6\n\n\nOPERATOR_TYPES = (nodes.BinaryOperator, nodes.UnaryOperator)\n\nSTATEMENT_NONE = -1\n\nSTATEMENT_ASSIGNMENT = 0\nSTATEMENT_FUNCTION_CALL = 1\nSTATEMENT_RETURN = 2\nSTATEMENT_BREAK = 3\n\nSTATEMENT_IF = 4\n\nSTATEMENT_ITERATOR_FOR = 5\nSTATEMENT_NUMERIC_FOR = 6\nSTATEMENT_REPEAT_UNTIL = 7\nSTATEMENT_WHILE = 8\n\nSTATEMENT_FUNCTION = 9\n\nVALID_IDENTIFIER = re.compile(r'^\\w[\\w\\d]*$')\n\n\nclass _State():\n\tdef __init__(self):\n\t\tself.current_statement = STATEMENT_NONE\n\t\tself.function_name = None\n\t\tself.function_local = False\n\n\nclass Visitor(traverse.Visitor):\n\tdef __init__(self):\n\t\ttraverse.Visitor.__init__(self)\n\n\t\tself.print_queue = []\n\n\t\tself._visited_nodes = [set()]\n\t\tself._states = [_State()]\n\n\t# ##\n\n\tdef _start_statement(self, statement):\n\t\tassert self._state().current_statement == STATEMENT_NONE\n\t\tself._state().current_statement = statement\n\t\tself.print_queue.append((CMD_START_STATEMENT, statement))\n\n\tdef _end_statement(self, statement):\n\t\tassert statement == self._state().current_statement\n\t\tself._state().current_statement = STATEMENT_NONE\n\t\tself.print_queue.append((CMD_END_STATEMENT, statement))\n\n\tdef _end_line(self):\n\t\tself.print_queue.append((CMD_END_LINE,))\n\n\tdef _start_block(self):\n\t\tself.print_queue.append((CMD_START_BLOCK,))\n\n\tdef _end_block(self):\n\t\tself.print_queue.append((CMD_END_BLOCK,))\n\n\tdef _write(self, fmt, *args, **kargs):\n\t\tself.print_queue.append((CMD_WRITE, fmt, args, kargs))\n\n\tdef _state(self):\n\t\treturn self._states[-1]\n\n\tdef _push_state(self):\n\t\treturn self._states.append(_State())\n\n\tdef _pop_state(self):\n\t\treturn self._states.pop()\n\n\t# ##\n\n\tdef visit_function_definition(self, node):\n\t\tis_statement = self._state().function_name is not None\n\n\t\tif is_statement:\n\t\t\tself._start_statement(STATEMENT_FUNCTION)\n\n\t\t\tif self._state().function_local:\n\t\t\t\tself._write(\"local \")\n\n\t\t\tself._write(\"function \")\n\n\t\t\tself._visit(self._state().function_name)\n\n\t\t\tself._write(\"(\")\n\n\t\t\tself._state().function_name = None\n\t\telse:\n\t\t\tself._write(\"function (\")\n\n\t\tself._visit(node.arguments)\n\n\t\tself._write(\")\")\n\n\t\tself._end_line()\n\n\t\tself._visit(node.statements)\n\n\t\tself._write(\"end\")\n\n\t\tif is_statement:\n\t\t\tself._end_statement(STATEMENT_FUNCTION)\n\n\t# ##\n\n\tdef visit_table_constructor(self, node):\n\t\tself._write(\"{\")\n\n\t\tif len(node.records.contents) + len(node.array.contents) > 0:\n\t\t\tself._end_line()\n\n\t\t\tself._start_block()\n\n\t\t\tarray = node.array.contents\n\t\t\trecords = node.records.contents\n\n\t\t\tall_records = nodes.RecordsList()\n\t\t\tall_records.contents = array + records\n\n\t\t\tif len(array) > 0:\n\t\t\t\tfirst = array[0].value\n\n\t\t\t\tall_records.contents.pop(0)\n\n\t\t\t\tif not isinstance(first, nodes.Primitive) \\\n\t\t\t\t\t\tor first.type != first.T_NIL:\n\t\t\t\t\trecord = nodes.TableRecord()\n\t\t\t\t\trecord.key = nodes.Constant()\n\t\t\t\t\trecord.key.type = nodes.Constant.T_INTEGER\n\t\t\t\t\trecord.key.value = 0\n\t\t\t\t\trecord.value = first\n\n\t\t\t\t\tall_records.contents.insert(0, record)\n\n\t\t\tself._visit(all_records)\n\n\t\t\tself._skip(node.array)\n\t\t\tself._skip(node.records)\n\n\t\t\tself._end_block()\n\t\telse:\n\t\t\tself._skip(node.array)\n\t\t\tself._skip(node.records)\n\n\t\tself._write(\"}\")\n\n\tdef visit_table_record(self, node):\n\t\tif self._is_valid_name(node.key):\n\t\t\tself._write(node.key.value)\n\n\t\t\tself._skip(node.key)\n\n\t\t\tself._write(\" = \")\n\t\telse:\n\t\t\tself._write(\"[\")\n\n\t\t\tself._visit(node.key)\n\n\t\t\tself._write(\"] = \")\n\n\t\tself._visit(node.value)\n\n\t# visit_array_record is a passthough\n\n\t# ##\n\n\tdef visit_assignment(self, node):\n\t\tis_local = node.type == node.T_LOCAL_DEFINITION\n\n\t\tdsts = node.destinations.contents\n\t\tsrcs = node.expressions.contents\n\n\t\tif len(dsts) == 1 and len(srcs) == 1:\n\t\t\tdst = dsts[0]\n\t\t\tsrc = srcs[0]\n\n\t\t\tsrc_is_function = isinstance(src, nodes.FunctionDefinition)\n\t\t\tdst_is_simple = self._is_variable(dst)\n\n\t\t\tif src_is_function and dst_is_simple:\n\t\t\t\tself._state().function_name = dst\n\t\t\t\tself._state().function_local = is_local\n\n\t\t\t\tself._visit(src)\n\n\t\t\t\tself._skip(node.destinations)\n\t\t\t\tself._skip(node.expressions)\n\n\t\t\t\treturn\n\n\t\tif is_local:\n\t\t\tself._write(\"local \")\n\n\t\tself._start_statement(STATEMENT_ASSIGNMENT)\n\n\t\tself._visit(node.destinations)\n\n\t\tself._write(\" = \")\n\n\t\tself._visit(node.expressions)\n\n\t\tself._end_statement(STATEMENT_ASSIGNMENT)\n\n\tdef _is_variable(self, node):\n\t\tif isinstance(node, nodes.Identifier):\n\t\t\treturn True\n\n\t\treturn self._is_global(node)\n\n\tdef _is_global(self, node):\n\t\tif isinstance(node, nodes.TableElement):\n\t\t\treturn self._is_builtin(node.table)\n\n\t\treturn False\n\n\tdef _is_builtin(self, node):\n\t\tif not isinstance(node, nodes.Identifier):\n\t\t\treturn False\n\n\t\treturn node.type == nodes.Identifier.T_BUILTIN\n\n\tdef _is_valid_name(self, key):\n\t\tif not isinstance(key, nodes.Constant) or key.type != key.T_STRING:\n\t\t\treturn False\n\n\t\treturn VALID_IDENTIFIER.match(key.value)\n\n\t# ##\n\n\tdef visit_binary_operator(self, node):\n\t\tis_left_op = isinstance(node.left, OPERATOR_TYPES)\n\t\tis_right_op = isinstance(node.right, OPERATOR_TYPES)\n\n\t\t# If the subexpressions are less in order then this expression,\n\t\t# they should go with parentheses\n\n\t\tleft_parentheses = False\n\t\tright_parentheses = False\n\n\t\tbinop = nodes.BinaryOperator\n\n\t\tif is_left_op:\n\t\t\tif node.type <= binop.T_LOGICAL_AND:\n\t\t\t\tleft_parentheses = (\n\t\t\t\t\tnode.left.type <= node.type\n\t\t\t\t\tor (node.left.type <= binop.T_LOGICAL_AND\n\t\t\t\t\t\tand node.type <= binop.T_LOGICAL_AND)\n\t\t\t\t) and node.left.type != node.type\n\t\t\telse:\n\t\t\t\tleft_parentheses = node.left.type < node.type\n\n\t\tif is_right_op:\n\t\t\tif node.type <= nodes.BinaryOperator.T_LOGICAL_AND:\n\t\t\t\tright_parentheses = (\n\t\t\t\t\tnode.right.type <= node.type\n\t\t\t\t\tor (node.right.type <= binop.T_LOGICAL_AND\n\t\t\t\t\t\tand node.type <= binop.T_LOGICAL_AND)\n\t\t\t\t) and node.right.type != node.type\n\t\t\telse:\n\t\t\t\tright_parentheses = node.right.type < node.type\n\n\t\tif left_parentheses:\n\t\t\tself._write(\"(\")\n\n\t\tself._visit(node.left)\n\n\t\tif left_parentheses:\n\t\t\tself._write(\")\")\n\n\t\tif node.type == nodes.BinaryOperator.T_LOGICAL_OR:\n\t\t\tself._write(\" or \")\n\t\telif node.type == nodes.BinaryOperator.T_LOGICAL_AND:\n\t\t\tself._write(\" and \")\n\n\t\telif node.type == nodes.BinaryOperator.T_LESS_THEN:\n\t\t\tself._write(\" < \")\n\t\telif node.type == nodes.BinaryOperator.T_GREATER_THEN:\n\t\t\tself._write(\" > \")\n\t\telif node.type == nodes.BinaryOperator.T_LESS_OR_EQUAL:\n\t\t\tself._write(\" <= \")\n\t\telif node.type == nodes.BinaryOperator.T_GREATER_OR_EQUAL:\n\t\t\tself._write(\" >= \")\n\n\t\telif node.type == nodes.BinaryOperator.T_NOT_EQUAL:\n\t\t\tself._write(\" ~= \")\n\t\telif node.type == nodes.BinaryOperator.T_EQUAL:\n\t\t\tself._write(\" == \")\n\n\t\telif node.type == nodes.BinaryOperator.T_CONCAT:\n\t\t\tself._write(\" .. \")\n\n\t\telif node.type == nodes.BinaryOperator.T_ADD:\n\t\t\tself._write(\" + \")\n\t\telif node.type == nodes.BinaryOperator.T_SUBTRACT:\n\t\t\tself._write(\" - \")\n\n\t\telif node.type == nodes.BinaryOperator.T_DIVISION:\n\t\t\tself._write(\"/\")\n\t\telif node.type == nodes.BinaryOperator.T_MULTIPLY:\n\t\t\tself._write(\"*\")\n\t\telif node.type == nodes.BinaryOperator.T_MOD:\n\t\t\tself._write(\"%\")\n\n\t\telse:\n\t\t\tassert node.type == nodes.BinaryOperator.T_POW\n\t\t\tself._write(\"^\")\n\n\t\tif right_parentheses:\n\t\t\tself._write(\"(\")\n\n\t\tself._visit(node.right)\n\n\t\tif right_parentheses:\n\t\t\tself._write(\")\")\n\n\tdef visit_unary_operator(self, node):\n\t\tif node.type == nodes.UnaryOperator.T_LENGTH_OPERATOR:\n\t\t\tself._write(\"#\")\n\t\telif node.type == nodes.UnaryOperator.T_MINUS:\n\t\t\tself._write(\"-\")\n\t\telif node.type == nodes.UnaryOperator.T_NOT:\n\t\t\tself._write(\"not \")\n\n\t\thas_subexp = isinstance(node.operand, OPERATOR_TYPES)\n\t\tneed_parentheses = has_subexp and node.operand.type < node.type\n\n\t\tif need_parentheses:\n\t\t\tself._write(\"(\")\n\n\t\tself._visit(node.operand)\n\n\t\tif need_parentheses:\n\t\t\tself._write(\")\")\n\n\t# ##\n\n\tdef visit_statements_list(self, node):\n\t\tif len(self._states) > 1:\n\t\t\tself._start_block()\n\n\t\tself._push_state()\n\n\tdef leave_statements_list(self, node):\n\t\tself._pop_state()\n\n\t\tif len(self._states) > 1:\n\t\t\tself._end_block()\n\n\tdef _visit_comma_separated_list(self, node):\n\t\tif node.contents == []:\n\t\t\treturn\n\n\t\tfor subnode in node.contents[:-1]:\n\t\t\tself._visit(subnode)\n\t\t\tself._write(\", \")\n\n\t\tself._visit(node.contents[-1])\n\n\tvisit_identifiers_list = _visit_comma_separated_list\n\n\tdef visit_records_list(self, node):\n\t\tif node.contents == []:\n\t\t\treturn\n\n\t\tfor subnode in node.contents[:-1]:\n\t\t\tself._visit(subnode)\n\n\t\t\tself._write(\",\")\n\t\t\tself._end_line()\n\n\t\tself._visit(node.contents[-1])\n\t\tself._end_line()\n\n\tvisit_variables_list = _visit_comma_separated_list\n\tvisit_expressions_list = _visit_comma_separated_list\n\n\t# ##\n\n\tdef visit_identifier(self, node):\n\t\tif node.type == nodes.Identifier.T_SLOT:\n\t\t\tself._write(\"slot{0}\", node.slot)\n\t\telse:\n\t\t\tself._write(node.name)\n\n\tdef visit_multres(self, node):\n\t\tself._write(\"MULTRES\")\n\n\tdef visit_table_element(self, node):\n\t\tkey = node.key\n\t\tbase = node.table\n\n\t\tis_valid_name = self._is_valid_name(key)\n\n\t\tif self._is_global(node):\n\t\t\tassert is_valid_name\n\n\t\t\tself._skip(base)\n\t\t\tself._skip(key)\n\n\t\t\tself._write(key.value)\n\n\t\t\treturn\n\n\t\tbase_is_constructor = isinstance(base, nodes.TableConstructor)\n\n\t\tif not base_is_constructor and is_valid_name:\n\t\t\tself._visit(base)\n\t\t\tself._write(\".\")\n\n\t\t\tself._write(key.value)\n\t\t\tself._skip(key)\n\t\telse:\n\t\t\tif base_is_constructor:\n\t\t\t\tself._write(\"(\")\n\n\t\t\tself._visit(base)\n\n\t\t\tif base_is_constructor:\n\t\t\t\tself._write(\")\")\n\n\t\t\tself._write(\"[\")\n\n\t\t\tself._visit(key)\n\n\t\t\tself._write(\"]\")\n\n\tdef visit_vararg(self, node):\n\t\tself._write(\"...\")\n\n\tdef visit_function_call(self, node):\n\t\tis_statement = self._state().current_statement == STATEMENT_NONE\n\n\t\tif is_statement:\n\t\t\tself._start_statement(STATEMENT_FUNCTION_CALL)\n\n\t\t# We are going to modify this list so we can remove the first\n\t\t# argument\n\t\targs = node.arguments.contents\n\t\tis_method = False\n\n\t\tif len(args) > 0 and isinstance(node.function, nodes.TableElement):\n\t\t\ttable = node.function.table\n\n\t\t\tfirst_arg = node.arguments.contents[0]\n\n\t\t\tif self._is_valid_name(node.function.key):\n\t\t\t\tis_method = table == first_arg\n\n\t\tif is_method:\n\t\t\tself._visit(node.function.table)\n\t\t\tself._write(\":\")\n\t\t\tself._write(node.function.key.value)\n\n\t\t\tself._skip(node.function)\n\n\t\t\targs.pop(0)\n\n\t\t\tself._write(\"(\")\n\t\t\tself._visit(node.arguments)\n\t\t\tself._write(\")\")\n\n\t\t\tself._skip(node.arguments)\n\t\telse:\n\t\t\tself._visit(node.function)\n\n\t\t\tself._write(\"(\")\n\t\t\tself._visit(node.arguments)\n\t\t\tself._write(\")\")\n\n\t\tif is_statement:\n\t\t\tself._end_statement(STATEMENT_FUNCTION_CALL)\n\n\t# ##\n\n\tdef visit_if(self, node):\n\t\tself._start_statement(STATEMENT_IF)\n\n\t\tself._write(\"if \")\n\n\t\tself._visit(node.expression)\n\n\t\tself._write(\" then\")\n\n\t\tself._end_line()\n\n\t\tself._visit(node.then_block)\n\n\t\tself._visit_list(node.elseifs)\n\n\t\tif len(node.else_block.contents) > 0:\n\t\t\tself._write(\"else\")\n\n\t\t\tself._end_line()\n\n\t\t\tself._visit(node.else_block)\n\t\telse:\n\t\t\tself._skip(node.else_block)\n\n\t\tself._write(\"end\")\n\n\t\tself._end_statement(STATEMENT_IF)\n\n\tdef visit_elseif(self, node):\n\t\tself._write(\"elseif \")\n\n\t\tself._visit(node.expression)\n\n\t\tself._write(\" then\")\n\n\t\tself._end_line()\n\n\t\tself._visit(node.then_block)\n\n\t# ##\n\n\tdef visit_block(self, node):\n\t\tself._write(\"--- BLOCK #{0} {1}-{2}, warpins: {3} ---\",\n\t\t\t\t\tnode.index,\n\t\t\t\t\tnode.first_address, node.last_address,\n\t\t\t\t\tnode.warpins_count)\n\n\t\tself._end_line()\n\n\t\tself._visit_list(node.contents)\n\n\t\tself._write(\"--- END OF BLOCK #{0} ---\", node.index)\n\n\t\tself._end_line()\n\n\t\tself._end_line()\n\t\tself._visit(node.warp)\n\t\tself._end_line()\n\n\t\tself._end_line()\n\n\tdef visit_unconditional_warp(self, node):\n\t\tif node.type == nodes.UnconditionalWarp.T_FLOW:\n\t\t\tself._write(\"FLOW\")\n\t\telif node.type == nodes.UnconditionalWarp.T_JUMP:\n\t\t\tself._write(\"UNCONDITIONAL JUMP\")\n\n\t\tself._write(\"; TARGET BLOCK #{0}\", node.target.index)\n\n\t\tself._end_line()\n\n\tdef visit_conditional_warp(self, node):\n\t\tif hasattr(node, \"_slot\"):\n\t\t\tself._write(\"slot\" + str(node._slot))\n\t\t\tself._write(\" = \")\n\n\t\tself._write(\"if \")\n\n\t\tself._visit(node.condition)\n\n\t\tself._write(\" then\")\n\t\tself._end_line()\n\n\t\tself._write(\"JUMP TO BLOCK #{0}\", node.true_target.index)\n\n\t\tself._end_line()\n\t\tself._write(\"else\")\n\t\tself._end_line()\n\n\t\tself._write(\"JUMP TO BLOCK #{0}\", node.false_target.index)\n\n\t\tself._end_line()\n\n\t\tself._write(\"end\")\n\t\tself._end_line()\n\n\tdef visit_iterator_warp(self, node):\n\t\tself._write(\"for \")\n\n\t\tself._visit(node.variables)\n\n\t\tself._write(\" in \")\n\n\t\tself._visit(node.controls)\n\n\t\tself._end_line()\n\t\tself._write(\"LOOP BLOCK #{0}\", node.body.index)\n\n\t\tself._end_line()\n\t\tself._write(\"GO OUT TO BLOCK #{0}\", node.way_out.index)\n\n\t\tself._end_line()\n\n\tdef visit_numeric_loop_warp(self, node):\n\t\tself._write(\"for \")\n\n\t\tself._visit(node.index)\n\n\t\tself._write(\"=\")\n\n\t\tself._visit(node.controls)\n\n\t\tself._end_line()\n\t\tself._write(\"LOOP BLOCK #{0}\", node.body.index)\n\n\t\tself._end_line()\n\t\tself._write(\"GO OUT TO BLOCK #{0}\", node.way_out.index)\n\n\t# ##\n\n\tdef visit_return(self, node):\n\t\tself._start_statement(STATEMENT_RETURN)\n\n\t\tself._write(\"return \")\n\n\t\tself._visit(node.returns)\n\n\t\tself._end_statement(STATEMENT_RETURN)\n\n\tdef visit_break(self, node):\n\t\tself._start_statement(STATEMENT_BREAK)\n\n\t\tself._write(\"break\")\n\n\t\tself._end_statement(STATEMENT_BREAK)\n\n\t# ##\n\n\tdef visit_while(self, node):\n\t\tself._start_statement(STATEMENT_WHILE)\n\n\t\tself._write(\"while \")\n\t\tself._visit(node.expression)\n\t\tself._write(\" do\")\n\n\t\tself._end_line()\n\n\t\tself._visit(node.statements)\n\n\t\tself._write(\"end\")\n\t\tself._end_statement(STATEMENT_WHILE)\n\n\tdef visit_repeat_until(self, node):\n\t\tself._start_statement(STATEMENT_REPEAT_UNTIL)\n\n\t\tself._write(\"repeat\")\n\t\tself._end_line()\n\n\t\tself._visit(node.statements)\n\n\t\tself._write(\"until \")\n\t\tself._visit(node.expression)\n\n\t\tself._end_statement(STATEMENT_REPEAT_UNTIL)\n\n\tdef visit_numeric_for(self, node):\n\t\tself._start_statement(STATEMENT_NUMERIC_FOR)\n\n\t\tself._write(\"for \")\n\t\tself._visit(node.variable)\n\t\tself._write(\" = \")\n\n\t\tself._visit(node.expressions)\n\n\t\tself._write(\" do\")\n\n\t\tself._end_line()\n\n\t\tself._visit(node.statements)\n\n\t\tself._write(\"end\")\n\t\tself._end_statement(STATEMENT_NUMERIC_FOR)\n\n\tdef visit_iterator_for(self, node):\n\t\tself._start_statement(STATEMENT_ITERATOR_FOR)\n\n\t\tself._write(\"for \")\n\t\tself._visit(node.identifiers)\n\t\tself._write(\" in \")\n\t\tself._visit(node.expressions)\n\t\tself._write(\" do\")\n\n\t\tself._end_line()\n\n\t\tself._visit(node.statements)\n\n\t\tself._write(\"end\")\n\t\tself._end_statement(STATEMENT_ITERATOR_FOR)\n\n\t# ##\n\n\tdef visit_constant(self, node):\n\t\tif node.type != nodes.Constant.T_STRING:\n\t\t\tself._write(node.value)\n\t\t\treturn\n\n\t\tlines = node.value.count(\"\\n\")\n\n\t\tif lines > 2:\n\t\t\tself._write(\"[[\")\n\n\t\t\tself._write(\"\\n\")\n\n\t\t\tself._write(node.value)\n\n\t\t\tself._write(\"]]\")\n\t\telse:\n\t\t\ttext = node.value\n\n\t\t\ttext = text.replace(\"\\\\\", \"\\\\\\\\\")\n\t\t\ttext = text.replace(\"\\t\", \"\\\\t\")\n\t\t\ttext = text.replace(\"\\n\", \"\\\\n\")\n\t\t\ttext = text.replace(\"\\r\", \"\\\\r\")\n\t\t\ttext = text.replace(\"\\\"\", \"\\\\\\\"\")\n\n\t\t\tself._write('\"' + text + '\"')\n\n\tdef visit_primitive(self, node):\n\t\tif node.type == nodes.Primitive.T_FALSE:\n\t\t\tself._write(\"false\")\n\t\telif node.type == nodes.Primitive.T_TRUE:\n\t\t\tself._write(\"true\")\n\t\telse:\n\t\t\tself._write(\"nil\")\n\n\tdef _skip(self, node):\n\t\tself._visited_nodes[-1].add(node)\n\n\tdef _visit(self, node):\n\t\tassert node is not None\n\n\t\tif node in self._visited_nodes[-1]:\n\t\t\treturn\n\n\t\tself._visited_nodes[-1].add(node)\n\n\t\t# TODO: add check\n\t\t# \"It looks like you forgot about some node changes...\"\n\n\t\tself._visited_nodes.append(set())\n\n\t\ttraverse.Visitor._visit(self, node)\n\n\t\tself._visited_nodes.pop()\n\n\ndef write(fd, ast):\n\tassert isinstance(ast, nodes.FunctionDefinition)\n\n\tvisitor = Visitor()\n\n\ttraverse.traverse(visitor, ast.statements)\n\n\t_process_queue(fd, visitor.print_queue)\n\n\ndef _get_next_significant(queue, i):\n\ti += 1\n\n\twhile i < len(queue):\n\t\tcmd = queue[i]\n\n\t\tif cmd[0] not in (CMD_END_LINE, CMD_WRITE):\n\t\t\tbreak\n\n\t\ti += 1\n\n\tif i < len(queue):\n\t\treturn queue[i]\n\telse:\n\t\treturn (CMD_END_BLOCK,)\n\n\ndef _process_queue(fd, queue):\n\tindent = 0\n\n\tline_broken = True\n\n\tfor i, cmd in enumerate(queue):\n\t\tassert isinstance(cmd, tuple)\n\n\t\tif cmd[0] == CMD_START_STATEMENT:\n\t\t\t# assert line_broken\n\t\t\tpass\n\t\telif cmd[0] == CMD_END_STATEMENT:\n\t\t\tfd.write(\"\\n\")\n\t\t\tline_broken = True\n\n\t\t\tnext_cmd = _get_next_significant(queue, i)\n\n\t\t\tif next_cmd[0] not in (CMD_END_BLOCK, CMD_START_BLOCK):\n\t\t\t\tassert next_cmd[0] == CMD_START_STATEMENT\n\n\t\t\t\tif next_cmd[1] != cmd[1]\t\t\t\\\n\t\t\t\t\t\tor cmd[1] >= STATEMENT_IF\t\\\n\t\t\t\t\t\tor next_cmd[1] >= STATEMENT_IF:\n\t\t\t\t\tfd.write(\"\\n\")\n\t\telif cmd[0] == CMD_END_LINE:\n\t\t\tfd.write(\"\\n\")\n\t\t\tline_broken = True\n\t\telif cmd[0] == CMD_START_BLOCK:\n\t\t\tindent += 1\n\t\telif cmd[0] == CMD_END_BLOCK:\n\t\t\tindent -= 1\n\n\t\t\tassert indent >= 0\n\t\telse:\n\t\t\tassert cmd[0] == CMD_WRITE\n\n\t\t\tif line_broken:\n\t\t\t\tfd.write(indent * '\\t')\n\t\t\t\tline_broken = False\n\n\t\t\t_id, fmt, args, kargs = cmd\n\n\t\t\tif len(args) + len(kargs) > 0:\n\t\t\t\ttext = fmt.format(*args, **kargs)\n\t\t\telif isinstance(fmt, str):\n\t\t\t\ttext = fmt\n\t\t\telse:\n\t\t\t\ttext = str(fmt)\n\n\t\t\tfd.write(text)\n"
  },
  {
    "path": "ljd/pseudoasm/__init__.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n"
  },
  {
    "path": "ljd/pseudoasm/constants.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport ljd.bytecode.constants\n\n\ndef write_tables(writer, prototype):\n\ti = 0\n\n\tfor element in prototype.constants.complex_constants:\n\t\tif isinstance(element, ljd.bytecode.constants.Table):\n\t\t\t_write_table(writer, i, element)\n\n\t\ti += 1\n\n\ndef _write_table(writer, index, table):\n\twriter.stream.open_block(\"ktable#{0} = [\", index)\n\n\ti = 0\n\n\tfor element in table.array:\n\t\tif i != 0 or element is not None:\n\t\t\ttext = _translate_element(element)\n\n\t\t\twriter.stream.write_line(\"#{0}: {1},\", i, text)\n\n\t\ti += 1\n\n\tfor key, value in table.dictionary:\n\t\tkey = _translate_element(key)\n\t\tvalue = _translate_element(value)\n\n\t\twriter.stream.write_line(\"[{0}] = {1},\", key, value)\n\n\twriter.stream.close_block(\"]\")\n\twriter.stream.write_line()\n\twriter.stream.write_line()\n\n\ndef _translate_element(element):\n\tif element is True:\n\t\treturn \"true\"\n\telif element is False:\n\t\treturn \"false\"\n\telif element is None:\n\t\treturn \"nil\"\n\telif isinstance(element, bytes):\n\t\treturn '\"' + element.decode(\"utf8\") + '\"'\n\telse:\n\t\treturn str(element)\n"
  },
  {
    "path": "ljd/pseudoasm/instructions.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport ljd.bytecode.instructions as ins\nfrom ljd.bytecode.constants import T_NIL, T_FALSE, T_TRUE\n\nimport ljd.pseudoasm.prototype\n\n_FORMAT = \"{addr:3}\\t[{line:3}]\\t{name:<5}\\t{a:3}\\t{b}\\t{c}\\t; {description}\"\n\n\n_DESCRIPTION_HANDLERS = [None] * 255\n\n\nclass _State():\n\tdef __init__(self, writer, prototype, instructions):\n\t\tfor key, value in writer.__dict__.items():\n\t\t\tsetattr(self, key, value)\n\n\t\tself.prototype = prototype\n\t\tself.instructions = instructions\n\n\ndef write(writer, prototype):\n\tglobal _MAP\n\n\t# skip the first function header\n\taddr = 1\n\n\tinstructions = prototype.instructions\n\n\twriter = _State(writer, prototype, instructions)\n\n\twhile addr < len(instructions):\n\t\tinstruction = instructions[addr]\n\t\tline = prototype.debuginfo.lookup_line_number(addr)\n\n\t\tif instruction.opcode == ins.FNEW.opcode:\n\t\t\t_write_function(writer, addr, line, instruction)\n\t\telse:\n\t\t\t_write_instruction(writer, addr, line, instruction)\n\n\t\taddr += 1\n\n\ndef _write_instruction(writer, addr, line, instruction):\n\tdescription = _translate_description(writer, addr, line, instruction)\n\n\twriter.stream.write_multiline(_FORMAT,\n\t\taddr=addr,\n\t\tline=line,\n\t\tname=instruction.name,\n\t\ta=instruction.A if instruction.A_type is not None else \"\",\n\t\tb=instruction.B\tif instruction.B_type is not None else \"\",\n\t\tc=instruction.CD if instruction.CD_type is not None else \"\",\n\t\tdescription=description\n\t)\n\n\ndef _write_function(writer, addr, line, instruction):\n\tprototype = writer.prototype.constants.complex_constants[instruction.CD]\n\n\tdescription = ljd.pseudoasm.prototype.format_header(writer, prototype)\n\n\twriter.stream.open_block(_FORMAT,\n\t\taddr=addr,\n\t\tline=line,\n\t\tname=\"FNEW\",\n\t\ta=instruction.A,\n\t\tb=\"\",\n\t\tc=instruction.CD,\n\t\tdescription=description\n\t)\n\n\twriter.stream.write_line()\n\n\tljd.pseudoasm.prototype.write_body(writer, prototype)\n\n\twriter.stream.close_block()\n\n\ndef _translate_description(writer, addr, line, instruction):\n\tglobal _DESCRIPTION_HANDLERS\n\n\thandler = _DESCRIPTION_HANDLERS[instruction.opcode]\n\tdescription = instruction.description\n\n\treturn handler(writer, description, addr, line, instruction)\n\n\ndef _translate(writer, addr, value, attr_type):\n\tprototype = writer.prototype\n\n\tif attr_type == ins.T_DST or attr_type == ins.T_BS:\n\t\treturn \"slot\" + str(value)\n\tif attr_type == ins.T_VAR:\n\t\tname = _lookup_variable_name(writer, addr, value)\n\n\t\tif name is not None:\n\t\t\treturn name\n\t\telse:\n\t\t\treturn \"slot\" + str(value)\n\telif attr_type == ins.T_UV:\n\t\tname = prototype.debuginfo.lookup_upvalue_name(value)\n\t\treturn \"uv\" + str(value) + '\"' + name + '\"'\n\telif attr_type == ins.T_PRI:\n\t\tif value is None or value == T_NIL:\n\t\t\treturn \"nil\"\n\t\telif value is True or value == T_TRUE:\n\t\t\treturn \"true\"\n\t\telse:\n\t\t\tassert value is False or value == T_FALSE\n\t\t\treturn \"false\"\n\telif attr_type == ins.T_NUM:\n\t\treturn str(prototype.constants.numeric_constants[value])\n\telif attr_type == ins.T_STR:\n\t\tbinary = prototype.constants.complex_constants[value]\n\t\treturn '\"' + binary + '\"'\n\telif attr_type == ins.T_TAB:\n\t\treturn \"table#k\" + str(value)\n\telif attr_type == ins.T_CDT:\n\t\treturn str(prototype.constants.complex_constants[value])\n\telif attr_type == ins.T_JMP:\n\t\treturn str(1 + addr + value)\n\telif attr_type == ins.T_LIT or attr_type == ins.T_SLIT:\n\t\treturn str(value)\n\telif attr_type == ins.T_BS or attr_type == ins.T_RBS:\n\t\treturn \"r\" + str(value)\n\telse:\n\t\treturn \" \"  # \"r\" + str(value)\n\n\ndef _lookup_variable_name(writer, addr, slot):\n\twhile True:\n\t\tresult = _lookup_variable_name_step(writer, addr, slot)\n\n\t\tif isinstance(result, tuple):\n\t\t\taddr = result[0]\n\t\t\tslot = result[1]\n\t\t\tcontinue\n\n\t\treturn result\n\n\ndef _lookup_variable_name_step(writer, addr, slot):\n\tinfo = writer.prototype.debuginfo.lookup_local_name(addr, slot)\n\n\tif info is not None:\n\t\tname = info.name\n\n\t\tif name[0] == '<':\n\t\t\tname = \"slot\" + str(slot) + name\n\n\t\treturn name\n\n\tinstructions = writer.instructions\n\n\tknil_opcode = ins.KNIL.opcode\n\tconstants = writer.prototype.constants.complex_constants\n\n\twhile addr > 1:\n\t\taddr -= 1\n\t\tinstruction = instructions[addr]\n\n\t\tif instruction.A_type == ins.T_BS:\n\t\t\tif slot >= instruction.A \t\t\t\t\\\n\t\t\t\t\tand (instruction.opcode == knil_opcode\t\\\n\t\t\t\t\t\tor slot <= instruction.CD):\n\t\t\t\treturn None\n\n\t\t\tcontinue\n\n\t\tif instruction.A_type != ins.T_DST or instruction.A != slot:\n\t\t\tcontinue\n\n\t\tif instruction.opcode == ins.MOV.opcode:\n\t\t\t# Retry with new addr and slot\n\t\t\treturn addr, instruction.CD\n\n\t\tif instruction.opcode == ins.GGET.opcode:\n\t\t\tbinary = constants[instruction.CD]\n\t\t\treturn binary\n\n\t\t# field or method\n\t\tif instruction.opcode == ins.TGETS.opcode:\n\t\t\ttable_slot = instruction.B\n\t\t\ttable = _lookup_variable_name_step(writer, addr, table_slot)\n\n\t\t\tif table is None:\n\t\t\t\ttable = \"<unknown table>\"\n\n\t\t\tbinary = constants[instruction.CD]\n\t\t\treturn table + \".\" + binary\n\n\t\tif instruction.opcode == ins.UGET.opcode:\n\t\t\tuv = instruction.CD\n\t\t\tname = writer.prototype.debuginfo.lookup_upvalue_name(uv)\n\n\t\t\treturn \"uv\" + str(uv) + '\"' + name + '\"'\n\n\t\treturn None\n\n\treturn None\n\n\ndef _translate_standard(writer, addr, line, instruction):\n\tA = None\n\tB = None\n\tCD = None\n\n\tif instruction.A_type is not None:\n\t\tA = _translate(writer, addr, instruction.A, instruction.A_type)\n\n\tif instruction.B_type is not None:\n\t\tB = _translate(writer, addr, instruction.B, instruction.B_type)\n\n\tif instruction.CD_type is not None:\n\t\tCD = _translate(writer, addr, instruction.CD, instruction.CD_type)\n\n\treturn A, B, CD\n\n\ndef _translate_normal(writer, description, addr, line, instruction):\n\tA, B, CD = _translate_standard(writer, addr, line, instruction)\n\n\treturn description.format(A=A, B=B, C=CD, D=CD)\n\n\ndef _translate_concat(writer, description, addr, line, instruction):\n\tA = _translate(writer, addr, instruction.A, instruction.A_type)\n\n\targs = []\n\n\tstart = instruction.B\n\tend = instruction.CD + 1\n\n\twhile start != end:\n\t\tvar = _translate(writer, addr, start, ins.T_VAR)\n\t\targs.append(var)\n\t\tstart += 1\n\n\treturn description.format(A=A, concat_from_B_to_C=\" .. \".join(args))\n\n\ndef _translate_nil(writer, description, addr, line, instruction):\n\targs = []\n\n\tstart = instruction.A\n\tend = instruction.CD + 1\n\n\twhile start != end:\n\t\tvar = _translate(writer, addr, start, ins.T_VAR)\n\t\targs.append(var)\n\t\tstart += 1\n\n\treturn description.format(from_A_to_D=\", \".join(args))\n\n\ndef _translate_table_str_op(writer, description, addr, line, instruction):\n\tA, B, CD = _translate_standard(writer, addr, line, instruction)\n\n\tC = CD[1:-1]\n\n\treturn description.format(A=A, B=B, C=C)\n\n\ndef _translate_new_table(writer, description, addr, line, instruction):\n\tA = _translate(writer, addr, instruction.A, instruction.A_type)\n\n\tsize = instruction.CD\n\n\tarray_size = size & 0b0000011111111111\n\tdict_size = 2 ** (size >> 11)\n\n\treturn description.format(\n\t\tA=A,\n\t\tD_array=array_size,\n\t\tD_dict=dict_size,\n\t)\n\n\ndef _translate_mass_set(writer, description, addr, line, instruction):\n\tbase = instruction.A\n\n\ttable_var = _translate(writer, addr, base - 1, ins.T_VAR)\n\n\tfirst = instruction.CD\n\n\treturn description.format(\n\t\tA_minus_one=table_var,\n\t\tA=base,\n\t\tD_low=first,\n\t)\n\n\ndef _translate_varg_call(writer, description, addr, line, instruction):\n\tbase = instruction.A\n\targn = instruction.CD\n\tretn = instruction.B - 1\n\n\targs = []\n\treturns = []\n\n\ti = 0\n\twhile i < argn:\n\t\targs.append(_translate(writer, addr, base + i + 1, ins.T_VAR))\n\t\ti += 1\n\n\ti = 0\n\twhile i < retn:\n\t\treturns.append(_translate(writer, addr, base + i, ins.T_DST))\n\t\ti += 1\n\n\tfunc_var = _translate(writer, addr, base, ins.T_VAR)\n\n\treturn description.format(\n\t\tA=func_var,\n\t\tfrom_A_x_B_minus_two=\", \".join(returns)  if retn >= 0 else \"MULTRES\",\n\t\tfrom_A_plus_one_x_C=\", \".join(args)\n\t)\n\n\ndef _translate_call(writer, description, addr, line, instruction):\n\tbase = instruction.A\n\targn = instruction.CD - 1\n\tretn = instruction.B - 1\n\n\targs = []\n\treturns = []\n\n\ti = 0\n\twhile i < argn:\n\t\targs.append(_translate(writer, addr, base + i + 1, ins.T_VAR))\n\t\ti += 1\n\n\ti = 0\n\twhile i < retn:\n\t\treturns.append(_translate(writer, addr, base + i, ins.T_DST))\n\t\ti += 1\n\n\tfunc_var = _translate(writer, addr, base, ins.T_VAR)\n\n\treturn description.format(\n\t\tA=func_var,\n\t\tfrom_A_x_B_minus_two=\", \".join(returns) if retn >= 0 else \"MULTRES\",\n\t\tfrom_A_plus_one_x_C_minus_one=\", \".join(args)\n\t)\n\n\ndef _translate_varg_tailcall(writer, description, addr, line, instruction):\n\tbase = instruction.A\n\targn = instruction.CD - 1\n\n\targs = []\n\n\ti = 0\n\twhile i < argn:\n\t\targs.append(_translate(writer, addr, base + i + 1, ins.T_VAR))\n\t\ti += 1\n\n\tfunc_var = _translate(writer, addr, base, ins.T_VAR)\n\n\treturn description.format(\n\t\tA=func_var,\n\t\tfrom_A_plus_one_x_D=\", \".join(args)\n\t)\n\n\ndef _translate_tailcall(writer, description, addr, line, instruction):\n\tbase = instruction.A\n\targn = instruction.CD - 1\n\n\targs = []\n\n\ti = 0\n\twhile i < argn:\n\t\targs.append(_translate(writer, addr, base + i + 1, ins.T_VAR))\n\t\ti += 1\n\n\tfunc_var = _translate(writer, addr, base, ins.T_VAR)\n\n\treturn description.format(\n\t\tA=func_var,\n\t\tfrom_A_plus_one_x_D_minus_one=\", \".join(args)\n\t)\n\n\ndef _translate_iterator(writer, description, addr, line, instruction):\n\tbase = instruction.A\n\n\tA = _translate(writer, addr, instruction.A, ins.T_DST)\n\tA_plus_one = _translate(writer, addr, instruction.A + 1, ins.T_DST)\n\tA_plus_two = _translate(writer, addr, instruction.A + 2, ins.T_DST)\n\n\tA_minus_three = _translate(writer, addr, instruction.A - 3, ins.T_VAR)\n\tA_minus_two = _translate(writer, addr, instruction.A - 2, ins.T_VAR)\n\tA_minus_one = _translate(writer, addr, instruction.A - 1, ins.T_VAR)\n\n\tretn = instruction.B - 1\n\n\treturns = []\n\n\ti = 0\n\twhile i < retn:\n\t\treturns.append(_translate(writer, addr, base + i, ins.T_DST))\n\t\ti += 1\n\n\treturn description.format(\n\t\tA=A,\n\t\tA_plus_one=A_plus_one,\n\t\tA_plus_two=A_plus_two,\n\t\tA_minus_three=A_minus_three,\n\t\tA_minus_two=A_minus_two,\n\t\tA_minus_one=A_minus_one,\n\t\tfrom_A_x_B_minus_two=\", \".join(returns)\n\t)\n\n\ndef _translate_vararg(writer, description, addr, line, instruction):\n\treturns = []\n\n\tbase = instruction.A\n\n\tcount = instruction.B - 2\n\n\tif count < 0:\n\t\treturn description.format(from_A_x_B_minus_two=\"MULTRES\")\n\n\ti = 0\n\twhile i <= count:\n\t\treturns.append(_translate(writer, addr, base + i, ins.T_DST))\n\t\ti += 1\n\n\treturn description.format(\n\t\tfrom_A_x_B_minus_two=\", \".join(returns)\n\t)\n\n\ndef _translate_return_mult(writer, description, addr, line, instruction):\n\treturns = []\n\n\tbase = instruction.A\n\n\tcount = instruction.CD - 1\n\n\ti = 0\n\twhile i < count:\n\t\treturns.append(_translate(writer, addr, base + i, ins.T_VAR))\n\t\ti += 1\n\n\treturn description.format(\n\t\tfrom_A_x_D_minus_one=\", \".join(returns)\n\t)\n\n\ndef _translate_return_many(writer, description, addr, line, instruction):\n\treturns = []\n\n\tbase = instruction.A\n\n\tcount = instruction.CD - 2\n\n\ti = 0\n\twhile i < count:\n\t\treturns.append(_translate(writer, addr, base + i, ins.T_VAR))\n\t\ti += 1\n\n\treturn description.format(\n\t\tfrom_A_x_D_minus_two=\", \".join(returns)\n\t)\n\n\ndef _translate_return_one(writer, description, addr, line, instruction):\n\tA = _translate(writer, addr, instruction.A, ins.T_VAR)\n\n\treturn description.format(A=A)\n\n\ndef _translate_for_init(writer, description, addr, line, instruction):\n\tidx = _translate(writer, addr, instruction.A, ins.T_BS)\n\tstop = _translate(writer, addr, instruction.A + 1, ins.T_BS)\n\tstep = _translate(writer, addr, instruction.A + 2, ins.T_BS)\n\text_idx = _translate(writer, addr, instruction.A + 3, ins.T_VAR)\n\n\treturn description.format(\n\t\tA=idx,\n\t\tA_plus_one=stop,\n\t\tA_plus_two=step,\n\t\tA_plus_three=ext_idx,\n\t\tD=_translate(writer, addr, instruction.CD, ins.T_JMP)\n\t)\n\n\ndef _translate_numeric_loop(writer, description, addr, line, instruction):\n\tstop = _translate(writer, addr, instruction.A + 1, ins.T_VAR)\n\tstep = _translate(writer, addr, instruction.A + 2, ins.T_VAR)\n\text_idx = _translate(writer, addr, instruction.A + 3, ins.T_VAR)\n\n\t# ext_idx isn't correct var here, but for the visualisation sake we will\n\t# omit all the stuff with the internal idx var\n\n\treturn description.format(\n\t\tA=ext_idx,\n\t\tA_plus_one=stop,\n\t\tA_plus_two=step,\n\t\tD=_translate(writer, addr, instruction.CD, ins.T_JMP)\n\t)\n\n\ndef _translate_iter_loop(writer, description, addr, line, instruction):\n\tA_minus_one = _translate(writer, addr, instruction.A - 1, ins.T_VAR)\n\tA = _translate(writer, addr, instruction.A, ins.T_VAR)\n\n\treturn description.format(\n\t\tA_minus_one=A_minus_one,\n\t\tA=A,\n\t\tD=_translate(writer, addr, instruction.CD, ins.T_JMP)\n\t)\n\n\n_HANDLERS_MAP = (\n\t# Comparison ops\n\n\t(ins.ISLT.opcode, \t_translate_normal),\n\t(ins.ISGE.opcode, \t_translate_normal),\n\t(ins.ISLE.opcode, \t_translate_normal),\n\t(ins.ISGT.opcode, \t_translate_normal),\n\n\t(ins.ISEQV.opcode, \t_translate_normal),\n\t(ins.ISNEV.opcode, \t_translate_normal),\n\n\t(ins.ISEQS.opcode, \t_translate_normal),\n\t(ins.ISNES.opcode, \t_translate_normal),\n\n\t(ins.ISEQN.opcode, \t_translate_normal),\n\t(ins.ISNEN.opcode, \t_translate_normal),\n\n\t(ins.ISEQP.opcode, \t_translate_normal),\n\t(ins.ISNEP.opcode, \t_translate_normal),\n\n\t# Unary test and copy ops\n\n\t(ins.ISTC.opcode, \t_translate_normal),\n\t(ins.ISFC.opcode, \t_translate_normal),\n\n\t(ins.IST.opcode, \t_translate_normal),\n\t(ins.ISF.opcode, \t_translate_normal),\n\n\t# Unary ops\n\n\t(ins.MOV.opcode, \t_translate_normal),\n\t(ins.NOT.opcode, \t_translate_normal),\n\t(ins.UNM.opcode, \t_translate_normal),\n\t(ins.LEN.opcode, \t_translate_normal),\n\n\t# Binary ops\n\n\t(ins.ADDVN.opcode, \t_translate_normal),\n\t(ins.SUBVN.opcode, \t_translate_normal),\n\t(ins.MULVN.opcode, \t_translate_normal),\n\t(ins.DIVVN.opcode, \t_translate_normal),\n\t(ins.MODVN.opcode, \t_translate_normal),\n\n\t(ins.ADDNV.opcode, \t_translate_normal),\n\t(ins.SUBNV.opcode, \t_translate_normal),\n\t(ins.MULNV.opcode, \t_translate_normal),\n\t(ins.DIVNV.opcode, \t_translate_normal),\n\t(ins.MODNV.opcode, \t_translate_normal),\n\n\t(ins.ADDVV.opcode, \t_translate_normal),\n\t(ins.SUBVV.opcode, \t_translate_normal),\n\t(ins.MULVV.opcode, \t_translate_normal),\n\t(ins.DIVVV.opcode, \t_translate_normal),\n\t(ins.MODVV.opcode, \t_translate_normal),\n\n\t(ins.POW.opcode, \t_translate_normal),\n\t(ins.CAT.opcode, \t_translate_concat),\n\n\t# Constant ops\n\n\t(ins.KSTR.opcode, \t_translate_normal),\n\t(ins.KCDATA.opcode, \t_translate_normal),\n\t(ins.KSHORT.opcode, \t_translate_normal),\n\t(ins.KNUM.opcode, \t_translate_normal),\n\t(ins.KPRI.opcode, \t_translate_normal),\n\n\t(ins.KNIL.opcode, \t_translate_nil),\n\n\t# Upvalue and function ops\n\n\t(ins.UGET.opcode, \t_translate_normal),\n\n\t(ins.USETV.opcode, \t_translate_normal),\n\t(ins.USETS.opcode, \t_translate_normal),\n\t(ins.USETN.opcode, \t_translate_normal),\n\t(ins.USETP.opcode, \t_translate_normal),\n\n\t(ins.UCLO.opcode, \t_translate_normal),\n\n\t(ins.FNEW.opcode, \t_translate_normal),\n\n\t# Table ops\n\n\t(ins.TNEW.opcode, \t_translate_new_table),\n\n\t(ins.TDUP.opcode, \t_translate_normal),\n\n\t(ins.GGET.opcode, \t_translate_normal),\n\t(ins.GSET.opcode, \t_translate_normal),\n\n\t(ins.TGETV.opcode, \t_translate_normal),\n\t(ins.TGETS.opcode, \t_translate_table_str_op),\n\t(ins.TGETB.opcode, \t_translate_normal),\n\n\t(ins.TSETV.opcode, \t_translate_normal),\n\t(ins.TSETS.opcode, \t_translate_table_str_op),\n\t(ins.TSETB.opcode, \t_translate_normal),\n\n\t(ins.TSETM.opcode, \t_translate_mass_set),\n\n\t# Calls and vararg handling\n\n\t(ins.CALLM.opcode, \t_translate_varg_call),\n\t(ins.CALL.opcode, \t_translate_call),\n\t(ins.CALLMT.opcode, \t_translate_varg_tailcall),\n\t(ins.CALLT.opcode, \t_translate_tailcall),\n\n\t(ins.ITERC.opcode, \t_translate_iterator),\n\t(ins.ITERN.opcode, \t_translate_iterator),\n\n\t(ins.VARG.opcode, \t_translate_vararg),\n\n\t(ins.ISNEXT.opcode, \t_translate_normal),\n\n\t# Returns\n\n\t(ins.RETM.opcode, \t_translate_return_mult),\n\t(ins.RET.opcode, \t_translate_return_many),\n\t(ins.RET0.opcode, \t_translate_normal),\n\t(ins.RET1.opcode, \t_translate_return_one),\n\n\t# Loops and branches\n\n\t(ins.FORI.opcode, \t_translate_for_init),\n\t(ins.JFORI.opcode, \t_translate_for_init),\n\n\t(ins.FORL.opcode, \t_translate_numeric_loop),\n\t(ins.IFORL.opcode, \t_translate_numeric_loop),\n\t(ins.JFORL.opcode, \t_translate_numeric_loop),\n\n\t(ins.ITERL.opcode, \t_translate_iter_loop),\n\t(ins.IITERL.opcode, \t_translate_iter_loop),\n\t(ins.JITERL.opcode, \t_translate_iter_loop),\n\n\t(ins.LOOP.opcode, \t_translate_normal),\n\t(ins.ILOOP.opcode, \t_translate_normal),\n\t(ins.JLOOP.opcode, \t_translate_normal),\n\n\t(ins.JMP.opcode, \t_translate_normal),\n\n\t# Function headers\n\n\t(ins.FUNCF.opcode, \t_translate_normal),\n\t(ins.IFUNCF.opcode, \t_translate_normal),\n\t(ins.JFUNCF.opcode, \t_translate_normal),\n\n\t(ins.FUNCV.opcode, \t_translate_normal),\n\t(ins.IFUNCV.opcode, \t_translate_normal),\n\t(ins.JFUNCV.opcode, \t_translate_normal),\n\n\t(ins.FUNCC.opcode, \t_translate_normal),\n\t(ins.FUNCCW.opcode, \t_translate_normal)\n)\n\n\ndef _init():\n\tglobal _HANDLERS_MAP, _DESCRIPTION_HANDLERS\n\n\tfor opcode, handler in _HANDLERS_MAP:\n\t\t_DESCRIPTION_HANDLERS[opcode] = handler\n\n\tdel globals()[\"_init\"]\n\tdel globals()[\"_HANDLERS_MAP\"]\n\n_init()\n"
  },
  {
    "path": "ljd/pseudoasm/prototype.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport ljd.pseudoasm.constants\nimport ljd.pseudoasm.instructions\n\n\ndef write(writer, prototype):\n\t_write_header(writer, prototype)\n\twrite_body(writer, prototype)\n\n\twriter.stream.close_block(\"\")\n\n\ndef _write_header(writer, prototype):\n\twriter.stream.open_block(\"main {0}\", format_header(writer, prototype))\n\n\ndef format_header(writer, prototype):\n\treturn \"{s}:{start}-{end}: {argn}{varg} args,\"\t\\\n\t\t\t\" {uvs} upvalues, {slots} slots\".format(\n\t\ts=writer.source,\n\t\tstart=prototype.first_line_number,\n\t\tend=prototype.first_line_number + prototype.lines_count,\n\t\targn=prototype.arguments_count,\n\t\tvarg=\"+\" if prototype.flags.is_variadic else \"\",\n\t\tuvs=len(prototype.constants.upvalue_references),\n\t\tslots=prototype.framesize\n\t)\n\n\ndef write_body(writer, prototype):\n\twriter.stream.write_line(\";;;; constant tables ;;;;\")\n\tljd.pseudoasm.constants.write_tables(writer, prototype)\n\n\twriter.stream.write_line(\";;;; instructions ;;;;\")\n\tljd.pseudoasm.instructions.write(writer, prototype)\n"
  },
  {
    "path": "ljd/pseudoasm/writer.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport ljd.util.indentedstream\n\nimport ljd.pseudoasm.prototype\n\n\nclass _State():\n\tdef __init__(self):\n\t\tself.flags = None\n\t\tself.stream = None\n\t\tself.source = None\n\n\ndef write(fd, header, prototype):\n\twriter = _State()\n\n\twriter.stream = ljd.util.indentedstream.IndentedStream(fd)\n\twriter.flags = header.flags\n\twriter.source = \"N/A\" if header.flags.is_stripped else header.name\n\n\t_write_header(writer, header)\n\n\tljd.pseudoasm.prototype.write(writer, prototype)\n\n\ndef _write_header(writer, header):\n\twriter.stream.write_multiline(\"\"\"\n;\n; Disassemble of {origin}\n;\n; Source file: {source}\n;\n; Flags:\n;\tStripped: {stripped}\n;\tEndianness: {endianness}\n;\tFFI: {ffi}\n;\n\n\"\"\", \t\torigin=header.origin,\n\t\tsource=writer.source,\n\t\tstripped=\"Yes\" if header.flags.is_stripped else \"No\",\n\t\tendianness=\"Big\" if header.flags.is_big_endian else \"Little\",\n\t\tffi=\"Present\" if header.flags.has_ffi else \"Not present\")\n"
  },
  {
    "path": "ljd/rawdump/__init__.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n"
  },
  {
    "path": "ljd/rawdump/code.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nfrom ljd.util.log import errprint\n\nimport ljd.bytecode.instructions as instructions\n\n\n_OPCODES = (\n\t# Comparison ops\n\n\t(0x00, \tinstructions.ISLT),  # @UndefinedVariable\n\t(0x01, \tinstructions.ISGE),  # @UndefinedVariable\n\t(0x02, \tinstructions.ISLE),  # @UndefinedVariable\n\t(0x03, \tinstructions.ISGT),  # @UndefinedVariable\n\n\t(0x04, \tinstructions.ISEQV),  # @UndefinedVariable\n\t(0x05, \tinstructions.ISNEV),  # @UndefinedVariable\n\n\t(0x06, \tinstructions.ISEQS),  # @UndefinedVariable\n\t(0x07, \tinstructions.ISNES),  # @UndefinedVariable\n\n\t(0x08, \tinstructions.ISEQN),  # @UndefinedVariable\n\t(0x09, \tinstructions.ISNEN),  # @UndefinedVariable\n\n\t(0x0A, \tinstructions.ISEQP),  # @UndefinedVariable\n\t(0x0B, \tinstructions.ISNEP),  # @UndefinedVariable\n\n\t# Unary test and copy ops\n\n\t(0x0C, \tinstructions.ISTC),  # @UndefinedVariable\n\t(0x0D, \tinstructions.ISFC),  # @UndefinedVariable\n\n\t(0x0E, \tinstructions.IST),  # @UndefinedVariable\n\t(0x0F, \tinstructions.ISF),  # @UndefinedVariable\n\n\t(0x0E, \tinstructions.ISTYPE),  # @UndefinedVariable\n\t(0x0F, \tinstructions.ISNUM),  # @UndefinedVariable\n\n\t# Unary ops\n\n\t(0x10, \tinstructions.MOV),  # @UndefinedVariable\n\t(0x11, \tinstructions.NOT),  # @UndefinedVariable\n\t(0x12, \tinstructions.UNM),  # @UndefinedVariable\n\t(0x13, \tinstructions.LEN),  # @UndefinedVariable\n\n\t# Binary ops\n\n\t(0x14, \tinstructions.ADDVN),  # @UndefinedVariable\n\t(0x15, \tinstructions.SUBVN),  # @UndefinedVariable\n\t(0x16, \tinstructions.MULVN),  # @UndefinedVariable\n\t(0x17, \tinstructions.DIVVN),  # @UndefinedVariable\n\t(0x18, \tinstructions.MODVN),  # @UndefinedVariable\n\n\t(0x19, \tinstructions.ADDNV),  # @UndefinedVariable\n\t(0x1A, \tinstructions.SUBNV),  # @UndefinedVariable\n\t(0x1B, \tinstructions.MULNV),  # @UndefinedVariable\n\t(0x1C, \tinstructions.DIVNV),  # @UndefinedVariable\n\t(0x1D, \tinstructions.MODNV),  # @UndefinedVariable\n\n\t(0x1E, \tinstructions.ADDVV),  # @UndefinedVariable\n\t(0x1F, \tinstructions.SUBVV),  # @UndefinedVariable\n\t(0x20, \tinstructions.MULVV),  # @UndefinedVariable\n\t(0x21, \tinstructions.DIVVV),  # @UndefinedVariable\n\t(0x22, \tinstructions.MODVV),  # @UndefinedVariable\n\n\t(0x23, \tinstructions.POW),  # @UndefinedVariable\n\t(0x24, \tinstructions.CAT),  # @UndefinedVariable\n\n\t# Constant ops\n\n\t(0x25, \tinstructions.KSTR),  # @UndefinedVariable\n\t(0x26, \tinstructions.KCDATA),  # @UndefinedVariable\n\t(0x27, \tinstructions.KSHORT),  # @UndefinedVariable\n\t(0x28, \tinstructions.KNUM),  # @UndefinedVariable\n\t(0x29, \tinstructions.KPRI),  # @UndefinedVariable\n\n\t(0x2A, \tinstructions.KNIL),  # @UndefinedVariable\n\n\t# Upvalue and function ops\n\n\t(0x2B, \tinstructions.UGET),  # @UndefinedVariable\n\n\t(0x2C, \tinstructions.USETV),  # @UndefinedVariable\n\t(0x2D, \tinstructions.USETS),  # @UndefinedVariable\n\t(0x2E, \tinstructions.USETN),  # @UndefinedVariable\n\t(0x2F, \tinstructions.USETP),  # @UndefinedVariable\n\n\t(0x30, \tinstructions.UCLO),  # @UndefinedVariable\n\n\t(0x31, \tinstructions.FNEW),  # @UndefinedVariable\n\n\t# Table ops\n\n\t(0x32, \tinstructions.TNEW),  # @UndefinedVariable\n\n\t(0x33, \tinstructions.TDUP),  # @UndefinedVariable\n\n\t(0x34, \tinstructions.GGET),  # @UndefinedVariable\n\t(0x35, \tinstructions.GSET),  # @UndefinedVariable\n\n\t(0x36, \tinstructions.TGETV),  # @UndefinedVariable\n\t(0x37, \tinstructions.TGETS),  # @UndefinedVariable\n\t(0x38, \tinstructions.TGETB),  # @UndefinedVariable\n\t(0x38, \tinstructions.TGETR),  # @UndefinedVariable\n\n\t(0x39, \tinstructions.TSETV),  # @UndefinedVariable\n\t(0x3A, \tinstructions.TSETS),  # @UndefinedVariable\n\t(0x3B, \tinstructions.TSETB),  # @UndefinedVariable\n\n\t(0x3C, \tinstructions.TSETM),  # @UndefinedVariable\n\t(0x3B, \tinstructions.TSETR),  # @UndefinedVariable\n\n\t# Calls and vararg handling\n\n\t(0x3D, \tinstructions.CALLM),  # @UndefinedVariable\n\t(0x3E, \tinstructions.CALL),  # @UndefinedVariable\n\t(0x3F, \tinstructions.CALLMT),  # @UndefinedVariable\n\t(0x40, \tinstructions.CALLT),  # @UndefinedVariable\n\n\t(0x41, \tinstructions.ITERC),  # @UndefinedVariable\n\t(0x42, \tinstructions.ITERN),  # @UndefinedVariable\n\n\t(0x43, \tinstructions.VARG),  # @UndefinedVariable\n\n\t(0x44, \tinstructions.ISNEXT),  # @UndefinedVariable\n\n\t# Returns\n\n\t(0x45, \tinstructions.RETM),  # @UndefinedVariable\n\t(0x46, \tinstructions.RET),  # @UndefinedVariable\n\t(0x47, \tinstructions.RET0),  # @UndefinedVariable\n\t(0x48, \tinstructions.RET1),  # @UndefinedVariable\n\n\t# Loops and branches\n\n\t(0x49, \tinstructions.FORI),  # @UndefinedVariable\n\t(0x4A, \tinstructions.JFORI),  # @UndefinedVariable\n\n\t(0x4B, \tinstructions.FORL),  # @UndefinedVariable\n\t(0x4C, \tinstructions.IFORL),  # @UndefinedVariable\n\t(0x4D, \tinstructions.JFORL),  # @UndefinedVariable\n\n\t(0x4E, \tinstructions.ITERL),  # @UndefinedVariable\n\t(0x4F, \tinstructions.IITERL),  # @UndefinedVariable\n\t(0x50, \tinstructions.JITERL),  # @UndefinedVariable\n\n\t(0x51, \tinstructions.LOOP),  # @UndefinedVariable\n\t(0x52, \tinstructions.ILOOP),  # @UndefinedVariable\n\t(0x53, \tinstructions.JLOOP),  # @UndefinedVariable\n\n\t(0x54, \tinstructions.JMP),  # @UndefinedVariable\n\n\t# Function headers\n\n\t(0x55, \tinstructions.FUNCF),  # @UndefinedVariable\n\t(0x56, \tinstructions.IFUNCF),  # @UndefinedVariable\n\t(0x57, \tinstructions.JFUNCF),  # @UndefinedVariable\n\n\t(0x58, \tinstructions.FUNCV),  # @UndefinedVariable\n\t(0x59, \tinstructions.IFUNCV),  # @UndefinedVariable\n\t(0x5A, \tinstructions.JFUNCV),  # @UndefinedVariable\n\n\t(0x5B, \tinstructions.FUNCC),  # @UndefinedVariable\n\t(0x5C, \tinstructions.FUNCCW)  # @UndefinedVariable\n)\n\n\n_MAP = [None] * 256\n\n\ndef read(parser):\n\tglobal _MAP\n\n\tcodeword = parser.stream.read_uint(4)\n\n\topcode = codeword & 0xFF\n\n\tinstruction_class = _MAP[opcode]\n\n\tif instruction_class is None:\n\t\terrprint(\"Warning: unknown opcode {0:08x}\", opcode)\n\t\tinstruction_class = instructions.UNKNW  # @UndefinedVariable #zzw.20180714\n\n\tinstruction = instruction_class()\n\n\tif instruction_class.opcode != opcode:\n\t\tinstruction.opcode = opcode\n\n\t_set_instruction_operands(parser, codeword, instruction)\n\n\treturn instruction\n\n\ndef _set_instruction_operands(parser, codeword, instruction):\n\tif instruction.args_count == 3:\n\t\tA = (codeword >> 8) & 0xFF\n\t\tCD = (codeword >> 16) & 0xFF\n\t\tB = (codeword >> 24) & 0xFF\n\telse:\n\t\tA = (codeword >> 8) & 0xFF\n\t\tCD = (codeword >> 16) & 0xFFFF\n\n\tif instruction.A_type is not None:\n\t\tinstruction.A = _process_operand(parser, instruction.A_type, A)\n\n\tif instruction.B_type is not None:\n\t\tinstruction.B = _process_operand(parser, instruction.B_type, B)\n\n\tif instruction.CD_type is not None:\n\t\tinstruction.CD = _process_operand(parser, instruction.CD_type, CD)\n\n\ndef _process_operand(parser, operand_type, operand):\n\tif operand_type == instructions.T_STR\t\t\t\\\n\t\t\tor operand_type == instructions.T_TAB\t\\\n\t\t\tor operand_type == instructions.T_FUN\t\\\n\t\t\tor operand_type == instructions.T_CDT:\n\t\treturn parser.complex_constants_count - operand - 1\n\telif operand_type == instructions.T_JMP:\n\t\treturn operand - 0x8000\n\telse:\n\t\treturn operand\n\n\ndef _init():\n\tglobal _OPCODES, _MAP\n\topcode = 0\n\tfor instruction in _OPCODES:\n\t\t_MAP[opcode] = instruction[1]\n\t\topcode = opcode + 1\n\n\tdel globals()[\"_init\"]\n\tdel globals()[\"_OPCODES\"]\n\n_init()\n"
  },
  {
    "path": "ljd/rawdump/constants.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport sys\nimport struct\n\nimport ljd.bytecode.constants\n\nimport gconfig\n\nBCDUMP_KGC_CHILD = 0\nBCDUMP_KGC_TAB = 1\nBCDUMP_KGC_I64 = 2\nBCDUMP_KGC_U64 = 3\nBCDUMP_KGC_COMPLEX = 4\nBCDUMP_KGC_STR = 5\n\n\nBCDUMP_KTAB_NIL = 0\nBCDUMP_KTAB_FALSE = 1\nBCDUMP_KTAB_TRUE = 2\nBCDUMP_KTAB_INT = 3\nBCDUMP_KTAB_NUM = 4\nBCDUMP_KTAB_STR = 5\n\n\ndef read(parser, constants):\n\tr = True\n\n\tr = r and _read_upvalue_references(parser, constants.upvalue_references)\n\tr = r and _read_complex_constants(parser, constants.complex_constants)\n\tr = r and _read_numeric_constants(parser, constants.numeric_constants)\n\n\treturn r\n\n\ndef _read_upvalue_references(parser, references):\n\ti = 0\n\n\twhile i < parser.upvalues_count:\n\t\ti += 1\n\t\tupvalue = parser.stream.read_uint(2)\n\t\treferences.append(upvalue)\n\n\treturn True\n\n\ndef _read_complex_constants(parser, complex_constants):\n\ti = 0\n\n\twhile i < parser.complex_constants_count:\n\t\tconstant_type = parser.stream.read_uleb128()\n\n\t\tif constant_type >= BCDUMP_KGC_STR:\n\t\t\tlength = constant_type - BCDUMP_KGC_STR\n\n\t\t\tstring = parser.stream.read_bytes(length)\n\t\t\t#print (string.decode(\"unicode-escape\"))\n\t\t\t#print(str(complex_constants))\n\t\t\t#zzw 20180714 support str encode\n\t\t\tcomplex_constants.append(string.decode(gconfig.gFlagDic['strEncode']))\n\t\telif constant_type == BCDUMP_KGC_TAB:\n\t\t\ttable = ljd.bytecode.constants.Table()\n\n\t\t\tif not _read_table(parser, table):\n\t\t\t\treturn False\n\n\t\t\tcomplex_constants.append(table)\n\t\telif constant_type != BCDUMP_KGC_CHILD:\n\t\t\tnumber = _read_number(parser)\n\n\t\t\tif constant_type == BCDUMP_KGC_COMPLEX:\n\t\t\t\timaginary = _read_number(parser)\n\t\t\t\tcomplex_constants.append((number, imaginary))\n\t\t\telse:\n\t\t\t\tcomplex_constants.append(number)\n\t\telse:\n\t\t\tcomplex_constants.append(parser.prototypes.pop())\n\n\t\ti += 1\n\n\treturn True\n\n\ndef _read_numeric_constants(parser, numeric_constants):\n\ti = 0\n\n\twhile i < parser.numeric_constants_count:\n\t\tisnum, lo = parser.stream.read_uleb128_from33bit()\n\n\t\tif isnum:\n\t\t\thi = parser.stream.read_uleb128()\n\n\t\t\tnumber = _assemble_number(lo, hi)\n\t\telse:\n\t\t\tnumber = _process_sign(lo)\n\n\t\tnumeric_constants.append(number)\n\n\t\ti += 1\n\n\treturn True\n\n\ndef _read_number(parser):\n\tlo = parser.stream.read_uleb128()\n\thi = parser.stream.read_uleb128()\n\n\treturn _assemble_number(lo, hi)\n\n\ndef _read_signed_int(parser):\n\tnumber = parser.stream.read_uleb128()\n\n\treturn _process_sign(number)\n\n\ndef _assemble_number(lo, hi):\n\tif sys.byteorder == 'big':\n\t\tfloat_as_int = lo << 32 | hi\n\telse:\n\t\tfloat_as_int = hi << 32 | lo\n\n\traw_bytes = struct.pack(\"=Q\", float_as_int)\n\treturn struct.unpack(\"=d\", raw_bytes)[0]\n\n\ndef _process_sign(number):\n\tif number & 0x80000000:\n\t\treturn -0x100000000 + number\n\telse:\n\t\treturn number\n\n\ndef _read_table(parser, table):\n\tarray_items_count = parser.stream.read_uleb128()\n\thash_items_count = parser.stream.read_uleb128()\n\n\twhile array_items_count > 0:\n\t\tconstant = _read_table_item(parser)\n\n\t\ttable.array.append(constant)\n\n\t\tarray_items_count -= 1\n\n\twhile hash_items_count > 0:\n\t\tkey = _read_table_item(parser)\n\t\tvalue = _read_table_item(parser)\n\n\t\ttable.dictionary.append((key, value))\n\n\t\thash_items_count -= 1\n\n\treturn True\n\n\ndef _read_table_item(parser):\n\tdata_type = parser.stream.read_uleb128()\n\n\tif data_type >= BCDUMP_KTAB_STR:\n\t\tlength = data_type - BCDUMP_KTAB_STR\n\t\t# zzw 20180714 support str encode\n\t\treturn parser.stream.read_bytes(length).decode(gconfig.gFlagDic['strEncode'])\n\n\telif data_type == BCDUMP_KTAB_INT:\n\t\treturn _read_signed_int(parser)\n\n\telif data_type == BCDUMP_KTAB_NUM:\n\t\treturn _read_number(parser)\n\n\telif data_type == BCDUMP_KTAB_TRUE:\n\t\treturn True\n\n\telif data_type == BCDUMP_KTAB_FALSE:\n\t\treturn False\n\n\telse:\n\t\tassert data_type == BCDUMP_KTAB_NIL\n\n\t\treturn None\n"
  },
  {
    "path": "ljd/rawdump/debuginfo.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport sys\n\nimport ljd.bytecode.debuginfo\n\n\nVARNAME_END = 0\nVARNAME_FOR_IDX = 1\nVARNAME_FOR_STOP = 2\nVARNAME_FOR_STEP = 3\nVARNAME_FOR_GEN = 4\nVARNAME_FOR_STATE = 5\nVARNAME_FOR_CTL = 6\nVARNAME__MAX = 7\n\n\nINTERNAL_VARNAMES = [\n\tNone,\n\t\"<index>\",\n\t\"<limit>\",\n\t\"<step>\",\n\t\"<generator>\",\n\t\"<state>\",\n\t\"<control>\"\n]\n\n\ndef read(parser, line_offset, debuginfo):\n\tr = True\n\n\tr = r and _read_lineinfo(parser, line_offset, debuginfo.addr_to_line_map)\n\tr = r and _read_upvalue_names(parser, debuginfo.upvalue_variable_names)\n\tr = r and _read_variable_infos(parser, debuginfo.variable_info)\n\n\treturn r\n\n\ndef _read_lineinfo(parser, line_offset, lineinfo):\n\tif parser.lines_count >= 65536:\n\t\tlineinfo_size = 4\n\telif parser.lines_count >= 256:\n\t\tlineinfo_size = 2\n\telse:\n\t\tlineinfo_size = 1\n\n\tlineinfo.append(0)\n\n\twhile len(lineinfo) < parser.instructions_count + 1:\n\t\tline_number = parser.stream.read_uint(lineinfo_size)\n\t\tlineinfo.append(line_offset + line_number)\n\n\treturn True\n\n\ndef _read_upvalue_names(parser, names):\n\twhile len(names) < parser.upvalues_count:\n\t\tstring = parser.stream.read_zstring()\n\t\tnames.append(string.decode(\"utf-8\"))\n\n\treturn True\n\n\ndef _read_variable_infos(parser, infos):\n\t# pc - program counter\n\tlast_addr = 0\n\n\twhile True:\n\t\tinfo = ljd.bytecode.debuginfo.VariableInfo()\n\n\t\tinternal_vartype = parser.stream.read_byte()\n\n\t\tif internal_vartype >= VARNAME__MAX:\n\t\t\tprefix = internal_vartype.to_bytes(1, sys.byteorder)\n\t\t\tsuffix = parser.stream.read_zstring()\n\n\t\t\tinfo.name = (prefix + suffix).decode(\"utf-8\")\n\t\t\tinfo.type = info.T_VISIBILE\n\n\t\telif internal_vartype == VARNAME_END:\n\t\t\tbreak\n\t\telse:\n\t\t\tindex = internal_vartype\n\t\t\tinfo.name = INTERNAL_VARNAMES[index]\n\t\t\tinfo.type = info.T_INTERNAL\n\n\t\tstart_addr = last_addr + parser.stream.read_uleb128()\n\t\tend_addr = start_addr + parser.stream.read_uleb128()\n\n\t\tinfo.start_addr = start_addr\n\t\tinfo.end_addr = end_addr\n\n\t\tlast_addr = start_addr\n\n\t\tinfos.append(info)\n\n\treturn True\n"
  },
  {
    "path": "ljd/rawdump/header.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nfrom ljd.util.log import errprint\n\n\n_MAGIC = b'\\x1bLJ'\n\n_MAX_VERSION = 0x80\n\n_FLAG_IS_BIG_ENDIAN = 0b00000001\n_FLAG_IS_STRIPPED = 0b00000010\n_FLAG_HAS_FFI = 0b00000100\n\n\nclass Flags():\n    def __init__(self):\n        self.is_big_endian = False\n        self.is_stripped = False\n        self.has_ffi = False\n\n\nclass Header():\n    def __init__(self):\n        self.version = 0\n        self.flags = Flags()\n        self.origin = b''\n        self.name = b''\n\n\ndef read(state, header):\n    r = True\n\n    header.origin = state.stream.name\n\n    r = r and _check_magic(state)\n\n    r = r and _read_version(state, header)\n    r = r and _read_flags(state, header)\n    r = r and _read_name(state, header)\n    #print(\"header good!\")\n\n    return r\n\n\ndef _check_magic(state):\n    if state.stream.read_bytes(3) != _MAGIC:\n        errprint(\"Invalid magic, not a LuaJIT format\")\n        return False\n\n    return True\n\n\ndef _read_version(state, header):\n    header.version = state.stream.read_byte()\n\n    if header.version > _MAX_VERSION:\n        errprint(\"Version {0}: propritary modifications\",\n                        header.version)\n        return False\n\n    return True\n\n\ndef _read_flags(parser, header):\n    bits = parser.stream.read_uleb128()\n\n    header.flags.is_big_endian = bits & _FLAG_IS_BIG_ENDIAN\n    bits &= ~_FLAG_IS_BIG_ENDIAN\n\n    header.flags.is_stripped = bits & _FLAG_IS_STRIPPED\n    bits &= ~_FLAG_IS_STRIPPED\n\n    header.flags.has_ffi = bits & _FLAG_HAS_FFI\n    bits &= ~_FLAG_HAS_FFI\n\n    # zzw.20180714 pitch: flag value is according to parser.flag when parse proto, not by header.flags\n    parser.flags.is_big_endian = header.flags.is_big_endian\n    parser.flags.is_stripped = header.flags.is_stripped\n    parser.flags.is_big_endian = header.flags.has_ffi\n\n    if bits != 0:\n        errprint(\"Unknown flags set: {0:08b}\", bits)\n        return False\n\n    return True\n\n\ndef _read_name(state, header):\n    if header.flags.is_stripped:\n        header.name = state.stream.name\n    else:\n        length = state.stream.read_uleb128()\n        header.name = state.stream.read_bytes(length).decode(\"utf8\")\n\n    return True\n"
  },
  {
    "path": "ljd/rawdump/parser.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n#!/usr/bin/python3\n\nimport ljd.util.binstream\nfrom ljd.util.log import errprint\n\nimport ljd.bytecode.prototype\n\nimport ljd.rawdump.header\nimport ljd.rawdump.prototype\n\n\nclass _State():\n    def __init__(self):\n        self.stream = ljd.util.binstream.BinStream()\n        self.flags = ljd.rawdump.header.Flags()\n        self.prototypes = []\n\n\ndef parse(filename):\n    parser = _State()\n\n    parser.stream.open(filename)\n\n    header = ljd.rawdump.header.Header()\n\n    r = True\n\n    try:\n        r = r and _read_header(parser, header)\n        #print(\"good1\")\n        r = r and _read_prototypes(parser, parser.prototypes)\n        #print(\"good2\")\n    except IOError as e:\n        errprint(\"I/O error while reading dump: {0}\", str(e))\n        r = False\n\n    if r and not parser.stream.eof():\n        errprint(\"Stopped before whole file was read, something wrong\")\n        r = False\n\n    if r and len(parser.prototypes) != 1:\n        errprint(\"Invalid prototypes stack order\")\n        r = False\n\n    parser.stream.close()\n\n    if r:\n        return header, parser.prototypes[0]\n    else:\n        return None, None\n\n#zzw 20180716 解析字节码文件头部结构header\n'''\n| magic(3 bytes)| version(1 byte) | flag(1 uleb128) [| name(1 uleb128) |]\n'''\ndef _read_header(parser, header):\n    if not ljd.rawdump.header.read(parser, header):\n        errprint(\"Failed to read raw-dump header\")\n        return False\n\n    if header.flags.is_big_endian:\n        parser.stream.data_byteorder = 'big'\n    else:\n        parser.stream.data_byteorder = 'little'\n\n    return True\n\n\ndef _read_prototypes(state, prototypes):\n    while not state.stream.eof():\n        prototype = ljd.bytecode.prototype.Prototype()\n        #print (\"good rwsdump->parser->read_prototypes\")\n\n        if not ljd.rawdump.prototype.read(state, prototype):\n            if state.stream.eof():\n                break\n            else:\n                errprint(\"Failed to read prototype\")\n                return False\n\n        prototypes.append(prototype)\n\n    return True\n"
  },
  {
    "path": "ljd/rawdump/prototype.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nfrom ljd.util.log import errprint\n\nimport ljd.bytecode.instructions as ins\n\nimport ljd.rawdump.constants\nimport ljd.rawdump.debuginfo\nimport ljd.rawdump.code\n\n\nFLAG_HAS_CHILD = 0b00000001\nFLAG_IS_VARIADIC = 0b00000010\nFLAG_HAS_FFI = 0b00000100\nFLAG_JIT_DISABLED = 0b00001000\nFLAG_HAS_ILOOP = 0b00010000\n\n\nclass _State():\n    def __init__(self, parser):\n        for key, value in parser.__dict__.items():\n            setattr(self, key, value)\n\n        self.upvalues_count = 0\n        self.complex_constants_count = 0\n        self.numeric_constants_count = 0\n        self.instructions_count = 0\n        self.debuginfo_size = 0\n'''\nzzw 20180716\n| size(1 uleb128) | flag(1 byte) | arguments_count(1 byte) \n| framesize(1 byte) | upvalues_count(1 byte) | complex_constants_count(1 uleb128) \n| numeric_constants_count(1 uleb128) | instructions_count(1 uleb128) [| debuginfo_size(1 uleb128)\n| first_line_number(1 uleb128) | lines_count(1 uleb128) ] | instructions(protoheader define) \n| constants(protoheader define) | debginfo(protoheader flage define) |\n'''\n\ndef read(parser, prototype):\n    parser = _State(parser)\n\n    size = parser.stream.read_uleb128()\n\n    if size == 0:\n        return False\n\n    if not parser.stream.check_data_available(size):\n        errprint(\"File truncated\")\n        return False\n\n    start = parser.stream.pos\n\n    r = True\n\n    r = r and _read_flags(parser, prototype)\n    r = r and _read_counts_and_sizes(parser, prototype)\n    r = r and _read_instructions(parser, prototype)\n    r = r and _read_constants(parser, prototype)\n    r = r and _read_debuginfo(parser, prototype)\n\n    end = parser.stream.pos\n\n    if r:\n        assert end - start == size,                     \\\n            \"Incorrectly read: from {0} to {1} ({2}) instead of {3}\"\\\n            .format(start, end, end - start, size)\n\n    return r\n\n\ndef _read_flags(parser, prototype):\n    bits = parser.stream.read_byte()\n\n    prototype.flags.has_ffi = bool(bits & FLAG_HAS_FFI)\n    bits &= ~FLAG_HAS_FFI\n\n    prototype.flags.has_iloop = bool(bits & FLAG_HAS_ILOOP)\n    bits &= ~FLAG_HAS_ILOOP\n\n    prototype.flags.has_jit = not (bits & FLAG_JIT_DISABLED)\n    bits &= ~FLAG_JIT_DISABLED\n\n    prototype.flags.has_sub_prototypes = bool(bits & FLAG_HAS_CHILD)\n    bits &= ~FLAG_HAS_CHILD\n\n    prototype.flags.is_variadic = bool(bits & FLAG_IS_VARIADIC)\n    bits &= ~FLAG_IS_VARIADIC\n\n    if bits != 0:\n        errprint(\"Unknown prototype flags: {0:08b}\", bits)\n        return False\n\n    return True\n\n\ndef _read_counts_and_sizes(parser, prototype):\n    prototype.arguments_count = parser.stream.read_byte()\n    prototype.framesize = parser.stream.read_byte()\n\n    parser.upvalues_count = parser.stream.read_byte()\n    parser.complex_constants_count = parser.stream.read_uleb128()\n    parser.numeric_constants_count = parser.stream.read_uleb128()\n    parser.instructions_count = parser.stream.read_uleb128()\n\n    if parser.flags.is_stripped:\n        parser.debuginfo_size = 0\n    else:\n        parser.debuginfo_size = parser.stream.read_uleb128()\n\n    if parser.debuginfo_size == 0:\n        return True\n\n    prototype.first_line_number = parser.stream.read_uleb128()\n    prototype.lines_count = parser.stream.read_uleb128()\n\n    parser.lines_count = prototype.lines_count\n\n    return True\n\n\ndef _read_instructions(parser, prototype):\n    i = 0\n\n    if prototype.flags.is_variadic:\n        header = ins.FUNCV()\n    else:\n        header = ins.FUNCF()\n\n    header.A = prototype.framesize\n    prototype.instructions.append(header)\n\n    while i < parser.instructions_count:\n        instruction = ljd.rawdump.code.read(parser)\n\n        if not instruction:\n            return False\n\n        #print (\"inst：%s\" % instruction.name)\n        #print (\"opcode:%x\" % instruction.opcode)\n        #print (\"A:%x\" % instruction.A)\n        #print (\"B:%x\" % instruction.B)\n        #print (\"CD:%x\" % instruction.CD)\n        prototype.instructions.append(instruction)\n\n        i += 1\n\n    return True\n\n\ndef _read_constants(parser, prototype):\n    return ljd.rawdump.constants.read(parser, prototype.constants)\n\n\ndef _read_debuginfo(stream, prototype):\n    if stream.debuginfo_size == 0:\n        return True\n\n    return ljd.rawdump.debuginfo.read(stream,\n                        prototype.first_line_number,\n                        prototype.debuginfo)\n"
  },
  {
    "path": "ljd/util/__init__.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n"
  },
  {
    "path": "ljd/util/binstream.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport io\nimport os\nimport sys\n\n\nclass BinStream():\n\tdef __init__(self):\n\t\tself.fd = None\n\n\t\tself.size = 0\n\t\tself.pos = 0\n\t\tself.name = \"\"\n\n\t\tself.data_byteorder = sys.byteorder\n\n\tdef open(self, filename):\n\t\tself.name = filename\n\t\tself.fd = io.open(filename, 'rb')\n\t\tself.size = os.stat(filename).st_size\n\n\tdef close(self):\n\t\tself.fd.close()\n\t\tself.size = 0\n\t\tself.pos = 0\n\n\tdef eof(self):\n\t\treturn self.pos >= self.size\n\n\tdef check_data_available(self, size=1):\n\t\treturn self.pos + size <= self.size\n\n\tdef read_bytes(self, size=1):\n\t\tif not self.check_data_available(size):\n\t\t\traise IOError(\"Unexpected EOF while trying to read {0} bytes\"\n\t\t\t\t\t\t\t\t\t.format(size))\n\n\t\tdata = self.fd.read(size)\n\t\tself.pos += len(data)#size\n\n\t\treturn data\n\n\tdef read_byte(self):\n\t\tif not self.check_data_available(1):\n\t\t\traise IOError(\"Unexpected EOF while trying to read 1 byte\")\n\n\t\tdata = self.fd.read(1)\n\t\tself.pos += 1\n\n\t\treturn int.from_bytes(data,\n\t\t\t\t\tbyteorder=sys.byteorder,\n\t\t\t\t\tsigned=False)\n\n\tdef read_zstring(self):\n\t\tstring = b''\n\n\t\twhile not self.eof():\n\t\t\tbyte = self.read_bytes(1)\n\n\t\t\tif byte == b'\\x00':\n\t\t\t\treturn string\n\t\t\telse:\n\t\t\t\tstring += byte\n\n\t\treturn string\n\n\tdef read_uleb128(self):\n\t\tvalue = self.read_byte()\n\n\t\tif value >= 0x80:\n\t\t\tbitshift = 0\n\t\t\tvalue &= 0x7f\n\n\t\t\twhile True:\n\t\t\t\tbyte = self.read_byte()\n\n\t\t\t\tbitshift += 7\n\t\t\t\tvalue |= (byte & 0x7f) << bitshift\n\n\t\t\t\tif byte < 0x80:\n\t\t\t\t\tbreak\n\n\t\treturn value\n\n\tdef read_uleb128_from33bit(self):\n\t\tfirst_byte = self.read_byte()\n\n\t\tis_number_bit = first_byte & 0x1\n\t\tvalue = first_byte >> 1\n\n\t\tif value >= 0x40:\n\t\t\tbitshift = -1\n\t\t\tvalue &= 0x3f\n\n\t\t\twhile True:\n\t\t\t\tbyte = self.read_byte()\n\n\t\t\t\tbitshift += 7\n\t\t\t\tvalue |= (byte & 0x7f) << bitshift\n\n\t\t\t\tif byte < 0x80:\n\t\t\t\t\tbreak\n\n\t\treturn is_number_bit, value\n\n\tdef read_uint(self, size=4):\n\t\tvalue = self.read_bytes(size)\n\n\t\treturn int.from_bytes(value, byteorder=self.data_byteorder,\n\t\t\t\t\t\t\t\tsigned=False)\n"
  },
  {
    "path": "ljd/util/indentedstream.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\n_TAB_WIDTH = \" \" * 8\n\n\nclass IndentedStream():\n\tdef __init__(self, fd):\n\t\tself.fd = fd\n\n\t\tself.indent = 0\n\t\tself.line_open = False\n\n\tdef write_multiline(self, fmt, *args, **kargs):\n\t\tassert not self.line_open\n\n\t\tif len(args) + len(kargs) > 0:\n\t\t\ttext = fmt.format(*args, **kargs)\n\t\telse:\n\t\t\ttext = fmt\n\n\t\tlines = text.split(\"\\n\")\n\n\t\tif lines[0] == \"\":\n\t\t\tlines.pop(0)\n\n\t\tif lines[-1] == \"\":\n\t\t\tlines.pop(-1)\n\n\t\tspaces = \"\\t\" * self.indent\n\n\t\tfor line in lines:\n\t\t\tself.fd.write(spaces + line + \"\\n\")\n\n\tdef start_line(self):\n\t\tassert not self.line_open\n\t\tself.line_open = True\n\n\t\tself.fd.write(\"\\t\" * self.indent)\n\n\tdef write(self, fmt=\"\", *args, **kargs):\n\t\tassert self.line_open\n\n\t\tif len(args) + len(kargs) > 0:\n\t\t\ttext = fmt.format(*args, **kargs)\n\t\telif isinstance(fmt, str):\n\t\t\ttext = fmt\n\t\telse:\n\t\t\ttext = str(fmt)\n\n\t\tassert \"\\n\" not in text\n\n\t\tself.fd.write(text)\n\n\tdef end_line(self):\n\t\tassert self.line_open\n\n\t\tself.fd.write(\"\\n\")\n\n\t\tself.line_open = False\n\n\tdef write_line(self, *args, **kargs):\n\t\tself.start_line()\n\t\tself.write(*args, **kargs)\n\t\tself.end_line()\n\n\tdef open_block(self, *args, **kargs):\n\t\tif len(args) + len(kargs) > 0:\n\t\t\tself.write_line(*args, **kargs)\n\n\t\tself.indent += 1\n\n\tdef close_block(self, *args, **kargs):\n\t\tif len(args) + len(kargs) > 0:\n\t\t\tself.write_line(*args, **kargs)\n\n\t\tself.indent -= 1\n"
  },
  {
    "path": "ljd/util/log.py",
    "content": "#\n# Copyright (C) 2013 Andrian Nord. See Copyright Notice in main.py\n#\n\nimport sys\n\n\ndef errprint(*args):\n\tfmt = None\n\n\targs = list(args)\n\n\tif isinstance(args[0], str):\n\t\tfmt = args.pop(0)\n\n\tif fmt:\n\t\tprint(fmt.format(*args), file=sys.stderr)\n\telse:\n\t\tstrs = [repr(x) for x in args]\n\t\tprint(\" \".join(strs), file=sys.stderr)\n"
  },
  {
    "path": "main.py",
    "content": "#!/usr/bin/python3\n#\n# The MIT License (MIT)\n#\n# Copyright (c) 2013 Andrian Nord\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n#\n\nimport sys\n\nimport ljd.rawdump.parser\nimport ljd.pseudoasm.writer\nimport ljd.ast.builder\nimport ljd.ast.validator\nimport ljd.ast.locals\nimport ljd.ast.slotworks\nimport ljd.ast.unwarper\nimport ljd.ast.mutator\nimport ljd.lua.writer\n#zzw 20180714 support str encode\nimport gconfig\n\ndef dump(name, obj, level=0):\n    indent = level * '\\t'\n\n    if name is not None:\n        prefix = indent + name + \" = \"\n    else:\n        prefix = indent\n\n    if isinstance(obj, (int, float, str)):\n        print(prefix + str(obj))\n    elif isinstance(obj, list):\n        print (prefix + \"[\")\n\n        for value in obj:\n            dump(None, value, level + 1)\n\n        print (indent + \"]\")\n    elif isinstance(obj, dict):\n        print (prefix + \"{\")\n\n        for key, value in obj.items():\n            dump(key, value, level + 1)\n\n        print (indent + \"}\")\n    else:\n        print (prefix + obj.__class__.__name__)\n\n        for key in dir(obj):\n            if key.startswith(\"__\"):\n                continue\n\n            val = getattr(obj, key)\n            dump(key, val, level + 1)\n\n\ndef main():\n    file_in = sys.argv[1]\n\n    header, prototype = ljd.rawdump.parser.parse(file_in)\n    #print (\"good\")\n    if not prototype:\n        return 1\n\n    # TODO: args\n    # ljd.pseudoasm.writer.write(sys.stdout, header, prototype)\n\n    ast = ljd.ast.builder.build(prototype)\n\n    assert ast is not None\n\n    ljd.ast.validator.validate(ast, warped=True)\n\n    ljd.ast.mutator.pre_pass(ast)\n\n    # ljd.ast.validator.validate(ast, warped=True)\n\n    ljd.ast.locals.mark_locals(ast)\n\n    # ljd.ast.validator.validate(ast, warped=True)\n\n    ljd.ast.slotworks.eliminate_temporary(ast)\n\n    # ljd.ast.validator.validate(ast, warped=True)\n\n    if True:\n        ljd.ast.unwarper.unwarp(ast)\n\n        # ljd.ast.validator.validate(ast, warped=False)\n\n        if True:\n            ljd.ast.locals.mark_local_definitions(ast)\n\n            # ljd.ast.validator.validate(ast, warped=False)\n\n            ljd.ast.mutator.primary_pass(ast)\n\n            ljd.ast.validator.validate(ast, warped=False)\n\n    ljd.lua.writer.write(sys.stdout, ast)\n\n    return 0\n\n\nif __name__ == \"__main__\":\n    # zzw 20180714 support str encode\n    gconfig.gFlagDic['strEncode'] = 'utf-8'\n    retval = main()\n    sys.exit(retval)\n\n# vim: ts=8 noexpandtab nosmarttab softtabstop=8 shiftwidth=8\n"
  },
  {
    "path": "test/breaks.lua",
    "content": "--[[\n--]]\n\nfor i=1,2,3 do\n\tif x and y then\n\t\tprint(\"Then\")\n\telse\n\t\tbreak\n\tend\nend\n\nfor i=1,2,3 do\n\tif x then\n\t\tprint(\"Then\")\n\telse\n\t\tbreak\n\tend\n\n\tprint (\"Something\")\n\n\tif y then\n\t\tbreak\n\tend\nend\n\nfor i=1,2,3 do\n\tif x then\n\t\tprint(\"Then\")\n\telse\n\t\tif y then\n\t\t\tbreak\n\t\tend\n\tend\n\n\tprint (\"Something\")\n\n\tif y then\n\t\tbreak\n\tend\nend\n\nfor i=1,2,3 do\n\tif x then\n\t\tprint(\"Then\")\n\t\tif y then\n\t\t\tbreak\n\t\tend\n\telse\n\t\tbreak\n\tend\nend\n\nfor i=1,2,3 do\n\tif x then\n\t\tprint(\"Then\")\n\t\tif y then\n\t\t\tprint (\"Nested then\")\n\t\telse\n\t\t\tbreak\n\t\tend\n\telse\n\t\tbreak\n\tend\nend\n\nfor i=1,2,3 do\n\tif x then\n\t\tprint(\"Then\")\n\telse\n\t\tbreak\n\tend\n\n\tif y then\n\t\tprint (\"Y then\")\n\telse\n\t\tbreak\n\tend\nend\n\nprint (\"Too bad\")\n\nfor i=1,2,3 do\n\tif x then\n\t\tprint(\"Then\")\n\t\tif y then\n\t\t\tprint (\"Y then\")\n\t\t\tif z then\n\t\t\t\tprint (\"Z then\")\n\t\t\tend\n\t\tend\n\t\tbreak\n\tend\n\n\tif y then\n\t\tprint (\"Y then\")\n\telse\n\t\tbreak\n\tend\nend\n\nfor i=1,2,3 do\n\tif x then\n\t\tif y then\n\t\t\tif z then\n\t\t\t\tif xi then\n\t\t\t\t\tprint (\"Xi then\")\n\t\t\t\tend\n\t\t\tend\n\t\tend\n\t\tbreak\n\telse\n\t\tbreak\n\tend\n\n\tif y then\n\t\tprint (\"Y then\")\n\telse\n\t\tbreak\n\tend\nend\n\nfor i=1,2,3 do\n\tif x and y and z and xi then\n\t\tprint (\"Xi then\")\n\t\tbreak\n\telse\n\t\tbreak\n\tend\n\n\tif y then\n\t\tprint (\"Y then\")\n\telse\n\t\tbreak\n\tend\nend\n\nfor i=1,2,3 do\n\tif x then\n\t\tprint (\"X then\")\n\t\tif y then\n\t\t\tprint (\"Y then\")\n\t\t\tif z then\n\t\t\t\tprint (\"Z then\")\n\t\t\t\tif xi then\n\t\t\t\t\tprint (\"Xi then\")\n\t\t\t\tend\n\t\t\tend\n\t\tend\n\t\tbreak\n\telse\n\t\tbreak\n\tend\n\n\tif y then\n\t\tprint (\"Y then\")\n\telse\n\t\tbreak\n\tend\nend\n\nfor i=1,2,3 do\n\tif x then\n\t\tif z then\n\t\t\tprint(\"Z Then\")\n\t\telse\n\t\t\tbreak\n\t\tend\n\n\t\tprint (\"Something\")\n\n\t\tif y then\n\t\t\tprint (\"Y then\")\n\t\telse\n\t\t\tbreak\n\t\tend\n\telse\n\t\tbreak\n\tend\n\nend\n\nfor i=1,2,3 do\n\tif x then\n\t\tif z then\n\t\t\tprint(\"Z Then\")\n\t\telse\n\t\t\tbreak\n\t\tend\n\n\t\tprint (\"Something\")\n\telse\n\t\tbreak\n\tend\n\n\tif y then\n\t\tprint (\"Y then\")\n\telse\n\t\tbreak\n\tend\nend\n\nfunction updateAnimation()\n\tlocal currentTime = getElapsedTime()\n\tlocal startSequence = private.currentSequence + 1\n\tlocal endSequence = #private.sequence\n\n\tfor i=startSequence, endSequence, 1 do\n\t\tlocal entry = private.sequence[i]\n\n\t\tif entry.time <= currentTime then\n\t\t\tif entry.command == \"start\" then\n\t\t\t\tgoToSlide(entry.element, 2)\n\t\t\t\tgoToTime(entry.element, entry.animationTime)\n\t\t\t\tplay(entry.element)\n\t\t\telse\n\t\t\t\tif entry.command == \"step\" then\n\t\t\t\t\tgoToSlide(entry.element, 2)\n\t\t\t\t\tgoToTime(entry.element, entry.animationTime)\n\t\t\t\telse\n\t\t\t\t\tpause(entry.element)\n\t\t\t\tend\n\t\t\tend\n\n\t\t\tif entry.name ~= nil then\n\t\t\t\tsetAttribute(getElement(\"name\", entry.element), \"textstring\", entry.name)\n\t\t\tend\n\n\t\t\tprivate.currentSequence = i\n\n\t\t\tbreak\n\t\telse \n\t\t\tbreak\n\t\tend\n\tend \n\n\tif #private.sequence == private.currentSequence then\n\t\tprivate.playing = false\n\tend\n\n\treturn \nend\n\n--[[\n--]]\n"
  },
  {
    "path": "test/expression.lua",
    "content": "--[[\n--]]\n\nprint (\"true or true\")\n\nb = true or true\n\nprint (\"false and false\")\n\nb = false and false\n\nprint (\"false and or\")\n\nb = false and (x or y)\n\nprint (\"false and ((and) or)\")\n\nb = false and ((x and z) or y)\n\nprint (\"precalculated true expression\")\n\nc = true or (x and y) or true\n\nprint (\"precalculated false expression\")\n\nd = false and ((x and y) or true)\n\nprint (\"precalculated false expression with function\")\n\ne = error() and false and ((x and y) or true)\n\nprint (\"precalculated true expression with function\")\n\ne = error() and true and ((x and y) or true)\n\nprint (\"precalculated? false expression with variable\")\n\nlocal z = false\n\nf = z and ((x and y) or true)\n\nprint (\"precalculated false expression with nil\")\n\nf = nil and ((x and y) or true)\n\nprint (\"simple or expression\")\nb = x or y\n\nprint (\"simple or not expression\")\n\nb = not x or y\nprint (\"simple and expression\")\n\nb = x and y\n\nprint (\"simple or expression with binary comparison\")\n\nb = (x < 100) or y\n\nprint (\"simple and expression with binary comparison\")\n\nb = (x < 100) and y\n\nprint (\"simple and expression with binary comparison and function call\")\n\nb = (x < 100) and print(y)\n\nprint (\"simple and expression with double binary comparison\")\n\nb = (x < 100) and (y > 100)\n\n\nprint (\"(and) or expression\")\n\nb = (x and y) or z\n\nprint (\"(or) and expression\")\n\nb = (x or y) and z\n\nprint (\"(and) and expression\")\n\nb = (x and y) and z\n\nprint (\"(or) or expression\")\nb = (x or y) or z\n\nprint (\"or (and) expression\")\n\nb = x or (y and x)\nb = x < 100 or (y < 100 and x < 100)\n\nprint (\"and (or) expression\")\n\nb = x and (y or x)\n\nprint (\"and (and) expression\")\n\nb = x and (y and x)\n\nprint (\"or (or) expression\")\n\nb = x or (y or x)\n\nprint (\"ond (or) and expression\")\n\nb = x and (y or x) and z\n\nprint (\"or (and) or expression\")\n\nb = x or (y and x) or z\n\nprint (\"and of two ors\")\n\nb = (x or z) and (y or z)\nprint (\"or of two ands\")\n\nb = (x and z) or (y and z)\n\nprint (\"x or string\")\nlocal xi = \"nothing\"\nxi = x or \"something\"\n\nlocal xi\n\nprint (\"x and string\")\nxi = x and \"something\"\n\nprint (\"and (or) and (or) expression with comparisons\")\n\nb = x < 100 and (y < 100 or x < 100) and (z < 100 or x < 100)\n\nprint (\"and (or) and or or expression with comparisons\")\n\nb = x < 100 and (y < 100 or x < 100) and z < 100 or x < 100 or y < 100\n\nprint (\"and (or) and and and expression with comparisons\")\n\nb = x < 100 and (y < 100 or x < 100) and z < 100 and x < 100 and y < 100\n\nprint (\"or (and) or (and) expression with comparisons\")\n\nb = x < 100 or (y < 100 and x < 100) or (z < 100 and x < 100)\n\nprint (\"and (and) and (and) expression with comparisons\")\n\nb = x < 100 and (y < 100 and x < 100) and (z < 100 and x < 100)\n\nprint (\"or (or) or (or) expression with comparisons\")\n\nb = x < 100 or (y < 100 or x < 100) or (z < 100 or x < 100)\n\nprint (\"4 and expression with comparisons\")\n\nb = x < 100 and y < 100 and x < 100 and z < 100 and x < 100\n\nprint (\"4 or expression with comparisons\")\n\nb = x < 100 or y < 100 or x < 100 or z < 100 or x < 100\n\nprint (\"and (or or) and (or or) expression with comparisons\")\n\nb = x < 100 and (y < 100 or x < 100 or z < 100)\n\t\tand (y < 100 or x < 100 or z < 100)\nprint (\"and (or and or) and (or and or) expression with comparisons\")\n\nb = x < 100 and (y < 100 or (x < 100 and x > 100) or z < 100)\n\t\tand (y < 100 or (x < 100 and x > 100) or z < 100)\n\nprint (\"or (and or and) or (and or and) expression with comparisons\")\n\nb = x < 100 or (y < 100 and (x < 100 or x > 100) and z < 100)\n\t\t\tor (y < 100 and (x < 100 or x > 100) and z < 100)\n\nprint (\"(((or) and) or)\")\na = (((x < 100 or y < 100) and x < 100) or z < 100)\n\nprint (\"(((or or) and) or)\")\na = ((x < 100 or y < 100 or z < 100) and x < 100 or z < 100)\n\nprint (\"(((or and) and) or)\")\na = (x < 100 or y < 100 and z < 100) and x < 100 or z < 100\n\nprint (\"(((or and) and) or) and error()\")\na = (((x < 100 or y < 100 and z < 100) and x < 100) or z < 100) and error()\n\nprint (\"(or (and (or)))\")\na = x < 100 or (y < 100 and (x < 100 or z < 100))\n\nprint (\"(not or (and (or)))\")\na = (not (x < 100)) or (y < 100 and (x < 100 or z < 100))\n\nlocal value = 1.0\n\nvalue = scaleinfo.floorValue and math.floor(value) or math.ceil(value)\n\nlocal function foo(a)\n\tprint(a)\nend\n\nlocal x = \"\"\n\nfoo(x == \"\" and x or \"test\")\n\nlocal timeout = (menu.isOffer and (duration or -1)) or\n\t\t((timeout and timeout ~= -1) and timeout or missiontime or -1)\n\nlocal a = x < 100\n\nlocal exists = 0\n\nexists = ffi.string(messageDetails.messageType) ~= \"\"\n\nlocal row, cells, rowdata, colspans, noscaling, bgColor\n\nif is_magic then\n\trow = foo(bgColor or Helper.defaultArrowRowBackgroundColor)\nelse\n\trow = bar(bgColor)\nend\n\nlocal a = 0\n\na = z == 3 and (x < ((y == 0 and is_magic) and 3 or 2)) and \"a\" or \"b\"\n\nlocal a, is_magic, x, y, foo, bar\n\na = is_magic and foo(x == \"station\" and y) or bar()\n\nlocal a = (\n\t((not commander and true or IsSameComponent(commander, menu.playership))\n\tand \"\") or \" [\" .. ReadText(1001, 1001) .. \"]\"\n)\n\nlocal a = isfirst and foo(bar((table[trade.ware] and \"-\") or \"+\", 1 < x)) or \"\"\n\nlocal a, x, y, is_magic\n\na = (not x and ( (x < 50 and x < 100 and z) or (is_magic and 4 or 3) )) or x\n\nsetElementPosition(iconelement, x, y, width%2 ~= 0, height%2 ~= 0)\n\nif xi then\n\tlocal unlocked_defence_status = x or ((y or z) < 100)\n\n\tbar(x and y or z)\nend\n\nlocal function foo()\n\treturn {\n\t\tfont = x or y,\n\t\tfontsize = x or y\n\t}\nend\n\nmenu.logbook = foo(x or y) or {}\n\nlocal x, y, bar, do_not_collapse_this_if_please, a\n\nif x then\n\tif y then\n\t\ta = {\n\t\t\tx or y,\n\t\t\tbar(x or y) .. x or \"\"\n\t\t}\n\tend\n\n\tdo_not_collapse_this_if_please()\nend\n\n--[[\n--]]\n"
  },
  {
    "path": "test/ifs.lua",
    "content": "--[[\n--]]\n\nif true then\n\tprint(\"if true\")\nend\n\nprint (\"something\")\n\nif false then\n\tprint(\"if false\")\nend\n\nprint (\"something\")\n\nif x then\n\tprint (\"something after\")\nend\n\nif x and false then\n\tprint(\"if and false\")\nend\n\nif x then\n\tif false then\n\t\tprint(\"if and false\")\n\tend\nend\n\nif x then\n\tif false then\n\t\tprint(\"if and false\")\n\telse\n\t\tprint(\"if and false with else!\")\n\tend\nend\n\nif x then\n\tif false then\n\t\tprint(\"if and false\")\n\telse\n\t\tprint(\"if and false with else!\")\n\tend\nelse\n\tprint (\"Else!\")\nend\n\nif x and true then\n\tprint(\"if and true\")\nend\n\nif x or false then\n\tprint(\"if or false\")\nend\n\n\nif x or true then\n\tprint(\"if or true\")\nend\n\nif x < 100 then\n\tprint (\"then\")\nelse\n\tprint (\"else\")\nend\n\nif x < 100 and y < 100 then\n\tprint (\"semi-nested then\")\nelse\n\tprint (\"else\")\nend\n\nif x < 100 or z > 100 then\n\tif y < 100 or x > 100 then\n\t\tprint (\"Nested then\")\n\tend\nend\n\nif x < 100 or z > 100 then\n\tif y < 100 or x > 100 then\n\t\tprint (\"Nested then\")\n\tend\n\n\tprint (\"Enclosure\")\nend\n\nif x < 100 or z > 100 then\n\tif y < 100 or x > 100 then\n\t\tprint (\"Nested then\")\n\telse\n\t\tprint (\"Nested else\")\n\tend\n\n\tprint (\"Enclosure\")\nend\n\nif x < 100 or z > 100 then\n\tif y < 100 or x > 100 then\n\t\tprint (\"Nested then\")\n\tend\n\n\tprint (\"Enclosure\")\nelse\n\tprint (\"Else\")\nend\n\nif x < 100 or z > 100 then\n\tif y < 300 or x > 100 then\n\t\tprint (\"Nested then\")\n\telse\n\t\tprint (\"Nested else\")\n\tend\nend\n\n\nif x < 100 or z > 100 then\n\tif y < 100 or x > 100 then\n\t\tprint (\"Nested then\")\n\tend\nelse\n\tprint (\"Else\")\nend\n\n\nif x < 100 or z > 100 then\n\tif y < 100 or x > 100 then\n\t\tprint (\"Nested then\")\n\telse\n\t\tprint (\"Nested else\")\n\tend\nelse\n\tprint (\"Else\")\nend\n\nif x < 100 or z > 100 then\n\tif y < 100 or x > 100 then\n\t\tprint (\"Nested then\")\n\telse\n\t\tprint (\"Nested else\")\n\tend\nelse\n\tif y < 100 or x > 100 then\n\t\tprint (\"Nested else then\")\n\telse\n\t\tprint (\"Nested else else\")\n\tend\nend\n\nif x < 100 or y < 100 then\n\tprint (\"x or y with comparisons\")\nend\n\n\nif x < 100 and y < 100 then\n\tprint (\"x and y with comparisons\")\nend\n\nif x < 100 or y < 100 then\n\tprint (\"x or y with comparisons\")\nelse\n\tprint (\"ELSE x or y with comparisons\")\nend\n\nif x < 100 and y < 100 then\n\tprint (\"x and y with comparisons\")\nelse\n\tprint (\"ELSE x and y with comparisons\")\nend\n\nif (x < 100 and y < 100) or z < 100 then\n\tprint (\"(and) or with comparisons\")\nelse\n\tprint (\"ELSE (and) or with comparisons\")\nend\n\nif x < 300 and y < 300 then\n\tprint (\"True terminator!\")\n\n\tif x < 300  and z < 300 then\n\t\tprint(\"Nested if\")\n\tend\nelse\n\tprint (\"False terminator!\")\n\n\tif x < 300 and z < 300 then\n\t\tprint(\"Enclosed nested if\")\n\tend\n\n\tprint (\"Enclosure\")\nend\n\nif x or y then\n\tprint (\"x or y\")\nend\n\nif x and y then\n\tprint (\"x and y\")\nend\n\nif x or y then\n\tprint (\"x or y\")\nelse\n\tprint (\"ELSE x or y\")\nend\n\nif x and y then\n\tprint (\"x and y\")\nelse\n\tprint (\"ELSE x and y\")\nend\n\nif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\tprint (\"True terminator!\")\nelse\n\tprint (\"False terminator!\")\nend\n\nif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\tprint (\"True terminator!\")\n\n\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\tprint (\"True terminator!\")\n\n\t\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\t\tprint (\"True terminator!\")\n\t\telse\n\t\t\tprint (\"False terminator!\")\n\t\tend\n\n\t\tprint (\"Enclosed\")\n\telse\n\t\tprint (\"False terminator!\")\n\tend\n\n\tprint (\"Enclosed\")\nelse\n\tprint (\"False terminator!\")\nend\n\nif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\tprint (\"True terminator!\")\n\n\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\tprint (\"True terminator!\")\n\n\t\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\t\tprint (\"True terminator!\")\n\t\telse\n\t\t\tprint (\"False terminator!\")\n\t\tend\n\n\t\tprint (\"Enclosed\")\n\telse\n\t\tprint (\"False terminator!\")\n\tend\nelse\n\tprint (\"False terminator!\")\nend\n\nif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\tprint (\"True terminator!\")\n\n\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\tprint (\"True terminator!\")\n\n\t\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\t\tprint (\"True terminator!\")\n\t\telse\n\t\t\tprint (\"False terminator!\")\n\t\tend\n\telse\n\t\tprint (\"False terminator!\")\n\tend\nelse\n\tprint (\"False terminator!\")\nend\n\nif (y < 300 or z > 300) then\n\tprint (\"True terminator!\")\n\n\tif (x < 300 and z < 300) then\n\t\tprint (\"True terminator!\")\n\n\t\tif x < 300  or z < 300 then\n\t\t\tprint (\"True terminator!\")\n\t\telse\n\t\t\tprint (\"False terminator!\")\n\t\tend\n\telse\n\t\tprint (\"False terminator!\")\n\tend\n\n\tprint (\"Enclosed\")\nelse\n\tprint (\"False terminator!\")\nend\n\nif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\tprint (\"True terminator!\")\n\n\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\tprint (\"True terminator!\")\n\n\t\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\t\tprint (\"True terminator!\")\n\t\telse\n\t\t\tprint (\"False terminator!\")\n\t\tend\n\telse\n\t\tprint (\"False terminator!\")\n\tend\nelse\n\tprint (\"False terminator!\")\n\n\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\tprint (\"True terminator!\")\n\n\t\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\t\tprint (\"True terminator!\")\n\t\telse\n\t\t\tprint (\"False terminator!\")\n\t\tend\n\telse\n\t\tprint (\"False terminator!\")\n\tend\nend\n\nif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\tprint (\"True terminator!\")\n\n\t\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\t\tprint (\"True terminator!\")\n\t\telse\n\t\t\tprint (\"False terminator!\")\n\t\tend\n\telse\n\t\tprint (\"False terminator!\")\n\tend\nelse\n\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\tprint (\"True terminator!\")\n\n\t\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\t\tprint (\"True terminator!\")\n\t\telse\n\t\t\tprint (\"False terminator!\")\n\t\tend\n\telse\n\t\tprint (\"False terminator!\")\n\tend\nend\n\nlocal a = 0\n\nif x % 2 == 0 then\n\ta = 1\nend\n\nlocal a = x % 2 == 0 or a\n\nlocal a = \"test\"\nlocal b = \"result\"\n\nif a == \"test\" then\n\tb = \"test\"\nelseif a == \"1234\" then\n\tb = \"1234\"\nelseif a == \"asd\" then\n\tb = \"asd\"\nelseif a == \"fadasd\" then\n\tb = \"fadasd\"\nelse\n\tb = \"Otherwise\"\nend\n\nprint (\"Same thing as expression\")\n\nb = (a == \"test\" and \"test\") or (a == \"1234\" and \"1234\") or (a == \"asd\" and \"asd\") or (a == \"fadasd\" and \"fadasd\") or \"Otherwise\"\n\nprint (a, b)\n\nlocal a = \"test\"\nif a == \"test\" then\n\tb = \"test\"\n\tif  a == \"1234\" then\n\t\tb = \"1234\"\n\n\t\tif a == \"asd\" then\n\t\t\ta = \"asd\"\n\n\t\t\tif a == \"fadasd\" then\n\t\t\t\tb = \"fadasd\"\n\t\t\tend\n\t\tend\n\tend\nend\n\nlocal a = \"test\"\nlocal b = \"result\"\nif a == \"test\" then\n\tb = \"test\"\n\tif a == \"test\" then\n\t\tb = \"test\"\n\telseif a == \"1234\" then\n\t\tb = \"1234\"\n\telseif a == \"asd\" then\n\t\tb = \"asd\"\n\telseif a == \"fadasd\" then\n\t\tb = \"fadasd\"\n\telse\n\t\tb = \"Otherwise\"\n\tend\nelseif a == \"1234\" then\n\tb = \"1234\"\nelseif a == \"asd\" then\n\tb = \"asd\"\nelseif a == \"fadasd\" then\n\tb = \"fadasd\"\nelse\n\tb = \"Otherwise\"\nend\n\nprint (a, b)\n\nif componentInfo.details ~= nil then\n\tlayout = componentInfo.details.layout\n\n\tif layout == \"table\" then\n\t\tmainFrame = \"tableFrame\"\n\telse\n\t\tif layout == \"header\" then\n\t\t\tmainFrame = \"headerFrame\"\n\t\telse\n\t\t\tif layout == \"long\" then\n\t\t\t\tmainFrame = \"fullFrame\"\n\t\t\telse\n\t\t\t\tif layout == \"short\" then\n\t\t\t\t\tmainFrame = \"topFrame\"\n\t\t\t\tend\n\t\t\tend\n\n\t\tend\n\tend\nend\n\nprint (\"asd\")\n\nlocal value = 1.3\n\nif scaleinfo.floorValue then\n\tvalue = math.floor(value*scaleinfo.factor)\nelse\n\tvalue = math.ceil(value*scaleinfo.factor)\nend\n\nfunction func(button, buttonElement)\n\tlocal stateEntry = buttonElement.buttonState\n\tlocal targetSlide = nil\n\n\tif buttonElement.active then\n\t\tif stateEntry.mouseClick or stateEntry.keyboardPress then\n\t\t\ttargetSlide = \"click\"\n\t\telse\n\t\t\tif stateEntry.mouseOver or stateEntry.keyboard then\n\t\t\t\ttargetSlide = \"highlight\"\n\t\t\telse\n\t\t\t\ttargetSlide = \"normal\"\n\t\t\tend\n\t\tend\n\telse\n\t\ttargetSlide = \"unselect\"\n\tend\n\n\tlocal _, curSide = getCurrentSlide(buttonElement.element)\nend\n\n\nlocal sliderelement = {}\nlocal centerValue = \"\"\n\nif sliderelement.scale[1].displayCenter then\n\tif sliderelement.scale[2] ~= nil and sliderelement.scale[2].displayCenter then\n\t\tcenterValue = formatNumber(\n\t\t\t\tmath.abs(getSliderCenterValue(sliderValue, sliderelement.scale[1])),\n\t\t\t\tsliderelement.scale[1].valueSuffix,\n\t\t\t\tmath.abs(getSliderCenterValue(sliderValue, sliderelement.scale[2])),\n\t\t\t\tsliderelement.scale[2].valueSuffix)\n\tend\nelse\n\tif sliderelement.scale[1].displayCenter then\n\t\tcenterValue = formatNumber(math.abs(getSliderCenterValue(sliderValue, sliderelement.scale[1])), sliderelement.scale[1].valueSuffix)\n\telse\n\t\tif sliderelement.scale[2] and sliderelement.scale[2].displayCenter then\n\t\t\tcenterValue = formatNumber(math.abs(getSliderCenterValue(sliderValue, sliderelement.scale[2])), sliderelement.scale[2].valueSuffix)\n\t\tend\n\tend\nend\n\nfunction setElementPosition(anarkElement, x, y, xUseHalfPixel, yUseHalfPixel)\n\tif config.verifyPixelExact then\n\t\tlocal testx = x\n\n\t\tif testx and ((xUseHalfPixel and private.offsetx % 1 == 0)\n\t\t\t\tor (not xUseHalfPixel and private.offsetx % 1 ~= 0)) then\n\t\t\ttestx = testx + 0.5\n\t\tend\n\n\t\tlocal testy = y\n\n\t\tif testy and ((yUseHalfPixel and private.offsety % 1 == 0)\n\t\t\t\tor (not yUseHalfPixel and private.offsety % 1 ~= 0)) then\n\t\t\ttesty = testy + 0.5\n\t\tend\n\n\t\tif (testx ~= nil and testx % 1 ~= 0)\n\t\t\t\tor (testy ~= nil and testy % 1 ~= 0) then\n\t\t\tDebugError(\"Widget system warning. Given position for element \" .. tostring(anarkElement) .. \" uses subpixels. This will lead to graphical issues. x/y: \" .. tostring(x) .. \" / \" .. tostring(y) .. \" - using halfpixels (x/y): \" .. tostring(xUseHalfPixel) .. \" / \" .. tostring(yUseHalfPixel))\n\t\tend\n\tend\n\n\tsetElementPositionUnchecked(anarkElement, x, y)\nend\n\nlocal relationLEDValue, maxLED, minLED, boostActive\n\nif relationLEDValue < 0 then\n\tif boostActive then\n\t\tmaxLED = maxLED - 1\n\tend\nelse\n\tminLED = relationLEDValue < 0 and boostLocal or minLED - 1\nend\n\nfunction aaa()\n\tlocal a, b, c\n\n\tif a == 0 then\n\t\tif b == 2 then\n\t\t\tprint(\"b\")\n\t\telse\n\t\t\tprint(\"bend\")\n\t\t\treturn\n\t\tend\n\telse\n\t\tfunction asd()\n\t\t\tprint(a, b, c)\n\t\tend\n\n\t\treturn\n\tend\n\n\treturn\nend\n\nlocal nins, snapref, dumpreg, snapno, printsnap, tr, snap, tracesnap\n\nfor ins=1, nins do\n\tif ins >= snapref then\n\t\tif dumpreg then\n\t\t\tout:write(format(\"\", snapno))\n\t\telse\n\t\t\tout:write(format(\"\", snapno))\n\t\tend\n\n\t\tprintsnap(tr, snap)\n\t\tsnapno = snapno + 1\n\t\tsnap = tracesnap(tr, snapno)\n\t\tsnapref = snap and snap[0] or 65536\n\tend\n\n\tlocal m, ot, op1, op2, ridsp = traceir(tr, ins)\n\tlocal oidx = shr(ot, 8)*6\n\tlocal t = band(ot, 31)\n\tlocal op = sub(irnames, oidx + 1, oidx + 6)\n\n\tprint (\"Test\")\nend\n\nif x == 0 then\n\tprint (\"then\")\nelse\nend\n\nlocal menu, x, y, test, xi\n\nprint(\"asd\")\n\nmenu.onUpdate = function ()\n\tif x and y then\n\t\ttest = x or y\n\t\n\t\tprint (\"test\")\n\n\t\tmenu.attr = x or foo(y, \"macro\")\n\tend\n\n\treturn \nend\n\nif shouldDisplayIcon(onScreen, targetElement.obstructed, (targetElement.outlined or targetElement.surfaceElement or targetElement.crate or targetElement.switchable) and targetElement.messageType ~= \"missionobjective\", targetElement.messageType == \"missionobjective\") then\n\tprint(\"asd\")\nend\n\n\nif test == 3 then\n\tprint(\"Just a test\")\nelse\nend\n\nif x == 2 then\n\tprint(\"This may crash the if else above!\")\nend\n\nlocal xi, x, y, z\n\nif xi then\n\tz = x or y\n\tz = x or y\n\tz = x or y\n\n\tprint (\"asd\")\nend\n\nif xi then\n\tlocal unlocked_defence_status = x or (y or z) < 100\n\n\tbar((x and y) or z)\nend\n\n--[[\n--]]\n"
  },
  {
    "path": "test/loop.lua",
    "content": "--[[\n--]]\n\nfor i=1, 100 do\n\tprint (\"Numeric loop\")\nend\n\nfor i=1, 100, 2 do\n\tprint (\"numeric for with step\")\nend\n\nfor i=1, 100 do\n\tfor i=1, 100 do\n\t\tprint (\"Nested numeric loop\")\n\tend\nend\n\nfor i=1, 100 do\n\tprint (\"Numeric loop with break\")\n\tbreak\nend\n\nfor i=1, 100 do\n\tfor i=1, 100 do\n\t\tprint (\"Nested numeric loop with outer break\")\n\tend\n\tbreak\nend\n\nfor i=1, 100 do\n\tfor i=1, 100 do\n\t\tprint (\"Nested numeric loop with inner break\")\n\t\tbreak\n\tend\nend\n\nfor i=1, 100 do\n\tfor i=1, 100 do\n\t\tbreak\n\tend\nend\n\n\nfor i=0, 0 do\n\tprint (\"Zero loop\")\nend\n\n\nfor key, value in pairs(t) do\n\tprint (\"iterator for\")\n\tprint(key, value)\nend\n\nfor key, value in ipairs(t) do\n\tprint(\"iterator for with another iterator\")\n\tprint(key, value)\nend\n\nfor key, value, x, y, z in iterate_over(t) do\n\tprint(\"iterator for with crazy custom iterator\")\n\tprint(key, value, x, y, z)\nend\n\na, b, c = pairs(t)\n\nfor key, value in a, b, c do\n\tprint(\"iterator for with dissected iterator\")\n\tprint(key, value)\nend\n\nx = 3\n\nwhile x > 0 do\n\tprint (\"while\")\n\n\tx = x - 1\nend\n\ny = 0\nx = y\n\nprint (\"while with emmidiate break\")\nwhile x do\n\tbreak\nend\n\nwhile x and false do\n\tprint (\"while x and false\")\nend\n\nwhile x or false do\n\tprint (\"while x or false\")\nend\n\nwhile x and true do\n\tprint (\"while x and true\")\nend\n\nwhile x or true do\n\tprint (\"while x or true\")\nend\n\nprint (\"Something\")\n\nwhile true do\n\tprint (\"while true\")\n\n\tif x then\n\t\tprint (\"something\")\n\tend\nend\n\n\nprint (\"Something\")\n\nwhile true do\n\tif x then\n\t\tprint (\"something\")\n\tend\nend\n\nprint (\"Something\")\n\nwhile true do\n\tif x then\n\t\tprint(\"something\")\n\t\tbreak\n\tend\nend\n\nwhile true do\n\tif x then\n\t\tbreak\n\tend\nend\n\n\nwhile false do\n\tprint (\"while false\")\nend\n\nwhile x do\n\tprint (\"while with copy check\")\n\tx = y\nend\n\nwhile x > 100 do\n\tprint (\"while\")\n\n\twhile x > 100 do\n\t\tprint (\"Enclosed nested while\")\n\tend\n\n\tprint (\"Enclosure\")\nend\n\nwhile x > 100 do\n\tprint (\"Enclosure\")\n\n\twhile x > 100 do\n\t\tprint (\"Enclosed from ahead nested while\")\n\tend\nend\n\nwhile x > 100 do\n\twhile x > 100 do\n\t\tprint (\"Enclosed from below nested while\")\n\tend\n\n\tprint (\"Enclosure\")\nend\n\nwhile x > 100 do\n\twhile x > 100 do\n\t\tprint (\"Nested while\")\n\tend\nend\n\nwhile x < 100 or y < 100 do\n\tprint (\"while with expression\")\n\tx = y\nend\n\nwhile x and y do\n\tprint (\"while with variables expression\")\n\tx = y\nend\n\nwhile x < 100 or y < 100 do\n\twhile x < 100 or y < 100 do\n\t\tprint (\"Nested while with expression\")\n\tend\nend\n\nif x < 100 and y < 100 then\n\twhile x < 100 or y < 100 do\n\t\twhile x < 100 or y < 100 do\n\t\t\tprint (\"Nested while with expression within if\")\n\t\tend\n\tend\nend\n\nwhile x < 100 or y < 100 do\n\tif x < 100 and y < 100 then\n\t\twhile x < 100 or y < 100 do\n\t\t\tprint (\"Nested while with expression with if in middle\")\n\t\tend\n\tend\nend\n\n\nwhile x < 100 or y < 100 do\n\tif x < 100 or y < 100 then\n\t\twhile x < 100 or y < 100 do\n\t\t\tprint (\"Nested while with expression with if in middle\")\n\t\tend\n\tend\nend\n\nwhile x < 100 or y < 100 do\n\tif x < 100 or y < 100 then\n\t\twhile x < 100 or y < 100 do\n\t\t\tprint (\"Nested while with expression with break in middle\")\n\t\tend\n\t\tbreak\n\tend\nend\n\nwhile x < 100 or y < 100 do\n\tif x < 100 or y < 100 then\n\t\twhile x < 100 or y < 100 do\n\t\t\tprint (\"Nested while with expression with break in the end\")\n\t\t\tbreak\n\t\tend\n\tend\nend\n\nwhile x < 100 or y < 100 do\n\tif (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 then\n\t\twhile x < 100 or y < 100 do\n\t\t\tprint (\"Nested while with really complex expression\")\n\t\tend\n\tend\nend\n\nwhile (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 do\n\tif (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 then\n\t\twhile x < 100 or y < 100 do\n\t\t\tprint (\"Nested while with really complex expression\")\n\t\tend\n\tend\nend\nwhile x < 100 and y < 100 do\n\tif x < 100 or y < 100 then\n\t\twhile (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 do\n\t\t\tprint (\"Nested while with really complex expression\")\n\t\tend\n\tend\nend\n\nwhile (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 do\n\tif (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 then\n\t\twhile (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 do\n\t\t\tif (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 then\n\t\t\t\tprint (\"Nested while with really complex expression\")\n\t\t\tend\n\t\tend\n\tend\nend\n\nwhile (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 do\n\tif (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 then\n\t\twhile (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 do\n\t\t\tif (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 then\n\t\t\t\tprint (\"Nested while with really complex expression\")\n\n\t\t\t\tbreak\n\t\t\tend\n\t\tend\n\tend\nend\n\nrepeat\n\tprint (\"repeat until with copy check\")\n\tx = y\nuntil not x\n\nrepeat\n\tprint (\"repeat until with copy check\")\n\tx = y\nuntil not x\n\nrepeat\n\tprint (\"Repeat until with break\")\n\tbreak\nuntil x < 3\n\n\nrepeat\n\tprint (\"Enclosed\")\n\n\trepeat\n\t\tprint (\"Nested repeat until\")\n\tuntil x < 3\n\n\tprint (\"Enclosed\")\nuntil x < 3\n\nrepeat\n\trepeat\n\t\tprint (\"Nested repeat until\")\n\tuntil x < 3\n\n\tprint (\"Enclosed\")\nuntil x < 3\n\nrepeat\n\trepeat\n\t\tprint (\"Nested repeat until\")\n\tuntil x < 3\nuntil x < 3\n\nrepeat\n\tprint (\"repeat until\")\n\tx = x + 1\nuntil x > 5 or x < 3\n\nrepeat\n\tprint (\"Repeat until with expression\")\nuntil x < 3 and y < 3\n\nrepeat\n\tprint (\"Repeat until with expression\")\n\trepeat\n\t\tprint (\"Repeat until with expression\")\n\tuntil x < 3 or y < 3\nuntil x < 3 and y < 3\n\nrepeat\n\tif (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 then\n\t\tprint (\"Repeat until with expression\")\n\t\trepeat\n\t\t\tif (((x < 100 or y < 100 and z < 100)) or x > 300) and z == 3 then\n\t\t\t\tprint (\"Repeat until with expression\")\n\t\t\tend\n\t\tuntil x < 3 or y < 3\n\tend\nuntil x < 3 and y < 3\n\n--[[\n--]]\n\nif x then\n\tfor i=1,2,3 do\n\t\tprint (\"something\")\n\n\t\tif y then\n\t\t\tbreak\n\t\tend\n\n\t\tprint (\"something\")\n\tend\nelse\n\tprint(\"else\")\nend\n"
  },
  {
    "path": "test/primitive.lua",
    "content": "function assignment()\n\tfunction generator()\n\t\treturn 1, 2, 3\n\tend\n\n\ta = 1\n\tb, c, d = nil\n\te, f, g = 1, 2, 3\n\tlocal i, k, l = 3, 2, g + 1\n\t\n\tlocal m, n, o, p = 1, generator()\n\n\tprint (a, b, c, d, e, f, g, i, k, l)\nend\n\nfunction vararg(...)\n\ta = ...\n\tc, d = ...\n\tt = {...}\n\ts = {1, 2, 3, ...}\n\n\tlocal f, g, h = ...\n\n\tt.x = ...\n\n\tassignment(...)\n\n\tif t.x == 3 then\n\t\treturn a, t, s, ...\n\telse\n\t\treturn ...\n\tend\nend\n\nfunction tables()\n\tfunction generator(x, y, z)\n\t\treturn x, y, z\n\tend\n\n\tt = {\n\t\t[123.322] = 3,\n\t\t[3] = {\n\t\t\t\"a\", \"b\", \"c\"\n\t\t},\n\t\tgenerator(\"a\", \"b\", \"c\"),\n\t\tgenerator(\"d\", \"e\", \"f\")\n\t}\n\n\tt.var = 1\n\tt.str = \"Nope\"\n\n\tfunction t:foo(var)\n\t\tself.var = var;\n\t\tself.str = \"!!!\" .. var \n\tend \n\n\tt:foo(123)\n\n\tprint(t)\nend\n\nfunction logical()\n\tx = 3\n\n\tprint (\"if true\")\n\n\tif true then\n\t\tprint (\"That's true\")\n\tend\n\n\tprint (\"if false\")\n\n\tif false then\n\t\tprint (\"That's false\")\n\tend\n\n\tprint (\"Ordinary if\")\n\n\tif x == 123 then\n\t\tprint (\"Good number\")\n\tend\n\n\tprint (\"No then, only else\")\n\n\tif x == 1 then\n\telse\n\t\tprint (\"Not one!\")\n\tend\n\n\tprint (\"elseifs\")\n\n\tif x == 3 then\n\t\tprint(\"is three!\")\n\telseif x == 5 then\n\t\tprint(\"is five!\")\n\telseif x == 8 then\n\t\tprint(\"is eight!\")\n\t\treturn\n\telse\n\t\tprint(\"is something else!\")\n\tend\n\n\tprint (\"ordinary if\")\n\n\tif x == 6 then\n\t\tprint(\"Is six!\")\n\telse\n\t\tprint(\"Whatever else!\")\n\tend\t\n\n\tprint (\"The same if as expression\")\n\n\tlocal a = ((x == 6) and print(\"Is six!\")) or print(\"Whatever else!\")\n\n\tprint (\"Nested if\")\n\n\tif x == 666 then\n\t\tprint(\"Hellish X!\")\n\n\t\tif x > 321 then\n\t\t\tif x > 333 then\n\t\t\t\tprint (\"X > 321 AND 333 - Isn't that obvious already?\")\n\t\t\tend\n\t\telse\n\t\t\tprint (\"Seriously???\")\n\t\tend\n\telse\n\t\tprint(\"Not bad enough!\")\n\n\t\tif x ~= 42 then\n\t\t\tprint (\"And it doesn't answer anything\")\n\t\tend\n\tend\nend\n\nfunction logical_expressions()\n\tx = 0\n\ty = 1\n\tz = 2\n\n\tprint (\"simple or expression\")\n\n\tb = x or y\n\n\tprint (\"simple or not expression\")\n\n\tb = not x or y\n\n\tprint (\"simple and expression\")\n\n\tb = x and y\n\n\tprint (\"simple or expression with binary comparison\")\n\n\tb = (x < 100) or y\n\n\tprint (\"simple and expression with binary comparison\")\n\n\tb = (x < 100) and y\n\n\tprint (\"simple and expression with binary comparison and function call\")\n\n\tb = (x < 100) and print(y)\n\n\tprint (\"simple and expression with double binary comparison\")\n\n\tb = (x < 100) and (y > 100)\n\n\tprint (\"(and) or expression\")\n\n\tb = (x and y) or z\n\n\tprint (\"(or) and expression\")\n\n\tb = (x or y) and z\n\tprint (\"(and) and expression\")\n\n\tb = (x and y) and z\n\n\tprint (\"(or) or expression\")\n\tb = (x or y) or z\n\n\tprint (\"or (and) expression\")\n\n\tb = x or (y and x)\n\n\tprint (\"and (or) expression\")\n\n\tb = x and (y or x)\n\n\tprint (\"and (and) expression\")\n\n\tb = x and (y and x)\n\n\tprint (\"or (or) expression\")\n\n\tb = x or (y or x)\n\n\tprint (\"ond (or) and expression\")\n\n\tb = x and (y or x) and z\n\n\tprint (\"or (and) or expression\")\n\n\tb = x or (y and x) or z\n\n\tprint (\"and of two ors\")\n\n\tb = (x or z) and (y or z)\n\n\tprint (\"or of two ands\")\n\n\tb = (x and z) or (y and z)\n\n\tprint (\"and (or) and (or) expression with comparisons\")\n\n\tb = x < 100 and (y < 100 or x < 100) and (z < 100 or x < 100)\n\n\tprint (\"and (or) and or expression with comparisons\")\n\n\tb = x < 100 and (y < 100 or x < 100) and z < 100 or x < 100\n\n\tprint (\"or (and) or (and) expression with comparisons\")\n\n\tb = x < 100 or (y < 100 and x < 100) or (z < 100 and x < 100)\n\n\tprint (\"and (and) and (and) expression with comparisons\")\n\n\tb = x < 100 and (y < 100 and x < 100) and (z < 100 and x < 100)\n\n\tprint (\"or (or) or (or) expression with comparisons\")\n\n\tb = x < 100 or (y < 100 or x < 100) or (z < 100 or x < 100)\n\n\tprint (\"4 and expression with comparisons\")\n\n\tb = x < 100 and y < 100 and x < 100 and z < 100 and x < 100\n\n\tprint (\"4 or expression with comparisons\")\n\n\tb = x < 100 or y < 100 or x < 100 or z < 100 or x < 100\n\n\tprint (\"and (or or) and (or or) expression with comparisons\")\n\n\tb = x < 100 and (y < 100 or x < 100 or z < 100)\n\t\t\tand (y < 100 or x < 100 or z < 100)\n\tprint (\"and (or and or) and (or and or) expression with comparisons\")\n\n\tb = x < 100 and (y < 100 or (x < 100 and x > 100) or z < 100)\n\t\t\tand (y < 100 or (x < 100 and x > 100) or z < 100)\n\n\tprint (\"or (and or and) or (and or and) expression with comparisons\")\n\n\tb = x < 100 or (y < 100 and (x < 100 or x > 100) and z < 100)\n\t\t\tor (y < 100 and (x < 100 or x > 100) and z < 100)\n\n\tprint (\"simple or and expression with binary comparison\")\n\n\tb = x or (y and (x < 100))\n\n\tprint (\"normal logical expression\")\n\n\tb = (x and y) or ((y > 3) and (((x/2) < 1) or (y > 100)) and (x ~= 2))\n\n\tprint (\"precalculated true expression\")\n\n\tc = true or (x and y) or true\n\n\tprint (\"precalculated false expression\")\n\n\td = false and ((x and y) or true)\n\n\tprint (\"precalculated false expression with function\")\n\n\te = error() and false and ((x and y) or true)\n\n\tprint (\"precalculated true expression with function\")\n\n\te = error() and true and ((x and y) or true)\n\n\tprint (\"precalculated? false expression with variable\")\n\n\tlocal z = false\n\n\tf = z and ((x and y) or true)\n\n\tprint (\"precalculated false expression with nil\")\n\n\tf = nil and ((x and y) or true)\n\t\n\tprint(\"if with expression\")\n\n\ta = x or y\n\ta = x and y\n\ta = x < 100 or y < 100\n\ta = x < 100 and y < 100\n\n\tif x or y then\n\t\tprint (\"x or y\")\n\tend\n\n\tif x and y then\n\t\tprint (\"x and y\")\n\tend\n\n\tif x < 100 or y < 100 then\n\t\tprint (\"x or y with comparisons\")\n\tend\n\n\tif x < 100 and y < 100 then\n\t\tprint (\"x and y with comparisons\")\n\tend\n\n\tif x or y then\n\t\tprint (\"x or y\")\n\telse\n\t\tprint (\"ELSE x or y\")\n\tend\n\n\tif x and y then\n\t\tprint (\"x and y\")\n\telse\n\t\tprint (\"ELSE x and y\")\n\tend\n\n\tif x < 100 or y < 100 then\n\t\tprint (\"x or y with comparisons\")\n\telse\n\t\tprint (\"ELSE x or y with comparisons\")\n\tend\n\n\tif x < 100 and y < 100 then\n\t\tprint (\"x and y with comparisons\")\n\telse\n\t\tprint (\"ELSE x and y with comparisons\")\n\tend\n\n\tif (x < 100 and y < 100) or z < 100 then\n\t\tprint (\"(and) or with comparisons\")\n\telse\n\t\tprint (\"ELSE (and) or with comparisons\")\n\tend\n\n\tif (x < 300 and (y < 300 or z > 300)) or z < 300 and error() then\n\t\tprint (\"True terminator!\")\n\telse\n\t\tprint (\"False terminator!\")\n\tend\n\n\tif x < 300 and y < 300 then\n\t\tprint (\"True terminator!\")\n\n\t\tif x < 300  and z < 300 then\n\t\t\tprint(\"Nested if\")\n\t\tend\n\telse\n\t\tprint (\"False terminator!\")\n\n\t\tif x < 300 and z < 300 then\n\t\t\tprint(\"Enclosed nested if\")\n\t\tend\n\n\t\tprint (\"Enclosure\")\n\tend\n\n\twhile x > 300 and y < 300 do\n\t\tprint (\"In while\")\n\tend\n\n\trepeat\n\t\tprint (\"In repeat until\")\n\tuntil x < 300 and y > 300\n\n\tprint(x, y, b, c, d, e, f)\nend\n\nfunction functions()\n\tfunction func1(x, y)\n\t\tfunction sub(z)\n\t\t\treturn z\n\t\tend\n\n\t\treturn x, y, sub\n\tend\n\n\tx, y, z = func1(1, 2)\n\tprint(z(4))\n\n\tx = func1(1, 2)\n\n\tfunc1(1, 2)\n\n\tfunction func2(x)\n\t\tprint (x)\n\tend\n\n\tfunction func3(x)\n\t\treturn x*2\n\tend\n\n\tfunc2(func3(3))\n\n\tfunction func4(x, y, z)\n\t\tprint (x, y, z)\n\tend\n\n\tfunc4(1, 2, func2(3))\nend\n\nfunction locals(x, y, ...)\n\tlocal a, b, c = ...\n\n\tfunction generator()\n\t\treturn 1, 2, 3\n\tend\n\n\tlocal d, e, f  = generator()\n\n\tlocal g, h, i, k = 4, generator()\n\n\tlocal l, m, n = f, e\nend\n\n\nfunction loops()\n\tfunction iterate_over(table)\n\t\tfunction iterator(table, index)\n\t\t\tkey, value = next(table, index)\n\n\t\t\treturn key, value, 1, 2, 3\n\t\tend\n\n\t\treturn iterator, table, nil\n\tend\n\n\tt = {1, 2, 3}\n\n\tprint (\"numeric for without step\")\n\n\tfor i=1, 100 do\n\t\tprint(i)\n\tend\n\n\tprint (\"numeric for with step\")\n\n\tfor i=1, 100, 2 do\n\t\tprint(i)\n\tend\n\n\tprint (\"iterator for\")\n\n\tfor key, value in pairs(t) do\n\t\tprint(key, value)\n\tend\n\n\tprint(\"iterator for with another iterator\")\n\n\tfor key, value in ipairs(t) do\n\t\tprint(key, value)\n\tend\n\n\tprint(\"iterator for with crazy custom iterator\")\n\n\tfor key, value, x, y, z in iterate_over(t) do\n\t\tprint(key, value, x, y, z)\n\tend\n\n\tprint(\"iterator for with dissected iterator\")\n\n\ta, b, c = pairs(t)\n\n\tfor key, value in a, b, c do\n\t\tprint(key, value)\n\tend\n\n\tprint (\"while\")\n\n\tx = 3\n\n\twhile x > 0 do\n\t\tx = x - 1\n\tend\n\t\n\tprint (\"while with copy check\")\n\n\ty = 0\n\tx = y\n\n\twhile x do\n\t\tx = y\n\tend\n\n\tprint (\"repeat until\")\n\n\trepeat\n\t\tx = x + 1\n\tuntil x > 5\n\n\tprint (\"repeat until with copy check\")\n\n\trepeat\n\t\tx = y\n\tuntil not x\n\n\tprint (\"While with break\")\n\n\twhile x > 5 do\n\t\tbreak\n\tend\n\n\tprint (\"Repeat until with break\")\n\n\trepeat\n\t\tbreak\n\tuntil x < 3\n\n\tprint (\"Numeric for with break\")\n\n\tfor i=0,1,2 do\n\t\tbreak\n\tend\n\n\tprint (\"Iterator for with break\")\n\n\tfor key,value in pairs(t) do\n\t\tbreak\n\tend\n\n\tprint (\"Loop with break and function inside\")\n\n\tt = {}\n\n\tfor i=0,100 do\n\t\ty = 3\n\t\tt[i] = function ()\n\t\t\treturn i + y\n\t\tend\n\n\t\tif i == 5 then\n\t\t\tprint (\"then\")\n\t\t\tbreak\n\t\telse\n\t\t\tprint (\"else\")\n\t\tend\n\tend\nend\n\nfunction upvalues()\n\ttest = 0\n\n\tfunction sub(x)\n\t\ttest = test + 1\n\t\ttest = 3\n\t\ttest = \"asd\"\n\t\ttest = 4.0\n\t\treturn test + x\n\tend\n\n\tprint(sub(3))\nend\n\n\nfunction subblock()\n\tprint (\"Subblock with locals\")\n\n\tx = 3\n\n\tdo\n\t\tlocal a = 2\n\n\t\tprint(a + x)\n\tend\n\n\ty = 4\nend\n"
  }
]