Skip to content

Commit

Permalink
Instr: rename is_jump() to has_jump()
Browse files Browse the repository at this point in the history
* Instr constructor now raises an error if argument is a label but
  the operation has no jump argument
* complete Instr doc
  • Loading branch information
vstinner committed Feb 29, 2016
1 parent 13fba39 commit 9742e30
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 13 deletions.
16 changes: 12 additions & 4 deletions bytecode/instr.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,18 @@ def _check(self, name, arg, lineno):
if not isinstance(name, str):
raise TypeError("operation name must be a str")
try:
_opcode.opmap[name]
opcode = _opcode.opmap[name]
except KeyError:
raise ValueError("invalid operation name")

# check lineno
if lineno is not None:
_check_lineno(lineno)

if isinstance(arg, Label) and not self._has_jump(opcode):
raise ValueError("label argument cannot be used in %s operation"
% name)

def set(self, name, arg=UNSET, *, lineno=None):
"""Modify the instruction in-place.
Expand Down Expand Up @@ -202,9 +206,13 @@ def __eq__(self, other):
return False
return self._cmp_key() == other._cmp_key()

def is_jump(self):
return (self._opcode in _opcode.hasjrel
or self._opcode in _opcode.hasjabs)
@staticmethod
def _has_jump(opcode):
return (opcode in _opcode.hasjrel
or opcode in _opcode.hasjabs)

def has_jump(self):
return self._has_jump(self._opcode)

def is_cond_jump(self):
"""Is a conditional jump?"""
Expand Down
2 changes: 1 addition & 1 deletion bytecode/peephole_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ def optimize_block(self, block):
meth = getattr(self, meth_name, None)
if meth is not None:
meth(instr)
elif instr.is_jump():
elif instr.has_jump():
self.optimize_jump_to_cond_jump(instr)

# Note: Skipping over LOAD_CONST trueconst; POP_JUMP_IF_FALSE
Expand Down
21 changes: 17 additions & 4 deletions bytecode/tests/test_instr.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
import opcode
import unittest
from bytecode import Instr, UNSET
from bytecode import UNSET, Label, Instr
from bytecode.tests import TestCase


Expand All @@ -19,6 +19,12 @@ def test_constructor(self):
with self.assertRaises(ValueError):
Instr("xxx")

# label
label = Label()
with self.assertRaises(ValueError):
Instr("LOAD_CONST", label)
Instr("JUMP_ABSOLUTE", label)

def test_attr(self):
instr = Instr("LOAD_CONST", 3, lineno=5)
self.assertEqual(instr.name, 'LOAD_CONST')
Expand Down Expand Up @@ -71,12 +77,12 @@ def test_compare(self):
# different arg
self.assertNotEqual(instr, Instr("LOAD_CONST", 4, lineno=7))

def test_is_jump(self):
def test_has_jump(self):
jump = Instr("JUMP_ABSOLUTE", 3)
self.assertTrue(jump.is_jump())
self.assertTrue(jump.has_jump())

instr = Instr("LOAD_FAST", 2)
self.assertFalse(instr.is_jump())
self.assertFalse(instr.has_jump())

def test_is_cond_jump(self):
jump = Instr("POP_JUMP_IF_TRUE", 3)
Expand All @@ -85,6 +91,13 @@ def test_is_cond_jump(self):
instr = Instr("LOAD_FAST", 2)
self.assertFalse(instr.is_cond_jump())

def test_is_uncond_jump(self):
jump = Instr("JUMP_ABSOLUTE", 3)
self.assertTrue(jump.is_uncond_jump())

instr = Instr("POP_JUMP_IF_TRUE", 2)
self.assertFalse(instr.is_uncond_jump())

def test_const_key_not_equal(self):
def check(value):
self.assertEqual(Instr('LOAD_CONST', value),
Expand Down
20 changes: 16 additions & 4 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ Instr

The type of the :attr:`arg` attribute depends on the operation.

:class:`Label` argument must only be used with operation having a jump
argument.

Attributes:

.. attribute:: name
Expand Down Expand Up @@ -81,19 +84,28 @@ Instr
* RAISE_VARARGS
* BREAK_LOOP
* CONTINUE_LOOP
* unconditional jumps (see :meth:`is_uncond_jump`)
* unconditional jumps: :meth:`is_uncond_jump`

.. method:: has_jump()

.. method:: is_jump()
Has the operation a jump? Return a boolean.

Is the operation a conditional or unconditional jump? Return a boolean.
More generic than `is_cond_jump` and :meth:`is_uncond_jump`, it includes
other operations. Examples::

* FOR_ITER
* SETUP_EXCEPT
* CONTINUE_LOOP

.. method:: is_cond_jump()

Is the operation an conditional jump? Return a boolean.

Examples of conditional jumps:
Conditional jumps:

* JUMP_IF_FALSE_OR_POP
* JUMP_IF_TRUE_OR_POP
* POP_JUMP_IF_FALSE
* POP_JUMP_IF_TRUE

.. method:: is_uncond_jump()
Expand Down

0 comments on commit 9742e30

Please sign in to comment.