Have you looked at the built-in AST module, ast?
https://docs.python.org/3/library/ast.html
I don’t see anything preventing you from walking the AST Python itself can give
you- you’d look for two Set AST nodes if we were to do {{ }}.
There’s also the parser built-in module. You can use it if you first use
dis.code_info to get the source then re-parse it. It helps with parse trees.
Parse trees are generated before the AST I think. You’d use the parser module’s
ST objects with the token module’s constants, for example token.LBRACE or
token.RBRACE.
Have you looked at the built-in dis module? You can use dis.code_info(obj) to
get the string of the function. Then you could look for your specified syntax
with regex and recompile that with the ast module.
Sent from my iPhone
> On Sep 25, 2018, at 1:49 AM, Marko Ristin-Kaufmann <[email protected]>
> wrote:
>
> Hi James,
> Thanks for the feedback!
>
> I also thought about decompiling the condition to find its AST and figure out
> what old values are needed. However, this is not so easily done at the moment
> as all the decompilation libraries I looked at (meta, ucompyle6) are simply
> struggling to keep up with the development of the python bytecode. In other
> words, the decompiler needs to be updated with every new version of python
> which is kind of a loosing race (unless the python devs themselves don't
> provide this functionality which is not the case as far as I know).
>
> There is macropy (https://github.com/lihaoyi/macropy) which was suggested on
> the other thread
> (https://groups.google.com/forum/#!topic/python-ideas/dmXz_7LH4GI) that I'm
> currently looking at.
>
> Cheers,
> Marko
>
>
>> On Tue, 25 Sep 2018 at 00:35, James Lu <[email protected]> wrote:
>> You could disassemble (import dis) the lambda to biew the names of the
>> lambdas.
>>
>> @before(lambda self, key, _, length, get: self.length(), self.get(key))
>>
>> Perhaps you could disassemble the function code and look at all operations
>> or accesses that are done to “old.” and evaluate those expressions before
>> the function runs. Then you could “replace” the expression.
>> @post(lambda self, key, old: old.get is None and old.length + 1 ==
>> self.length())
>>
>> Either the system would grab old.get and old.length or be greedy and grab
>> old.get is None and old.length + 1. It would then replace the old.get and
>> old.length with injects that only respond to is None and +1.
>>
>> Or, a syntax like this
>> @post(lambda self, key, old: [old.get(old.key)] is None and
>> [old.self.length() + 1] ==
>> self.length())
>>
>> Where the stuff inside the brackets is evaluated before the decorated
>> function runs. It would be useful for networking functions or functions that
>> do something ephemeral, where data related to the value being accessed
>> needed for the expression no longer exists after the function.
>>
>> This does conflict with list syntax forever, so maybe either force people to
>> do list((expr,)) or use an alternate syntax like one item set syntax { } or
>> double set syntax {{ }} or double list syntax [[ ]]. Ditto with having to
>> avoid the literals for the normal meaning.
>>
>> You could modify Python to accept any expression for the lambda function and
>> propose that as a PEP. (Right now it’s hardcoded as a dotted name and
>> optionally a single argument list surrounded by parentheses.)
>>
>> I suggest that instead of “@before” it’s “@snapshot” and instead of “old”
>> it’s “snapshot”.
>>
>> Python does have unary plus/minus syntax as well as stream operators (<<,
>> >>) and list slicing syntax and the @ operator and operators & and | if you
>> want to play with syntax. There’s also the line continuation character for
>> crazy lambdas.
>>
>> Personally I prefer
>> @post(lambda self, key, old: {{old.self.get(old.key)}} and
>> {{old.self.length() + 1}} ==
>> self.length())
>>
>> because it’s explicit about what it does (evaluate the expressions within {{
>> }} before the function runs. I also find it elegant.
>>
>> Alternatively, inside the {{ }} could be a special scope where locals() is
>> all the arguments @pre could’ve received as a dictionary. For either option
>> you can remove the old parameter from the lambda. Example:
>> @post(lambda self, key: {{self.get(key)}} and {{self.length() + 1}} ==
>> self.length())
>>
>> Perhaps the convention should be to write {{ expr }} (with the spaces in
>> between).
>>
>> You’d probably have to use the ast module to inspect it instead of the dis
>> modul. Then find some way to reconstruct the expressions inside the double
>> brackets- perhaps by reconstructing the AST and compiling it to a code
>> object, or perhaps by finding the part of the string the expression is
>> located. dis can give you the code as a string and you can run a carefully
>> crafted regex on it.
>> _______________________________________________
>> Python-ideas mailing list
>> [email protected]
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________
Python-ideas mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/