Skip to content

Commit

Permalink
fix: supports missing operations
Browse files Browse the repository at this point in the history
  • Loading branch information
yetone committed Nov 15, 2023
1 parent bbd2953 commit 94d038d
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 6 deletions.
1 change: 1 addition & 0 deletions olo/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
PY2 = sys.version_info[0] == 2
PY39 = sys.version_info[:2] >= (3, 9)
PY310 = sys.version_info[:2] >= (3, 10)
PY311 = sys.version_info[:2] >= (3, 11)

if PY2:
from future_builtins import zip as izip, map as imap
Expand Down
121 changes: 115 additions & 6 deletions olo/libs/decompiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# and is released under the Apache 2.0 license: https://www.apache.org/licenses/LICENSE-2.0

from __future__ import absolute_import, print_function, division
from olo.compat import PY2, PY310, izip, xrange
from olo.compat import PY2, PY310, PY311, izip, xrange

import sys
import types
Expand Down Expand Up @@ -137,18 +137,30 @@ def decompile(decompiler):
oparg * 65536
)
i += 2

opname = opnames[op].replace('+', '_')
if op >= HAVE_ARGUMENT:
if op in hasconst:
arg = [code.co_consts[oparg]]
elif op in hasname:
arg = [code.co_names[oparg]]
if opname == 'LOAD_GLOBAL':
push_null = False
if PY311:
push_null = oparg & 1
oparg >>= 1
arg = [code.co_names[oparg], push_null]
else:
arg = [code.co_names[oparg]]
elif op in hasjrel:
arg = [i + oparg * (2 if PY310 else 1)]
arg = [i + oparg * (2 if PY310 else 1)
* (-1 if 'BACKWARD' in opname else 1)]
elif op in haslocal:
arg = [code.co_varnames[oparg]]
elif op in hascompare:
arg = [cmp_op[oparg]]
elif op in hasfree:
if PY311:
oparg -= len(code.co_varnames)
arg = [free[oparg]]
elif op in hasjabs:
arg = [oparg * (2 if PY310 else 1)]
Expand Down Expand Up @@ -317,11 +329,38 @@ def CALL_METHOD(decompiler, argc):
method = pop()
return ast.CallFunc(method, args)

def CACHE(decompiler):
pass

def CALL(decompiler, argc):
values = decompiler.pop_items(argc)

keys = decompiler.kw_names
decompiler.kw_names = None

args = values
keywords = []
if keys:
args = values[:-len(keys)]
keywords = [ast.keyword(k, v) for k, v in zip(keys, values[-len(keys):])]

self = decompiler.stack.pop()
callable_ = decompiler.stack.pop()
if callable_ is None:
callable_ = self
else:
args.insert(0, self)
decompiler.stack.append(callable_)
return decompiler._call_function(args, keywords)

def COMPARE_OP(decompiler, op):
oper2 = decompiler.stack.pop()
oper1 = decompiler.stack.pop()
return ast.Compare(oper1, [(op, oper2)])

def COPY_FREE_VARS(decompiler, n):
pass

def DUP_TOP(decompiler):
return decompiler.stack[-1]

Expand Down Expand Up @@ -405,9 +444,37 @@ def JUMP_FORWARD(decompiler, endpos):
decompiler.targets[endpos] = if_exp
return if_exp

def LIST_APPEND(decompiler, offset=None):
throw(InvalidQuery, 'Use generator expression (... for ... in ...) '
'instead of list comprehension [... for ... in ...] inside query') # noqa

def LIST_APPEND(decompiler, offset):
tos = decompiler.stack.pop()
list_node = decompiler.stack[-offset]
if isinstance(list_node, ast.comprehension):
throw(InvalidQuery('Use generator expression (... for ... in ...) '
'instead of list comprehension [... for ... in ...] inside query'))

assert isinstance(list_node, ast.List), list_node
list_node.elts.append(tos)

def LIST_EXTEND(decompiler, offset):
if offset != 1:
raise NotImplementedError(offset)
items = decompiler.stack.pop()
if not isinstance(items, ast.Constant):
raise NotImplementedError(type(items))
if not isinstance(items.value, tuple):
raise NotImplementedError(type(items.value))
lst = decompiler.stack.pop()
if not isinstance(lst, ast.List):
raise NotImplementedError(type(lst))
values = [make_const(v) for v in items.value]
lst.elts.extend(values)
return lst

def LIST_TO_TUPLE(decompiler):
tos = decompiler.stack.pop()
if not isinstance(tos, ast.List):
throw(InvalidQuery, "Translation error, please contact developers: list expected, got: %r" % tos)
return ast.Tuple(tos.elts, ast.Load())

def LOAD_ATTR(decompiler, attr_name):
return ast.Getattr(decompiler.stack.pop(), attr_name)
Expand Down Expand Up @@ -470,8 +537,44 @@ def MAKE_FUNCTION(decompiler, argc):
flags = 0 # todo
return ast.Lambda(argnames, defaults, flags, func_decompiler.ast)

def conditional_jump_none_impl(decompiler, endpos, negate):
expr = decompiler.stack.pop()
assert(decompiler.pos < decompiler.conditions_end)
if decompiler.pos in decompiler.or_jumps:
clausetype = ast.Or
op = ast.IsNot if negate else ast.Is
else:
clausetype = ast.And
op = ast.Is if negate else ast.IsNot
expr = ast.Compare(expr, [op()], [ast.Constant(None)])
decompiler.stack.append(expr)

if decompiler.next_pos in decompiler.targets:
decompiler.process_target(decompiler.next_pos)

expr = decompiler.stack.pop()
clause = ast.BoolOp(op=clausetype(), values=[expr])
clause.endpos = endpos
decompiler.targets.setdefault(endpos, clause)
return clause

def jump_if_none(decompiler, endpos):
return decompiler.conditional_jump_none_impl(endpos, False)

def jump_if_not_none(decompiler, endpos):
return decompiler.conditional_jump_none_impl(endpos, True)


POP_JUMP_BACKWARD_IF_FALSE = JUMP_IF_FALSE
POP_JUMP_BACKWARD_IF_TRUE = JUMP_IF_TRUE
POP_JUMP_FORWARD_IF_FALSE = JUMP_IF_FALSE
POP_JUMP_FORWARD_IF_TRUE = JUMP_IF_TRUE
POP_JUMP_IF_FALSE = JUMP_IF_FALSE
POP_JUMP_IF_TRUE = JUMP_IF_TRUE
POP_JUMP_BACKWARD_IF_NONE = jump_if_none
POP_JUMP_BACKWARD_IF_NOT_NONE = jump_if_not_none
POP_JUMP_FORWARD_IF_NONE = jump_if_none
POP_JUMP_FORWARD_IF_NOT_NONE = jump_if_not_none

def POP_TOP(decompiler):
pass
Expand All @@ -483,6 +586,12 @@ def RETURN_VALUE(decompiler):
decompiler.stack.append(simplify(expr))
raise AstGenerated()

def RETURN_GENERATOR(decompiler):
pass

def RESUME(decompiler, where):
pass

def ROT_TWO(decompiler):
tos = decompiler.stack.pop()
tos1 = decompiler.stack.pop()
Expand Down

0 comments on commit 94d038d

Please sign in to comment.