Skip to content

Commit

Permalink
Complete the API doc
Browse files Browse the repository at this point in the history
  • Loading branch information
vstinner committed Feb 29, 2016
1 parent 51bfecd commit c9f5c72
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 24 deletions.
2 changes: 2 additions & 0 deletions bytecode/bytecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
class BaseBytecode:
def __init__(self):
self.argcount = 0
# FIXME: rename to kwonlyargcount?
self.kw_only_argcount = 0
# FIXME: insane and safe value until _ConvertBytecodeToConcrete is able
# to compute the value itself
self._stacksize = 256
# FIXME: use something higher level? make it private?
self.flags = 0
self.first_lineno = 1
self.name = '<module>'
Expand Down
9 changes: 0 additions & 9 deletions bytecode/concrete.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,6 @@ def _check(self, name, arg, lineno):
raise ValueError("operation %s has no argument" % name)

def set(self, name, arg=UNSET, *, lineno=None):
"""Modify the instruction in-place.
Replace name, arg and lineno attributes.
This method must be used if the current and new operation don't have
the same requirements for argument. For example, replacing LOAD_CONST
with NOP cannot be done with instr.name='NOP' since this change raises
an exception (operation NOP has no argument).
"""
super().set(name, arg, lineno=lineno)
size = 1
if arg is not UNSET:
Expand Down
5 changes: 3 additions & 2 deletions bytecode/instr.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,15 @@ def is_jump(self):
or self._opcode in _opcode.hasjabs)

def is_cond_jump(self):
"""Is a conditional jump?"""
# Ex: POP_JUMP_IF_TRUE, JUMP_IF_FALSE_OR_POP
return ('JUMP_IF_' in self._name)

def is_uncond_jump(self):
"""Is an unconditiona jump?"""
"""Is an unconditional jump?"""
return self.name in {'JUMP_FORWARD', 'JUMP_ABSOLUTE'}

def _is_final(self):
def is_final(self):
if self._name in {'RETURN_VALUE', 'RAISE_VARARGS',
'BREAK_LOOP', 'CONTINUE_LOOP'}:
return True
Expand Down
186 changes: 173 additions & 13 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ bytecode module version string: ``bytecode.__version__`` (ex: ``'0.1'``).

Singleton used to mark the lack of value. It is different than ``None``.

Instruction classes:

* :class:`Instr`
* :class:`ConcreteInstr`
* :class:`Label`
* :class:`SetLineno`

Bytecode classes:

* :class:`BaseBytecode`
* :class:`Bytecode`
* :class:`ConcreteBytecode`
* :class:`Block`
* :class:`BytecodeBlocks`


Instructions
============
Expand Down Expand Up @@ -40,18 +55,50 @@ Instr

Line number (``int`` greater or equal than ``1``), or ``None``.

Static method:

.. staticmethod:: disassemble(code: bytes, offset: int)

Create an instruction from a bytecode string.

Methods:

.. method:: copy()

Create a copy of the instruction.

.. method:: is_final()

Is the operation a final operation? Return a boolean.

Final operations:

* RETURN_VALUE
* RAISE_VARARGS
* BREAK_LOOP
* CONTINUE_LOOP
* unconditional jumps (see :meth:`is_uncond_jump`)

.. method:: is_jump()

Is the operation a conditional or unconditional jump? Return a boolean.

.. method:: is_cond_jump()

Is the operation an conditional jump? Return a boolean.

Examples of conditional jumps:

* JUMP_IF_FALSE_OR_POP
* POP_JUMP_IF_TRUE

.. method:: is_uncond_jump()

Is the operation an unconditional jump? Return a boolean.

Unconditional jumps:

* JUMP_FORWARD
* JUMP_ABSOLUTE

.. method:: set(name, arg=UNSET, \*, lineno=None):

Replace all attributes.


ConcreteInstr
-------------
Expand All @@ -62,6 +109,13 @@ ConcreteInstr

If the operation has an argument, *arg* must be an integer.

Use the :meth:`~Instr.set` method to replace the operation name and the
argument at the same type. Otherwise, an exception can be raised if the
previous operation requires an argument and the new operation has no
argument (or the opposite).

Should only be used with :class:`ConcreteBytecode`.

Attributes:

.. attribute:: arg
Expand All @@ -77,13 +131,22 @@ ConcreteInstr

.. staticmethod:: disassemble(code: bytes, offset: int)

Create an instruction from a bytecode string.
Create a concrete instruction (:class:`ConcreteInstr`) from a bytecode
string.

Methods:

.. method:: copy()
.. method:: get_jump_target(instr_offset)

Create a copy of the instruction.
Get the absolute target offset of a jump. Return ``None`` if the
instruction is not a jump.

The *instr_offset* parameter is the offset of the instruction. It is
required by relative jumps.

.. method:: assemble() -> bytes

Assemble the instruction to a bytecode string.


Label
Expand All @@ -93,7 +156,7 @@ Label

Pseudo-instruction. Targets of jump instructions for :class:`Bytecode`.

Labels must not be used in :class:`ConcreteBytecode`.
Labels must only be used in :class:`Bytecode`.


SetLineno
Expand All @@ -107,16 +170,65 @@ SetLineno
Bytecode classes
================

BaseBytecode
------------

.. class:: BaseBytecode

Base class of bytecode classes.

Attributes:

.. attribute:: argcount

Argument count (``int``), default: ``0``.

.. attribute:: cellvars

Names of the cell variables (``list`` of ``str``), default: empty list.

.. attribute:: docstring

Document string aka "docstring" (``str``), default: not set (:data:`UNSET`).

.. attribute:: filename

Code filename (``str``), default: ``<string>``.

.. attribute:: first_lineno

First line number (``int``), default: ``1``.

.. attribute:: flags

Flags (``int``).

.. attribute:: kw_only_argcount

Keyword-only argument count (``int``), default: ``0``.

.. attribute:: name

Code name (``str``), default: ``<module>``.


Bytecode
--------

.. class:: Bytecode

Abstract bytecode: list of abstract instructions (:class:`Instr`).
Inherit from :class:`BaseBytecode` and :class:`list`.

It is possible to use concrete instructions (:class:`ConcreteInstr`), but
abstract instructions are preferred.

Attributes:

.. attribute:: argnames

Names of the argument names (``list`` of ``str``), default: empty list.

Static methods:

.. staticmethod:: from_code()
Expand All @@ -140,6 +252,25 @@ ConcreteBytecode
.. class:: ConcreteBytecode

List of concrete instructions (:class:`ConcreteInstr`).
Inherit from :class:`BaseBytecode`.

Attributes:

.. attribute:: consts

List of constants (``list``), default: empty list.

.. attribute:: freevars

List of free variable names (``list`` of ``str``), default: empty list.

.. attribute:: names

List of names (``list`` of ``str``), default: empty list.

.. attribute:: varnames

List of variable names (``list`` of ``str``), default: empty list.

Static methods:

Expand All @@ -162,26 +293,55 @@ ConcreteBytecode
Convert to abstrct bytecode with abstract instructions.


Block
-----

.. class:: Block

List of abstract instructions (:class:`Instr`). Inherit from :class:`list`.

Attributes:

.. attribute:: label

Block label (:class:`Label`).

.. attribute:: next_block

Next block (:class:`Block`), or ``None``.


BytecodeBlocks
--------------

.. class:: BytecodeBlocks

List of blocks, a block is a list of abstract instructions (:class:`Instr`)
and has a label (:class:`Label`).
List of blocks (:class:`Block`), a block is a list of abstract instructions
(:class:`Instr`) and has a label (:class:`Label`). Inherit from
:class:`BaseBytecode`.

It is possible to use concrete instructions (:class:`ConcreteInstr`) in
blocks, but abstract instructions are preferred.

Labels must not be used in blocks.

Static methods:
Attributes:

.. attribute:: argnames

Names of the argument names (``list`` of ``str``), default: empty list.

Methods:

.. staticmethod:: from_bytecode(bytecode)

Create a :class:`Bytecode` object to a :class:`BytecodeBlocks` object:
replace labels with blocks.

.. method:: add_block(instructions=None)

Add a new block. Return the new :class:`Block`.


Line Numbers
============
Expand Down

0 comments on commit c9f5c72

Please sign in to comment.