bytecode instead of on these mechanical issues. |
bytecode instead of on these mechanical issues. |
|
|
In addition to a low-level opcode-oriented API for directly generating specific |
In addition to a low-level opcode-oriented API for directly generating specific |
bytecodes, this module also offers an extensible mini-AST framework for |
Python bytecodes, this module also offers an extensible mini-AST framework for |
generating code from high-level specifications. This framework does most of |
generating code from high-level specifications. This framework does most of |
the work needed to transform tree-like structures into linear bytecode |
the work needed to transform tree-like structures into linear bytecode |
instructions, and includes the ability to do compile-time constant folding. |
instructions, and includes the ability to do compile-time constant folding. |
|
|
Changes since version 0.2: |
Changes since version 0.2: |
|
|
|
* Added a ``Getattr`` symbol that does static or dynamic attribute access and |
|
constant folding |
|
|
|
* Fixed ``code.from_function()`` not copying the ``co_filename`` attribute when |
|
``copy_lineno`` was specified. |
|
|
* The ``repr()`` of AST nodes doesn't include a trailing comma for 1-argument |
* The ``repr()`` of AST nodes doesn't include a trailing comma for 1-argument |
node types any more. |
node types any more. |
|
|
strings accepted (in the ``cmp_op`` tuple). ``"<>"`` is also accepted as an |
strings accepted (in the ``cmp_op`` tuple). ``"<>"`` is also accepted as an |
alias for ``"!="``. |
alias for ``"!="``. |
|
|
|
* Added code to verify that forward jump offsets don't exceed a 64KB span, and |
|
support absolute backward jumps to locations >64KB. |
|
|
Changes since version 0.1: |
Changes since version 0.1: |
|
|
* Constant handling has been fixed so that it doesn't confuse equal values of |
* Constant handling has been fixed so that it doesn't confuse equal values of |
* Various bug fixes |
* Various bug fixes |
|
|
There are a few features that aren't tested yet, and not all opcodes may be |
There are a few features that aren't tested yet, and not all opcodes may be |
fully supported. Notably, the following features are still NOT reliably |
fully supported. Also note the following limitations: |
supported yet: |
|
|
|
* Wide jump addressing (for generated bytecode>64K in size) |
* Jumps to as-yet-undefined labels cannot span a distance greater than 65,535 |
|
bytes. |
|
|
* The ``dis()`` module in Python 2.3 has a bug that makes it show incorrect |
* The ``dis()`` module in Python 2.3 has a bug that makes it show incorrect |
line numbers when the difference between two adjacent line numbers is |
line numbers when the difference between two adjacent line numbers is |
6 LOAD_DEREF 1 (z) |
6 LOAD_DEREF 1 (z) |
|
|
|
|
|
Obtaining Attributes |
|
-------------------- |
|
|
|
The ``Getattr`` node type takes an expression and an attribute name. The |
|
attribute name can be a constant string, in which case a ``LOAD_ATTR`` opcode |
|
is used, and constant folding is done if possible:: |
|
|
|
>>> from peak.util.assembler import Getattr |
|
|
|
>>> c = Code() |
|
>>> c(Getattr(Local('x'), '__class__')) |
|
>>> dis(c.code()) |
|
0 0 LOAD_FAST 0 (x) |
|
3 LOAD_ATTR 0 (__class__) |
|
|
|
|
|
>>> Getattr(Const(object), '__class__') # const expression, const result |
|
Const(<type 'type'>) |
|
|
|
Or the attribute name can be an expression, in which case a ``getattr()`` call |
|
is compiled instead:: |
|
|
|
>>> c = Code() |
|
>>> c(Getattr(Local('x'), Local('y'))) |
|
>>> dis(c.code()) |
|
0 0 LOAD_CONST 1 (<built-in function getattr>) |
|
3 LOAD_FAST 0 (x) |
|
6 LOAD_FAST 1 (y) |
|
9 CALL_FUNCTION 2 |
|
|
|
|
Calling Functions and Methods |
Calling Functions and Methods |
----------------------------- |
----------------------------- |
|
|
implements its ``fold`` argument and the suppression of folding when |
implements its ``fold`` argument and the suppression of folding when |
the call has no arguments. |
the call has no arguments. |
|
|
|
(By the way, this same ``Getattr`` node type is also available |
|
|
|
|
Setting the Code's Calling Signature |
Setting the Code's Calling Signature |
==================================== |
==================================== |
>>> c1 = Code.from_function(f1, copy_lineno=True) |
>>> c1 = Code.from_function(f1, copy_lineno=True) |
>>> c1.co_firstlineno |
>>> c1.co_firstlineno |
1 |
1 |
|
>>> c1.co_filename is f1.func_code.co_filename |
|
True |
|
|
If you create a ``Code`` instance from a function that has nested positional |
If you create a ``Code`` instance from a function that has nested positional |
arguments, the returned code object will include a prologue to unpack the |
arguments, the returned code object will include a prologue to unpack the |
|
|
>>> c = Code() |
>>> c = Code() |
>>> c( If(23, 42, 55) ) |
>>> c( If(23, 42, 55) ) |
>>> dis(c.code()) |
>>> dis(c.code()) # Python 2.3 may peephole-optimize this code |
0 0 LOAD_CONST 1 (23) |
0 0 LOAD_CONST 1 (23) |
3 JUMP_IF_FALSE 7 (to 13) |
3 JUMP_IF_FALSE 7 (to 13) |
6 POP_TOP |
6 POP_TOP |
|
|
>>> c = Code() |
>>> c = Code() |
>>> c( If(23, Return(42), 55) ) |
>>> c( If(23, Return(42), 55) ) |
>>> dis(c.code()) |
>>> dis(c.code()) # Python 2.3 may peephole-optimize this code |
0 0 LOAD_CONST 1 (23) |
0 0 LOAD_CONST 1 (23) |
3 JUMP_IF_FALSE 5 (to 11) |
3 JUMP_IF_FALSE 5 (to 11) |
6 POP_TOP |
6 POP_TOP |