Permalink
Browse files

Isolated the two unit test failures with scripts in opy/testdata/.

- Parameterize VirtualMachine: more_info, subset
- Remove unused print_frames() function
- Add ability to filter 'dis' by a single function, e.g. to see only the
  _parse() function in re.pyc.
  • Loading branch information...
Andy Chu
Andy Chu committed Apr 7, 2018
1 parent 72cc76f commit 45e8dcf353698ab543d38346f29ab9c753a19b5f
Showing with 123 additions and 35 deletions.
  1. +19 −27 opy/byterun/pyvm2.py
  2. +22 −7 opy/compiler2/dis_tool.py
  3. +2 −1 opy/opy_main.py
  4. +25 −0 opy/test.sh
  5. +44 −0 opy/testdata/generator_exception.py
  6. +11 −0 opy/testdata/regex_compile.py
View
@@ -72,7 +72,18 @@ def __str__(self):
class VirtualMachine(object):
def __init__(self, verbose=True):
def __init__(self, subset=False, verbose=True):
"""
Args:
subset: turn off bytecodes that OPy doesn't need (e.g. print
statement, etc.)
verbose: turn on logging
"""
self.subset = subset
self.more_info = False
#self.more_info = True
self.verbose = verbose
# The call stack of frames.
self.frames = []
# The current frame.
@@ -82,7 +93,6 @@ def __init__(self, verbose=True):
self.last_exception = None
self.except_frames = [] # Frames saved for GuestException
self.verbose = verbose
def top(self):
"""Return the value at the top of the stack, with no changes."""
@@ -160,22 +170,6 @@ def pop_frame(self):
else:
self.frame = None
def print_frames(self):
"""Print the call stack, for debugging."""
# TODO: Remove, UNUSED
print('FRAMES:')
print('')
for f in self.frames:
filename = f.f_code.co_filename
lineno = f.line_number()
print(' File "%s", line %d, in %s' % (
filename, lineno, f.f_code.co_name
))
linecache.checkcache(filename)
line = linecache.getline(filename, lineno, f.f_globals)
if line:
print(' ' + line.strip())
def resume_frame(self, frame):
frame.f_back = self.frame
val = self.run_frame(frame)
@@ -374,12 +368,11 @@ def run_frame(self, frame):
# NOTE: We shouldn't even use exceptions to model control flow?
if why == 'exception':
#self.print_frames()
exctype, value, tb = self.last_exception
debug('exctype: %s' % exctype)
debug('value: %s' % value)
debug('unused tb: %s' % tb)
if 0:
if self.more_info:
# Raise an exception with the EMULATED (guest) stack frames.
raise GuestException(exctype, value, self.except_frames)
else:
@@ -936,26 +929,25 @@ def call_function(self, arg, args, kwargs):
# The first parameter must be the correct type.
if not isinstance(posargs[0], func.im_class):
# Must match Python interpreter to pass unit tests!
if 1:
if self.more_info:
# More informative error that shows the frame.
raise TypeError(
'unbound method %s() must be called with %s instance '
'as first argument (got %s instance instead)' % (
'as first argument, was called with %s instance'
'(frame: %s)' % (
func.im_func.func_name,
func.im_class.__name__,
type(posargs[0]).__name__,
self.frame,
)
)
else:
# FIX
# More informative error that shows the frame.
raise TypeError(
'unbound method %s() must be called with %s instance '
'as first argument, was called with %s instance'
'(frame: %s)' % (
'as first argument (got %s instance instead)' % (
func.im_func.func_name,
func.im_class.__name__,
type(posargs[0]).__name__,
self.frame,
)
)
func = func.im_func
View
@@ -174,21 +174,31 @@ def out(*args, **kwargs):
class Visitor(object):
def __init__(self, dis_bytecode=True):
self.dis_bytecode = dis_bytecode # Whether to show disassembly.
def __init__(self, dis_bytecode=True, co_name=None):
"""
Args:
dis_bytecode: Whether to show disassembly.
co_name: only print code object with exact name (and its children)
"""
self.dis_bytecode = dis_bytecode
# Name of thing to print
self.co_name = co_name
self.op_counts = collections.Counter()
def show_consts(self, consts, level=0):
indent = INDENT * level
i = 0
for obj in consts:
for i, obj in enumerate(consts):
if isinstance(obj, types.CodeType):
print(indent+"%s (code object)" % i)
print("%s%s (code object)" % (indent, i))
# RECURSIVE CALL.
self.show_code(obj, level=level+1)
else:
print(indent+"%s %r" % (i, obj))
i += 1
print("%s%s %r" % (indent, i, obj))
def maybe_show_consts(self, consts, level=0):
for obj in consts:
if isinstance(obj, types.CodeType):
self.show_code(obj, level=level+1) # RECURSIVE CALL.
def show_bytecode(self, code, level=0):
"""Call dis.disassemble() to show bytecode."""
@@ -203,6 +213,11 @@ def show_bytecode(self, code, level=0):
def show_code(self, code, level=0):
"""Print a code object, e.g. metadata, bytecode, and consts."""
# Filter recursive call
if self.co_name and code.co_name != self.co_name:
self.maybe_show_consts(code.co_consts, level=level+1)
return
indent = INDENT * level
for name in dir(code):
View
@@ -254,8 +254,9 @@ def OpyCommandMain(argv):
with open(pyc_path, 'rb') as f:
# TODO: Make this a flag.
#v = inspect_pyc.Visitor(dis_bytecode=False)
#v = dis_tool.Visitor(dis_bytecode=False)
v = dis_tool.Visitor()
#v = dis_tool.Visitor(co_name='_parse')
v.Visit(f)
v.Report(report_f)
View
@@ -137,6 +137,31 @@ byterun-unit() {
done
}
# Isolated failures.
# File "/home/andy/git/oilshell/oil/bin/../opy/byterun/pyvm2.py", line 288, in manage_block_stack
# block = self.frame.block_stack[-1]
# IndexError: list index out of range
generator-exception() {
testdata/generator_exception.py
echo ---
../bin/opyc run testdata/generator_exception.py
}
# TypeError: unbound method append() must be called with SubPattern instance as
# first argument (got tuple instance instead)
regex-compile() {
testdata/regex_compile.py
echo ---
../bin/opyc run testdata/regex_compile.py
}
re-dis() {
../bin/opyc dis /usr/lib/python2.7/sre_parse.pyc
}
unit() {
PYTHONPATH=. "$@"
@@ -0,0 +1,44 @@
#!/usr/bin/python
from __future__ import print_function
"""
generator_exception.py
"""
import sys
def Tokenize(s):
for item in ('1', '2', '3'):
yield item
class Parser(object):
"""Recursive TDOP parser."""
def __init__(self, lexer):
self.lexer = lexer # iterable
self.token = None # current token
def Next(self):
"""Move to the next token."""
try:
t = self.lexer.next()
except StopIteration:
t = None
self.token = t
def main(argv):
lexer = Tokenize('1+2')
p = Parser(lexer)
p.Next()
p.Next()
print('Done')
if __name__ == '__main__':
try:
main(sys.argv)
except RuntimeError as e:
print >>sys.stderr, 'FATAL: %s' % e
sys.exit(1)
@@ -0,0 +1,11 @@
#!/usr/bin/python
from __future__ import print_function
"""
regex_compile.py
Failing test for opyc run / byterun.
"""
import re
print(re.compile(r'.*'))

0 comments on commit 45e8dcf

Please sign in to comment.