Author: Armin Rigo <[email protected]>
Branch: reverse-debugger
Changeset: r85423:0d91eaae941b
Date: 2016-06-28 14:03 +0200
http://bitbucket.org/pypy/pypy/changeset/0d91eaae941b/
Log: astcompiler and basic interpreter support for $NUM
diff --git a/lib-python/2.7/opcode.py b/lib-python/2.7/opcode.py
--- a/lib-python/2.7/opcode.py
+++ b/lib-python/2.7/opcode.py
@@ -194,5 +194,6 @@
def_op('CALL_METHOD', 202) # #args not including 'self'
def_op('BUILD_LIST_FROM_ARG', 203)
jrel_op('JUMP_IF_NOT_DEBUG', 204) # jump over assert statements
+def_op('LOAD_REVDB_VAR', 205) # reverse debugger (syntax example: $5)
del def_op, name_op, jrel_op, jabs_op
diff --git a/pypy/interpreter/astcompiler/assemble.py
b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -664,6 +664,7 @@
ops.JUMP_IF_NOT_DEBUG: 0,
ops.BUILD_LIST_FROM_ARG: 1,
+ ops.LOAD_REVDB_VAR: 1,
}
diff --git a/pypy/interpreter/astcompiler/ast.py
b/pypy/interpreter/astcompiler/ast.py
--- a/pypy/interpreter/astcompiler/ast.py
+++ b/pypy/interpreter/astcompiler/ast.py
@@ -1534,6 +1534,8 @@
return Num.from_object(space, w_node)
if space.isinstance_w(w_node, get(space).w_Str):
return Str.from_object(space, w_node)
+ if space.isinstance_w(w_node, get(space).w_RevDBMetaVar):
+ return RevDBMetaVar.from_object(space, w_node)
if space.isinstance_w(w_node, get(space).w_Attribute):
return Attribute.from_object(space, w_node)
if space.isinstance_w(w_node, get(space).w_Subscript):
@@ -2344,6 +2346,41 @@
State.ast_type('Str', 'expr', ['s'])
+class RevDBMetaVar(expr):
+
+ def __init__(self, metavar, lineno, col_offset):
+ self.metavar = metavar
+ expr.__init__(self, lineno, col_offset)
+
+ def walkabout(self, visitor):
+ visitor.visit_RevDBMetaVar(self)
+
+ def mutate_over(self, visitor):
+ return visitor.visit_RevDBMetaVar(self)
+
+ def to_object(self, space):
+ w_node = space.call_function(get(space).w_RevDBMetaVar)
+ w_metavar = space.wrap(self.metavar) # int
+ space.setattr(w_node, space.wrap('metavar'), w_metavar)
+ w_lineno = space.wrap(self.lineno) # int
+ space.setattr(w_node, space.wrap('lineno'), w_lineno)
+ w_col_offset = space.wrap(self.col_offset) # int
+ space.setattr(w_node, space.wrap('col_offset'), w_col_offset)
+ return w_node
+
+ @staticmethod
+ def from_object(space, w_node):
+ w_metavar = get_field(space, w_node, 'metavar', False)
+ w_lineno = get_field(space, w_node, 'lineno', False)
+ w_col_offset = get_field(space, w_node, 'col_offset', False)
+ _metavar = space.int_w(w_metavar)
+ _lineno = space.int_w(w_lineno)
+ _col_offset = space.int_w(w_col_offset)
+ return RevDBMetaVar(_metavar, _lineno, _col_offset)
+
+State.ast_type('RevDBMetaVar', 'expr', ['metavar'])
+
+
class Attribute(expr):
def __init__(self, value, attr, ctx, lineno, col_offset):
@@ -3439,6 +3476,8 @@
return self.default_visitor(node)
def visit_Str(self, node):
return self.default_visitor(node)
+ def visit_RevDBMetaVar(self, node):
+ return self.default_visitor(node)
def visit_Attribute(self, node):
return self.default_visitor(node)
def visit_Subscript(self, node):
@@ -3655,6 +3694,9 @@
def visit_Str(self, node):
pass
+ def visit_RevDBMetaVar(self, node):
+ pass
+
def visit_Attribute(self, node):
node.value.walkabout(self)
diff --git a/pypy/interpreter/astcompiler/astbuilder.py
b/pypy/interpreter/astcompiler/astbuilder.py
--- a/pypy/interpreter/astcompiler/astbuilder.py
+++ b/pypy/interpreter/astcompiler/astbuilder.py
@@ -1160,6 +1160,11 @@
elif first_child_type == tokens.BACKQUOTE:
expr = self.handle_testlist(atom_node.get_child(1))
return ast.Repr(expr, atom_node.get_lineno(),
atom_node.get_column())
+ elif first_child_type == tokens.REVDBMETAVAR:
+ string = atom_node.get_child(0).get_value()
+ return ast.RevDBMetaVar(int(string[1:]),
+ atom_node.get_lineno(),
+ atom_node.get_column())
else:
raise AssertionError("unknown atom")
diff --git a/pypy/interpreter/astcompiler/codegen.py
b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -1196,6 +1196,14 @@
sub.value.walkabout(self)
self._compile_slice(sub.slice, sub.ctx)
+ def visit_RevDBMetaVar(self, node):
+ if self.space.config.translation.reverse_debugger:
+ from pypy.interpreter.reverse_debugging import dbstate
+ if dbstate.extend_syntax_with_dollar_num:
+ self.emit_op_arg(ops.LOAD_REVDB_VAR, node.metavar)
+ return
+ self.error("$NUM is only valid in the reverse-debugger", node)
+
class TopLevelCodeGenerator(PythonCodeGenerator):
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py
b/pypy/interpreter/astcompiler/test/test_compiler.py
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -940,6 +940,15 @@
yield (self.st, "x=(lambda: (-0.0, 0.0), lambda: (0.0, -0.0))[1]()",
'repr(x)', '(0.0, -0.0)')
+ def test_revdb_metavar(self):
+ from pypy.interpreter.reverse_debugging import dbstate, setup_revdb
+ self.space.config.translation.reverse_debugger = True
+ setup_revdb(self.space)
+ dbstate.extend_syntax_with_dollar_num = True
+ dbstate.metavars = [self.space.wrap(6)]
+ self.simple_test("x = 7*$0", "x", 42)
+ dbstate.extend_syntax_with_dollar_num = False
+
class AppTestCompiler:
diff --git a/pypy/interpreter/astcompiler/tools/Python.asdl
b/pypy/interpreter/astcompiler/tools/Python.asdl
--- a/pypy/interpreter/astcompiler/tools/Python.asdl
+++ b/pypy/interpreter/astcompiler/tools/Python.asdl
@@ -71,6 +71,7 @@
| Repr(expr value)
| Num(object n) -- a number as a PyObject.
| Str(string s) -- need to specify raw, unicode, etc?
+ | RevDBMetaVar(int metavar)
-- other literals? bools?
-- the following expression can appear in assignment context
diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py
b/pypy/interpreter/astcompiler/tools/asdl_py.py
--- a/pypy/interpreter/astcompiler/tools/asdl_py.py
+++ b/pypy/interpreter/astcompiler/tools/asdl_py.py
@@ -400,7 +400,7 @@
if not (space.isinstance_w(w_obj, space.w_str) or
space.isinstance_w(w_obj, space.w_unicode)):
raise oefmt(space.w_TypeError,
- "AST string must be of type str or unicode")
+ "AST string must be of type str or unicode")
return w_obj
def get_field(space, w_node, name, optional):
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -412,6 +412,10 @@
def startup(self):
# To be called before using the space
+ if self.config.translation.reverse_debugger:
+ from pypy.interpreter.reverse_debugging import setup_revdb
+ setup_revdb(self)
+
self.threadlocals.enter_thread(self)
# Initialize already imported builtin modules
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -436,6 +436,8 @@
self.WITH_CLEANUP(oparg, next_instr)
elif opcode == opcodedesc.YIELD_VALUE.index:
self.YIELD_VALUE(oparg, next_instr)
+ elif opcode == opcodedesc.LOAD_REVDB_VAR.index:
+ self.LOAD_REVDB_VAR(oparg, next_instr)
else:
self.MISSING_OPCODE(oparg, next_instr)
@@ -1305,6 +1307,11 @@
w_dict = self.peekvalue()
self.space.setitem(w_dict, w_key, w_value)
+ def LOAD_REVDB_VAR(self, oparg, next_instr):
+ from pypy.interpreter.reverse_debugging import load_metavar
+ w_var = load_metavar(oparg)
+ self.pushvalue(w_var)
+
### ____________________________________________________________ ###
diff --git a/pypy/interpreter/pyparser/data/Grammar2.7
b/pypy/interpreter/pyparser/data/Grammar2.7
--- a/pypy/interpreter/pyparser/data/Grammar2.7
+++ b/pypy/interpreter/pyparser/data/Grammar2.7
@@ -104,7 +104,7 @@
'[' [listmaker] ']' |
'{' [dictorsetmaker] '}' |
'`' testlist1 '`' |
- NAME | NUMBER | STRING+ | revdb_metavar)
+ NAME | NUMBER | STRING+ | '$NUM')
listmaker: test ( list_for | (',' test)* [','] )
testlist_comp: test ( comp_for | (',' test)* [','] )
lambdef: 'lambda' [varargslist] ':' test
@@ -141,5 +141,3 @@
encoding_decl: NAME
yield_expr: 'yield' [testlist]
-
-revdb_metavar: '$NUM'
diff --git a/pypy/interpreter/reverse_debugging.py
b/pypy/interpreter/reverse_debugging.py
new file mode 100644
--- /dev/null
+++ b/pypy/interpreter/reverse_debugging.py
@@ -0,0 +1,41 @@
+import sys
+from rpython.rlib import revdb
+from rpython.rlib.debug import make_sure_not_resized
+from pypy.interpreter.error import oefmt
+
+
+class DBState:
+ extend_syntax_with_dollar_num = False
+ metavars = []
+
+dbstate = DBState()
+
+
+def setup_revdb(space):
+ assert space.config.translation.reverse_debugger
+ dbstate.space = space
+ #make_sure_not_resized(dbstate.breakpoint_funcnames)
+ #make_sure_not_resized(dbstate.watch_progs)
+ make_sure_not_resized(dbstate.metavars)
+ #revdb.register_debug_command(revdb.CMD_PRINT, lambda_print)
+ #revdb.register_debug_command(revdb.CMD_BACKTRACE, lambda_backtrace)
+ #revdb.register_debug_command(revdb.CMD_LOCALS, lambda_locals)
+ #revdb.register_debug_command(revdb.CMD_BREAKPOINTS, lambda_breakpoints)
+ #revdb.register_debug_command(revdb.CMD_MOREINFO, lambda_moreinfo)
+ #revdb.register_debug_command("ALLOCATING", lambda_allocating)
+ #revdb.register_debug_command(revdb.CMD_ATTACHID, lambda_attachid)
+ #revdb.register_debug_command(revdb.CMD_CHECKWATCH, lambda_checkwatch)
+ #revdb.register_debug_command(revdb.CMD_WATCHVALUES, lambda_watchvalues)
+
+def load_metavar(oparg):
+ space = dbstate.space
+ metavars = dbstate.metavars
+ w_var = metavars[oparg] if oparg < len(metavars) else None
+ if w_var is None:
+ raise oefmt(space.w_NameError, "no constant object '$%d'",
+ oparg)
+ if w_var is space.w_Ellipsis:
+ raise oefmt(space.w_RuntimeError,
+ "'$%d' refers to an object created later in time",
+ oparg)
+ return w_var
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit