Meta icon indicating copy to clipboard operation
Meta copied to clipboard

List comprehension not decompiled

Open mristin opened this issue 7 years ago • 7 comments

Hi, Similar to issue #41, the list comprehension is not decompiled:

>>> import meta.decompiler
>>> meta.decompiler.decompile_func(lambda x: [i for i in range(x)])

This gives me a traceback:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/marko/workspace/pqryopen/icontract/venv3/lib/python3.5/site-packages/meta/decompiler/__init__.py", line 37, in decompile_func
    ast_node = make_function(code, defaults=[], lineno=code.co_firstlineno)
  File "/home/marko/workspace/pqryopen/icontract/venv3/lib/python3.5/site-packages/meta/decompiler/instructions.py", line 137, in make_function
    stmnts = instructions.stmnt()
  File "/home/marko/workspace/pqryopen/icontract/venv3/lib/python3.5/site-packages/meta/decompiler/instructions.py", line 310, in stmnt
    self.visit(instr)
  File "/home/marko/workspace/pqryopen/icontract/venv3/lib/python3.5/site-packages/meta/decompiler/instructions.py", line 324, in visit
    method(instr)
  File "/home/marko/workspace/pqryopen/icontract/venv3/lib/python3.5/site-packages/meta/decompiler/instructions.py", line 372, in MAKE_FUNCTION
    function = make_function(code, defaults, lineno=instr.lineno, annotations=annotations, kw_defaults=kw_defaults)
  File "/home/marko/workspace/pqryopen/icontract/venv3/lib/python3.5/site-packages/meta/decompiler/instructions.py", line 135, in make_function
    instructions = Instructions(disassemble(code))
  File "/home/marko/workspace/pqryopen/icontract/venv3/lib/python3.5/site-packages/meta/decompiler/disassemble.py", line 20, in disassemble
    return list(disassembler(co))
  File "/home/marko/workspace/pqryopen/icontract/venv3/lib/python3.5/site-packages/meta/bytecodetools/disassembler_.py", line 25, in disassembler
    code = co.co_code
AttributeError: 'Str' object has no attribute 'co_code'

I suppose the solution to #41 will be the same as here?

mristin avatar Aug 24 '18 07:08 mristin

Hi @srossross , Any chance you could have a look at this issue the next week? It is blocking us to write predicates in our contracts (https://github.com/Parquery/icontract) and they are so omnipresent that it is hard to re-write them in a different way.

I'd really like to give you a hand with these issues. Please let me know how I could help -- maybe we could schedule a skype meeting with a shared screen and look at it together for a while (max 30min) and I would try to figure out how to fix the problem in more depth afterwards on my own?

I would be available for a call from Sept 8th onward.

mristin avatar Aug 31 '18 10:08 mristin

The offending object is on meta/bytecodetools/disassembler_.py:29:

def disassembler(co, lasti= -1):
    """Disassemble a code object. 
    
    :param co: code object
    :param lasti: internal
    :yields: Instructions.
    
    """
    print('''co is {}'''.format(co))  # TODO: debug remove
    if hasattr(co, 's'):
        print('''co.s is {}'''.format(co.s))  # TODO: debug remove

    code = co.co_code

In the offending case, the output is:

co is <_ast.Str object at 0x7fe9e3fdb4a8>
co.s is <lambda>.<locals>.<genexpr>

mristin avatar Aug 31 '18 10:08 mristin

Here is the trace of some values as they pass through the functions:

in meta.decompiler.instructions.make_function: code is <code object <lambda> at 0x7fbd38ed6780, file "/home/marko/.PyCharmCE2018.1/config/scratches/scratch.py", line 2>
in meta.decompiler.disassemble.disassemble: co is <code object <lambda> at 0x7fbd38ed6780, file "/home/marko/.PyCharmCE2018.1/config/scratches/scratch.py", line 2>
in meta.bytecodetools.disassembler_: co is <code object <lambda> at 0x7fbd38ed6780, file "/home/marko/.PyCharmCE2018.1/config/scratches/scratch.py", line 2>
in meta.decompiler.instructions.visit: instr is   2           0 LOAD_CONST               1 (<code object <listcomp> at 0x7fbd3a4ab9c0, file "/home/marko/.PyCharmCE2018.1/config/scratches/scratch.py", line 2>)
in meta.decompiler.instructions.visit: instr is               3 LOAD_CONST               2 ('<lambda>.<locals>.<listcomp>')
in meta.decompiler.instructions.visit: instr is               6 MAKE_FUNCTION            0
in meta.decompiler.instructions.MAKE_FUNCTION: code is <_ast.Str object at 0x7fbd38e60cc0>
in meta.decompiler.instructions.make_function: code is <_ast.Str object at 0x7fbd38e60cc0>
in meta.decompiler.disassemble.disassemble: co is <_ast.Str object at 0x7fbd38e60cc0>
in meta.bytecodetools.disassembler_: co is <_ast.Str object at 0x7fbd38e60cc0>
co.s is <lambda>.<locals>.<listcomp>

The content of the scratch file is:

import meta.decompiler
meta.decompiler.decompile_func(lambda x: [i for i in range(x)])

mristin avatar Aug 31 '18 10:08 mristin

Hi @srossross , Is there any chance that you might find time to look into this with me this week?

I don't expect it to take more than 30 minutes, I would just like to discuss with you what the exact problem is (and whether there are bigger repercussions which I am unaware of) before starting to work on a pull request.

Please also let me know if you are busy and won't have any spare time soon so that we dive into the code without any previous discussion and hack out the pull request.

mristin avatar Sep 10 '18 07:09 mristin

Hi @mristin, my time to work on this in the coming months will be very tight. It would be great if you could create a pull request.

srossross avatar Sep 10 '18 16:09 srossross

Hi @srossross ,

Thanks for letting me know. I've just started with the issue #39 .

mristin avatar Sep 11 '18 05:09 mristin

Hi @srossross , I tried hard with #39, but realized on the way that updating meta library for our purposes is actually a cause perdu. We would always have to keep up with new Python versions and this is much of an overkill for our application (getting the source code from a lambda function).

In the end, I decided to remove dependency on meta from icontract library (https://github.com/Parquery/icontract/commit/0e3edf5194fee9609d0b32e56ece7b288421570b) and decided to reparse the whole source code from the file. This approach, while way less efficient than using meta, works for our use cases and hopefully needs fewer updates with new Python versions.

I'll leave the issues open in case somebody wants to jump in and fix them.

mristin avatar Sep 16 '18 07:09 mristin