[pypy-svn] r17565 - in pypy/dist/pypy/interpreter: astcompiler pyparser pyparser/test test
ac at codespeak.net
ac at codespeak.net
Wed Sep 14 16:06:36 CEST 2005
Author: ac
Date: Wed Sep 14 16:06:35 2005
New Revision: 17565
Modified:
pypy/dist/pypy/interpreter/astcompiler/consts.py
pypy/dist/pypy/interpreter/astcompiler/pyassem.py
pypy/dist/pypy/interpreter/astcompiler/pycodegen.py
pypy/dist/pypy/interpreter/astcompiler/symbols.py
pypy/dist/pypy/interpreter/pyparser/astbuilder.py
pypy/dist/pypy/interpreter/pyparser/test/test_astcompiler.py
pypy/dist/pypy/interpreter/test/test_compiler.py
Log:
(Arre, Samuele)
Port the scope ambiguity fix from stablecompiler and
make gen-exprs work (allmost).
Modified: pypy/dist/pypy/interpreter/astcompiler/consts.py
==============================================================================
--- pypy/dist/pypy/interpreter/astcompiler/consts.py (original)
+++ pypy/dist/pypy/interpreter/astcompiler/consts.py Wed Sep 14 16:06:35 2005
@@ -8,7 +8,7 @@
SC_FREE = 3
SC_CELL = 4
SC_UNKNOWN = 5
-SC_REALLY_GLOBAL = 6
+SC_DEFAULT = 6
CO_OPTIMIZED = 0x0001
CO_NEWLOCALS = 0x0002
Modified: pypy/dist/pypy/interpreter/astcompiler/pyassem.py
==============================================================================
--- pypy/dist/pypy/interpreter/astcompiler/pyassem.py (original)
+++ pypy/dist/pypy/interpreter/astcompiler/pyassem.py Wed Sep 14 16:06:35 2005
@@ -434,7 +434,8 @@
class PyFlowGraph(FlowGraph):
- def __init__(self, space, name, filename, args=None, optimized=0, klass=0):
+ def __init__(self, space, name, filename, args=None, optimized=0,
+ klass=0, newlocals=0):
FlowGraph.__init__(self, space)
if args is None:
args = []
@@ -444,10 +445,12 @@
self.args = args # XXX
self.argcount = getArgCount(args)
self.klass = klass
+ self.flags = 0
if optimized:
- self.flags = CO_OPTIMIZED | CO_NEWLOCALS
- else:
- self.flags = 0
+ self.flags |= CO_OPTIMIZED
+ if newlocals:
+ self.flags |= CO_NEWLOCALS
+
self.consts = []
self.names = []
# Free variables found by the symbol table scan, including
Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py
==============================================================================
--- pypy/dist/pypy/interpreter/astcompiler/pycodegen.py (original)
+++ pypy/dist/pypy/interpreter/astcompiler/pycodegen.py Wed Sep 14 16:06:35 2005
@@ -9,7 +9,7 @@
from pypy.interpreter.astcompiler import ast, parse, walk, syntax
from pypy.interpreter.astcompiler import pyassem, misc, future, symbols
from pypy.interpreter.astcompiler.consts import SC_LOCAL, SC_GLOBAL, \
- SC_FREE, SC_CELL, SC_REALLY_GLOBAL
+ SC_FREE, SC_CELL, SC_DEFAULT
from pypy.interpreter.astcompiler.consts import CO_VARARGS, CO_VARKEYWORDS, \
CO_NEWLOCALS, CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION
from pypy.interpreter.astcompiler.pyassem import TupleArg
@@ -140,7 +140,7 @@
"""Defines basic code generator for Python bytecode
"""
-
+ scopeambiguity = False
def __init__(self, space, graph):
self.space = space
@@ -219,9 +219,19 @@
self._nameOp('STORE', name)
def loadName(self, name):
+ if (self.scope.nested and self.scopeambiguity and
+ name in self.scope.hasbeenfree):
+ raise SyntaxError("cannot reference variable '%s' because "
+ "of ambiguity between "
+ "scopes" % name)
+
self._nameOp('LOAD', name)
def delName(self, name):
+ scope = self.scope.check_name(name)
+ if scope == SC_CELL:
+ raise SyntaxError("can not delete variable '%s' "
+ "referenced in nested scope" % name)
self._nameOp('DELETE', name)
def _nameOp(self, prefix, name):
@@ -233,14 +243,14 @@
else:
self.emitop(prefix + '_FAST', name)
elif scope == SC_GLOBAL:
- if not self.optimized:
- self.emitop(prefix + '_NAME', name)
- else:
- self.emitop(prefix + '_GLOBAL', name)
+ self.emitop(prefix + '_GLOBAL', name)
elif scope == SC_FREE or scope == SC_CELL:
self.emitop(prefix + '_DEREF', name)
- elif scope == SC_REALLY_GLOBAL:
- self.emitop(prefix + '_GLOBAL', name)
+ elif scope == SC_DEFAULT:
+ if self.optimized and self.localsfullyknown:
+ self.emitop(prefix + '_GLOBAL', name)
+ else:
+ self.emitop(prefix + '_NAME', name)
else:
raise RuntimeError, "unsupported scope for var %s: %d" % \
(name, scope)
@@ -331,7 +341,8 @@
ndecorators = 0
gen = FunctionCodeGenerator(self.space, node, isLambda,
- self.class_name, self.get_module())
+ self.class_name, self.get_module(),
+ self.scopeambiguity)
walk(node.code, gen)
gen.finish()
self.set_lineno(node)
@@ -354,7 +365,8 @@
def visitClass(self, node):
gen = ClassCodeGenerator(self.space, node,
- self.get_module())
+ self.get_module(),
+ self.scopeambiguity)
walk(node.code, gen)
gen.finish()
self.set_lineno(node)
@@ -600,7 +612,7 @@
def visitGenExpr(self, node):
gen = GenExprCodeGenerator(self.space, node, self.class_name,
- self.get_module())
+ self.get_module(), self.scopeambiguity)
inner = node.code
assert isinstance(inner, ast.GenExprInner)
walk(inner, gen)
@@ -836,8 +848,6 @@
self.emitop('IMPORT_NAME', node.modname)
for name, alias in node.names:
if name == '*':
- if self.scope.nested:
- raise SyntaxError('import * is not allowed in a nested function')
self.namespace = 0
self.emit('IMPORT_STAR')
# There can only be one name w/ from ... import *
@@ -925,8 +935,6 @@
}
def visitExec(self, node):
- if self.scope.nested and node.locals is None and node.globals is None:
- raise SyntaxError('unqualified exec is not allowed in a nested function')
node.expr.accept( self )
if node.locals is None:
self.emitop_obj('LOAD_CONST', self.space.w_None)
@@ -1205,21 +1213,20 @@
node.expr.accept( self )
self.emit('PRINT_EXPR')
-AbstractFunctionCodeLambdaCounter = misc.Counter(0)
-
class AbstractFunctionCode(CodeGenerator):
def __init__(self, space, func, isLambda, class_name, mod):
self.class_name = class_name
self.module = mod
if isLambda:
- name = "<lambda.%d>" % AbstractFunctionCodeLambdaCounter.next()
+ name = "<lambda>"
else:
assert isinstance(func, ast.Function)
name = func.name
args, hasTupleArg = generateArgList(func.argnames)
graph = pyassem.PyFlowGraph(space, name, func.filename, args,
- optimized=1)
+ optimized=self.localsfullyknown,
+ newlocals=1)
self.isLambda = isLambda
CodeGenerator.__init__(self, space, graph)
self.optimized = 1
@@ -1270,10 +1277,13 @@
class FunctionCodeGenerator(AbstractFunctionCode):
- def __init__(self, space, func, isLambda, class_name, mod):
+ def __init__(self, space, func, isLambda, class_name, mod, parentscopeambiguity):
assert func.scope is not None
self.scope = func.scope
+ self.localsfullyknown = self.scope.localsfullyknown
+ self.scopeambiguity = (not self.localsfullyknown or parentscopeambiguity)
AbstractFunctionCode.__init__(self, space, func, isLambda, class_name, mod)
+
self.graph.setFreeVars(self.scope.get_free_vars())
self.graph.setCellVars(self.scope.get_cell_vars())
if self.scope.generator:
@@ -1281,9 +1291,12 @@
class GenExprCodeGenerator(AbstractFunctionCode):
- def __init__(self, space, gexp, class_name, mod):
+ def __init__(self, space, gexp, class_name, mod, parentscopeambiguity):
assert gexp.scope is not None
self.scope = gexp.scope
+ self.localsfullyknown = self.scope.localsfullyknown
+ self.scopeambiguity = (not self.localsfullyknown or parentscopeambiguity)
+
AbstractFunctionCode.__init__(self, space, gexp, 1, class_name, mod)
self.graph.setFreeVars(self.scope.get_free_vars())
self.graph.setCellVars(self.scope.get_cell_vars())
@@ -1296,6 +1309,7 @@
self.module = module
graph = pyassem.PyFlowGraph( space, klass.name, klass.filename,
optimized=0, klass=1)
+
CodeGenerator.__init__(self, space, graph)
self.graph.setFlag(CO_NEWLOCALS)
if not space.is_w(klass.doc, space.w_None):
@@ -1311,9 +1325,10 @@
class ClassCodeGenerator(AbstractClassCode):
- def __init__(self, space, klass, module):
+ def __init__(self, space, klass, module, parentscopeambiguity):
assert klass.scope is not None
self.scope = klass.scope
+ self.scopeambiguity = parentscopeambiguity
AbstractClassCode.__init__(self, space, klass, module)
self.graph.setFreeVars(self.scope.get_free_vars())
self.graph.setCellVars(self.scope.get_cell_vars())
Modified: pypy/dist/pypy/interpreter/astcompiler/symbols.py
==============================================================================
--- pypy/dist/pypy/interpreter/astcompiler/symbols.py (original)
+++ pypy/dist/pypy/interpreter/astcompiler/symbols.py Wed Sep 14 16:06:35 2005
@@ -2,7 +2,7 @@
from pypy.interpreter.astcompiler import ast
from pypy.interpreter.astcompiler.consts import SC_LOCAL, SC_GLOBAL, \
- SC_FREE, SC_CELL, SC_UNKNOWN, SC_REALLY_GLOBAL
+ SC_FREE, SC_CELL, SC_UNKNOWN, SC_DEFAULT
from pypy.interpreter.astcompiler.misc import mangle, Counter
from pypy.interpreter.pyparser.error import SyntaxError
import types
@@ -13,6 +13,7 @@
MANGLE_LEN = 256
class Scope:
+ localsfullyknown = True
# XXX how much information do I need about each name?
def __init__(self, name, module, klass=None):
self.name = name
@@ -22,6 +23,7 @@
self.globals = {}
self.params = {}
self.frees = {}
+ self.hasbeenfree = {}
self.cells = {}
self.children = []
# nested is true if the class could contain free variables,
@@ -91,7 +93,7 @@
The scope of a name could be LOCAL, GLOBAL, FREE, or CELL.
"""
if name in self.globals:
- return SC_REALLY_GLOBAL
+ return SC_GLOBAL
if name in self.cells:
return SC_CELL
if name in self.defs:
@@ -102,7 +104,7 @@
if self.nested:
return SC_UNKNOWN
else:
- return SC_GLOBAL
+ return SC_DEFAULT
def get_free_vars(self):
if not self.nested:
@@ -113,6 +115,7 @@
if not (name in self.defs or
name in self.globals):
free[name] = 1
+ self.hasbeenfree.update(free)
return free.keys()
def handle_children(self):
@@ -135,7 +138,8 @@
Be careful to stop if a child does not think the name is
free.
"""
- self.globals[name] = 1
+ if name not in self.defs:
+ self.globals[name] = 1
if name in self.frees:
del self.frees[name]
for child in self.children:
@@ -156,7 +160,7 @@
if sc == SC_UNKNOWN or sc == SC_FREE \
or isinstance(self, ClassScope):
self.frees[name] = 1
- elif sc == SC_GLOBAL or sc == SC_REALLY_GLOBAL:
+ elif sc == SC_DEFAULT or sc == SC_GLOBAL:
child_globals.append(name)
elif isinstance(self, FunctionScope) and sc == SC_LOCAL:
self.cells[name] = 1
@@ -262,6 +266,12 @@
self.pop_scope()
self.handle_free_vars(scope, parent)
+ def visitExec(self, node):
+ if not (node.globals or node.locals):
+ parent = self.cur_scope()
+ parent.localsfullyknown = False # bare exec statement
+ ast.ASTVisitor.visitExec(self, node)
+
def visitGenExpr(self, node ):
parent = self.cur_scope()
scope = GenExprScope(self.module, self.klass);
@@ -375,6 +385,7 @@
scope = self.cur_scope()
for name, asname in node.names:
if name == "*":
+ scope.localsfullyknown = False
continue
scope.add_def(asname or name)
Modified: pypy/dist/pypy/interpreter/pyparser/astbuilder.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyparser/astbuilder.py (original)
+++ pypy/dist/pypy/interpreter/pyparser/astbuilder.py Wed Sep 14 16:06:35 2005
@@ -795,6 +795,7 @@
# GenExpr(GenExprInner(Name('i'), [GenExprFor(AssName('i', 'OP_ASSIGN'), Name('j'), [])])))]))
expr = atoms[0]
genexpr_for = parse_genexpr_for(atoms[1:])
+ genexpr_for[0].is_outmost = True
builder.push(ast.GenExpr(ast.GenExprInner(expr, genexpr_for)))
return
builder.push(ast.Tuple(items))
Modified: pypy/dist/pypy/interpreter/pyparser/test/test_astcompiler.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyparser/test/test_astcompiler.py (original)
+++ pypy/dist/pypy/interpreter/pyparser/test/test_astcompiler.py Wed Sep 14 16:06:35 2005
@@ -31,7 +31,7 @@
listmakers,
dictmakers,
multiexpr,
- # genexps, investigate?
+ genexps,
attraccess,
slices,
imports,
Modified: pypy/dist/pypy/interpreter/test/test_compiler.py
==============================================================================
--- pypy/dist/pypy/interpreter/test/test_compiler.py (original)
+++ pypy/dist/pypy/interpreter/test/test_compiler.py Wed Sep 14 16:06:35 2005
@@ -197,12 +197,6 @@
def setup_method(self, method):
self.compiler = PythonAstCompiler(self.space)
- def test_scope_importstar_with_nested_free(self):
- py.test.skip("INPROGESS")
-
- def test_scope_exec_with_nested_free(self):
- py.test.skip("INPROGESS")
-
class SkippedForNowTestPyPyCompiler(BaseTestCompiler):
def setup_method(self, method):
self.compiler = PyPyCompiler(self.space)
More information about the Pypy-commit
mailing list