Meta icon indicating copy to clipboard operation
Meta copied to clipboard

Can't decompile chained conditional

Open Suor opened this issue 13 years ago • 6 comments

This won't decompile:

lambda: 1 if x else 2 if y else 3

Suor avatar Nov 28 '12 03:11 Suor

Thanks for testing this.

I'm glad to know it is being used. (I'll put some more effort into the test suite) You will have to wait until after the weekend though.

srossross avatar Nov 28 '12 04:11 srossross

Thanks for fast response, but your fix doesn't work for me. I pulled your development branch and tests work, but when I do:

In [1]: from meta.decompiler import decompile_func

In [2]: decompile_func(lambda: 1 if x else 2)
Out[2]: <_ast.Lambda at 0x23bdbd0>

In [3]: decompile_func(lambda: 1 if x else 2 if y else 3)
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-3-e268d849301c> in <module>()
----> 1 decompile_func(lambda: 1 if x else 2 if y else 3)

/home/suor/projects/xxauto.ru/Meta/meta/decompiler/__init__.pyc in decompile_func(func)
     35 #        default_names = []
     36 #    defaults = [_ast.Name(id='%s_default' % name, ctx=_ast.Load() , lineno=0, col_offset=0) for name in default_names]
---> 37     ast_node = make_function(code, defaults=[], lineno=code.co_firstlineno)
     38 
     39     return ast_node

/home/suor/projects/xxauto.ru/Meta/meta/decompiler/instructions.pyc in make_function(code, defaults, lineno)
    100                     stmnts = [_ast.Return(_ast.IfExp(stmnts[0].test, stmnts[0].body[0].value, stmnts[1].value))]
    101 
--> 102             assert len(stmnts) == 1, stmnts
    103             assert isinstance(stmnts[0], _ast.Return)
    104 

AssertionError: [<_ast.If object at 0x23c40d0>, <_ast.If object at 0x23c4210>, <_ast.Return object at 0x23c41d0>]

Suor avatar Nov 28 '12 05:11 Suor

Also It looks like it works for not lambda functions, but resulting ast contain If and Return nodes not IfExp and single Return:

In [11]: def hi(x,y): return 1 if x else 2 if y else 3

In [12]: print_ast(decompile_func(hi))
FunctionDef(args=arguments(args=[Name(ctx=Param(), 
                                      id='x'), 
                                 Name(ctx=Param(), 
                                      id='y')], 
                           defaults=[], 
                           kwarg=None, 
                           vararg=None), 
            body=[If(body=[Return(value=Num(n=1))], 
                     orelse=[], 
                     test=Name(ctx=Load(), 
                               id='x')), 
                  If(body=[Return(value=Num(n=2))], 
                     orelse=[], 
                     test=Name(ctx=Load(), 
                               id='y')), 
                  Return(value=Num(n=3))], 
            decorator_list=[], 
            name='hi')

That's what I expect to get:

In [19]: print_ast(ast.parse(inspect.getsource(hi)))
Module(body=[FunctionDef(args=arguments(args=[Name(ctx=Param(), 
                                                   id='x'), 
                                              Name(ctx=Param(), 
                                                   id='y')], 
                                        defaults=[], 
                                        kwarg=None, 
                                        vararg=None), 
                         body=[Return(value=IfExp(body=Num(n=1), 
                                                  orelse=IfExp(body=Num(n=2), 
                                                               orelse=Num(n=3), 
                                                               test=Name(ctx=Load(), 
                                                                         id='y')), 
                                                  test=Name(ctx=Load(), 
                                                            id='x')))], 
                         decorator_list=[], 
                         name='hi')])

Suor avatar Nov 28 '12 05:11 Suor

Sure it's kind of equivalent but surely won't work with lambdas

Suor avatar Nov 28 '12 05:11 Suor

Right. Thanks

FYI: If you look at the byte-code generated either of these two AST's they are identical.

dis.dis(compile(_ast.Module([decompile_func(hi)]),'<>','exec').co_consts[0])
dis.dis(hi)

srossross avatar Nov 28 '12 06:11 srossross

Thanks. And it was fast ;)

Suor avatar Nov 28 '12 06:11 Suor