|
|
Changes since version 0.2: |
Changes since version 0.2: |
|
|
* Added a ``Getattr`` symbol that does static or dynamic attribute access and |
* Added ``Suite``, ``TryExcept``, and ``TryFinally`` node types |
constant folding |
|
|
* Added a ``Getattr`` node type that does static or dynamic attribute access |
|
and constant folding |
|
|
* Fixed ``code.from_function()`` not copying the ``co_filename`` attribute when |
* Fixed ``code.from_function()`` not copying the ``co_filename`` attribute when |
``copy_lineno`` was specified. |
``copy_lineno`` was specified. |
6 LOAD_CONST 3 (1.0) |
6 LOAD_CONST 3 (1.0) |
9 LOAD_CONST 4 (1L) |
9 LOAD_CONST 4 (1L) |
|
|
|
|
Simple Containers |
Simple Containers |
----------------- |
----------------- |
|
|
False |
False |
|
|
|
|
|
``Suite`` and ``Pass`` |
|
---------------------- |
|
|
|
On occasion, it's helpful to be able to group a sequence of opcodes, |
|
expressions, or statements together, to be passed as an argument to other node |
|
types. The ``Suite`` node type accomplishes this:: |
|
|
|
>>> from peak.util.assembler import Suite, Pass |
|
|
|
>>> c = Code() |
|
>>> c.return_(Suite([Const(42), Code.DUP_TOP, Code.POP_TOP])) |
|
>>> dis(c.code()) |
|
0 0 LOAD_CONST 1 (42) |
|
3 DUP_TOP |
|
4 POP_TOP |
|
5 RETURN_VALUE |
|
|
|
And ``Pass`` is a shortcut for an empty ``Suite``, that generates nothing:: |
|
|
|
>>> Suite([]) |
|
Pass |
|
|
|
>>> c = Code() |
|
>>> c(Pass) |
|
>>> c.return_(None) |
|
>>> dis(c.code()) |
|
0 0 LOAD_CONST 0 (None) |
|
3 RETURN_VALUE |
|
|
|
|
Local and Global Names |
Local and Global Names |
---------------------- |
---------------------- |
|
|
code that might be unreachable. For example, consider this ``If`` |
code that might be unreachable. For example, consider this ``If`` |
implementation:: |
implementation:: |
|
|
>>> from peak.util.assembler import Pass |
|
>>> def If(cond, then, else_=Pass, code=None): |
>>> def If(cond, then, else_=Pass, code=None): |
... if code is None: |
... if code is None: |
... return cond, then, else_ |
... return cond, then, else_ |
>> 10 LOAD_CONST 0 (None) |
>> 10 LOAD_CONST 0 (None) |
13 RETURN_VALUE |
13 RETURN_VALUE |
|
|
Labels have a ``POP_BLOCK`` attribute that you can pass in when generating |
(Labels have a ``POP_BLOCK`` attribute that you can pass in when generating |
code. |
code.) |
|
|
|
And, for generating typical try/except blocks, you can use the ``TryExcept`` |
|
node type, which takes a body, a sequence of exception-type/handler pairs, |
|
and an optional "else" clause:: |
|
|
|
>>> from peak.util.assembler import TryExcept |
|
>>> c = Code() |
|
>>> c.return_( |
|
... TryExcept( |
|
... Return(1), # body |
|
... [(Const(KeyError),2), (Const(TypeError),3)], # handlers |
|
... Return(4) # else clause |
|
... ) |
|
... ) |
|
|
|
>>> dis(c.code()) |
|
0 0 SETUP_EXCEPT 8 (to 11) |
|
3 LOAD_CONST 1 (1) |
|
6 RETURN_VALUE |
|
7 POP_BLOCK |
|
8 JUMP_FORWARD 43 (to 54) |
|
>> 11 DUP_TOP |
|
12 LOAD_CONST 2 (<type 'exceptions.KeyError'>) |
|
15 COMPARE_OP 10 (exception match) |
|
18 JUMP_IF_FALSE 10 (to 31) |
|
21 POP_TOP |
|
22 POP_TOP |
|
23 POP_TOP |
|
24 POP_TOP |
|
25 LOAD_CONST 3 (2) |
|
28 JUMP_FORWARD 27 (to 58) |
|
>> 31 POP_TOP |
|
32 DUP_TOP |
|
33 LOAD_CONST 4 (<type 'exceptions.TypeError'>) |
|
36 COMPARE_OP 10 (exception match) |
|
39 JUMP_IF_FALSE 10 (to 52) |
|
42 POP_TOP |
|
43 POP_TOP |
|
44 POP_TOP |
|
45 POP_TOP |
|
46 LOAD_CONST 5 (3) |
|
49 JUMP_FORWARD 6 (to 58) |
|
>> 52 POP_TOP |
|
53 END_FINALLY |
|
>> 54 LOAD_CONST 6 (4) |
|
57 RETURN_VALUE |
|
>> 58 RETURN_VALUE |
|
|
|
|
Try/Finally Blocks |
Try/Finally Blocks |
adjusts the maximum expected stack size to accomodate up to three values being |
adjusts the maximum expected stack size to accomodate up to three values being |
put on the stack by the Python interpreter for exception handling. |
put on the stack by the Python interpreter for exception handling. |
|
|
|
For your convenience, the ``TryFinally`` node type can also be used to generate |
|
try/finally blocks:: |
|
|
|
>>> from peak.util.assembler import TryFinally |
|
>>> c = Code() |
|
>>> c( TryFinally(ExprStmt(1), ExprStmt(2)) ) |
|
>>> dis(c.code()) |
|
0 0 SETUP_FINALLY 8 (to 11) |
|
3 LOAD_CONST 1 (1) |
|
6 POP_TOP |
|
7 POP_BLOCK |
|
8 LOAD_CONST 0 (None) |
|
>> 11 LOAD_CONST 2 (2) |
|
14 POP_TOP |
|
15 END_FINALLY |
|
|
|
|
Loops |
Loops |
----- |
----- |
|
|
>>> from peak.util.assembler import LOAD_CONST, POP_BLOCK |
>>> from peak.util.assembler import LOAD_CONST, POP_BLOCK |
|
|
>>> def Pass(code=None): |
|
... if code is None: |
|
... return Pass |
|
|
|
>>> import sys |
>>> import sys |
>>> WHY_CONTINUE = {'2.3':5, '2.4':32, '2.5':32}[sys.version[:3]] |
>>> WHY_CONTINUE = {'2.3':5, '2.4':32, '2.5':32}[sys.version[:3]] |
|
|