[pypy-svn] r16558 - pypy/dist/pypy/lib/_stablecompiler

hpk at codespeak.net hpk at codespeak.net
Thu Aug 25 22:18:06 CEST 2005


Author: hpk
Date: Thu Aug 25 22:18:06 2005
New Revision: 16558

Modified:
   pypy/dist/pypy/lib/_stablecompiler/consts.py
   pypy/dist/pypy/lib/_stablecompiler/pyassem.py
   pypy/dist/pypy/lib/_stablecompiler/pycodegen.py
   pypy/dist/pypy/lib/_stablecompiler/symbols.py
   pypy/dist/pypy/lib/_stablecompiler/transformer.py
Log:
merge of pypy/interpreter/stablecompiler changes 
to pypy/lib/_stablecompiler with 

    svn merge -r 15452:16555 http://codespeak.net/svn/pypy/dist/pypy/interpreter/stablecompiler 

while being in the _stablecompiler directory. 
resolved conflicts that were mostly related to the 
trailing import sections. 



Modified: pypy/dist/pypy/lib/_stablecompiler/consts.py
==============================================================================
--- pypy/dist/pypy/lib/_stablecompiler/consts.py	(original)
+++ pypy/dist/pypy/lib/_stablecompiler/consts.py	Thu Aug 25 22:18:06 2005
@@ -8,6 +8,7 @@
 SC_FREE = 3
 SC_CELL = 4
 SC_UNKNOWN = 5
+SC_DEFAULT = 6
 
 CO_OPTIMIZED = 0x0001
 CO_NEWLOCALS = 0x0002

Modified: pypy/dist/pypy/lib/_stablecompiler/pyassem.py
==============================================================================
--- pypy/dist/pypy/lib/_stablecompiler/pyassem.py	(original)
+++ pypy/dist/pypy/lib/_stablecompiler/pyassem.py	Thu Aug 25 22:18:06 2005
@@ -316,7 +316,8 @@
 class PyFlowGraph(FlowGraph):
     super_init = FlowGraph.__init__
 
-    def __init__(self, name, filename, args=(), optimized=0, klass=None):
+    def __init__(self, name, filename, args=(), optimized=0, 
+                 klass=None, newlocals=0):
         self.super_init()
         self.name = name
         self.filename = filename
@@ -324,10 +325,11 @@
         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/lib/_stablecompiler/pycodegen.py
==============================================================================
--- pypy/dist/pypy/lib/_stablecompiler/pycodegen.py	(original)
+++ pypy/dist/pypy/lib/_stablecompiler/pycodegen.py	Thu Aug 25 22:18:06 2005
@@ -10,7 +10,7 @@
 from transformer import parse
 from visitor import walk
 import pyassem, misc, future, symbols
-from consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
+from consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, SC_DEFAULT
 from consts import CO_VARARGS, CO_VARKEYWORDS, \
     CO_NEWLOCALS, CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION
 from pyassem import TupleArg
@@ -195,6 +195,9 @@
     defined.
     """
 
+    scopeambiguity = False
+    parentscopeambiguity = False
+
     optimized = 0 # is namespace access optimized?
     __initialized = None
     class_name = None # provide default for instance variable
@@ -267,9 +270,18 @@
         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):
@@ -281,12 +293,14 @@
             else:
                 self.emit(prefix + '_FAST', name)
         elif scope == SC_GLOBAL:
-            if not self.optimized:
-                self.emit(prefix + '_NAME', name)
-            else:
-                self.emit(prefix + '_GLOBAL', name)
+            self.emit(prefix + '_GLOBAL', name)
         elif scope == SC_FREE or scope == SC_CELL:
             self.emit(prefix + '_DEREF', name)
+        elif scope == SC_DEFAULT: 
+            if self.optimized and self.localsfullyknown:
+                self.emit(prefix + '_GLOBAL', name)
+            else:
+                self.emit(prefix + '_NAME', name)
         else:
             raise RuntimeError, "unsupported scope for var %s: %d" % \
                   (name, scope)
@@ -376,7 +390,8 @@
             ndecorators = 0
 
         gen = self.FunctionGen(node, self.scopes, isLambda,
-                               self.class_name, self.get_module())
+                               self.class_name, self.get_module(),
+                               parentscopeambiguity = self.scopeambiguity or self.parentscopeambiguity)
         walk(node.code, gen)
         gen.finish()
         self.set_lineno(node)
@@ -397,7 +412,8 @@
 
     def visitClass(self, node):
         gen = self.ClassGen(node, self.scopes,
-                            self.get_module())
+                            self.get_module(), 
+                            parentscopeambiguity = self.scopeambiguity or self.parentscopeambiguity)
         walk(node.code, gen)
         gen.finish()
         self.set_lineno(node)
@@ -631,7 +647,8 @@
 
     def visitGenExpr(self, node):
         gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
-                                   self.get_module())
+                                   self.get_module(), 
+                                   parentscopeambiguity=self.scopeambiguity or self.parentscopeambiguity)
         walk(node.code, gen)
         gen.finish()
         self.set_lineno(node)
@@ -811,6 +828,11 @@
     # misc
 
     def visitDiscard(self, node):
+        # Important: this function is overridden in InteractiveCodeGenerator,
+        # which also has the effect that the following test only occurs in
+        # non-'single' modes.
+        if isinstance(node.expr, ast.Const):
+            return    # skip LOAD_CONST/POP_TOP pairs (for e.g. docstrings)
         self.set_lineno(node)
         self.visit(node.expr)
         self.emit('POP_TOP')
@@ -1289,7 +1311,8 @@
 
         args, hasTupleArg = generateArgList(func.argnames)
         self.graph = pyassem.PyFlowGraph(name, func.filename, args,
-                                         optimized=1)
+                                         optimized=self.localsfullyknown,
+                                         newlocals=1)
         self.isLambda = isLambda
         self.super_init()
 
@@ -1342,9 +1365,14 @@
 
     __super_init = AbstractFunctionCode.__init__
 
-    def __init__(self, func, scopes, isLambda, class_name, mod):
+    def __init__(self, func, scopes, isLambda, class_name, mod, parentscopeambiguity):
         self.scopes = scopes
         self.scope = scopes[func]
+
+        self.localsfullyknown = self.scope.localsfullyknown 
+        self.parentscopeambiguity = parentscopeambiguity
+        self.scopeambiguity = (not self.localsfullyknown or parentscopeambiguity)
+
         self.__super_init(func, scopes, isLambda, class_name, mod)
         self.graph.setFreeVars(self.scope.get_free_vars())
         self.graph.setCellVars(self.scope.get_cell_vars())
@@ -1358,9 +1386,14 @@
 
     __super_init = AbstractFunctionCode.__init__
 
-    def __init__(self, gexp, scopes, class_name, mod):
+    def __init__(self, gexp, scopes, class_name, mod, parentscopeambiguity):
         self.scopes = scopes
         self.scope = scopes[gexp]
+
+        self.localsfullyknown = self.scope.localsfullyknown 
+        self.parentscopeambiguity = parentscopeambiguity
+        self.scopeambiguity = (not self.localsfullyknown or parentscopeambiguity)
+
         self.__super_init(gexp, scopes, 1, class_name, mod)
         self.graph.setFreeVars(self.scope.get_free_vars())
         self.graph.setCellVars(self.scope.get_cell_vars())
@@ -1394,9 +1427,13 @@
 
     __super_init = AbstractClassCode.__init__
 
-    def __init__(self, klass, scopes, module):
+    def __init__(self, klass, scopes, module, parentscopeambiguity):
         self.scopes = scopes
         self.scope = scopes[klass]
+
+        self.parentscopeambiguity = parentscopeambiguity
+        self.scopeambiguity = parentscopeambiguity
+
         self.__super_init(klass, scopes, module)
         self.graph.setFreeVars(self.scope.get_free_vars())
         self.graph.setCellVars(self.scope.get_cell_vars())

Modified: pypy/dist/pypy/lib/_stablecompiler/symbols.py
==============================================================================
--- pypy/dist/pypy/lib/_stablecompiler/symbols.py	(original)
+++ pypy/dist/pypy/lib/_stablecompiler/symbols.py	Thu Aug 25 22:18:06 2005
@@ -1,7 +1,8 @@
 """Module symbol-table generator"""
 
 import ast
-from consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, SC_UNKNOWN
+from consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL, \
+                   SC_UNKNOWN, SC_DEFAULT
 from misc import mangle
 import types
 
@@ -11,6 +12,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
@@ -20,6 +22,7 @@
         self.globals = {}
         self.params = {}
         self.frees = {}
+        self.hasbeenfree = {}
         self.cells = {}
         self.children = []
         # nested is true if the class could contain free variables,
@@ -100,7 +103,7 @@
         if self.nested:
             return SC_UNKNOWN
         else:
-            return SC_GLOBAL
+            return SC_DEFAULT
 
     def get_free_vars(self):
         if not self.nested:
@@ -111,6 +114,7 @@
             if not (self.defs.has_key(name) or
                     self.globals.has_key(name)):
                 free[name] = 1
+        self.hasbeenfree.update(free)
         return free.keys()
 
     def handle_children(self):
@@ -133,7 +137,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 self.frees.has_key(name):
             del self.frees[name]
         for child in self.children:
@@ -237,6 +242,12 @@
         self.visit(node.code, scope)
         self.handle_free_vars(scope, parent)
 
+    def visitExec(self, node, parent): 
+        if not (node.globals or node.locals):
+            parent.localsfullyknown = False # bare exec statement
+        for child in node.getChildNodes():
+            self.visit(child, parent)
+    
     def visitGenExpr(self, node, parent):
         scope = GenExprScope(self.module, self.klass);
         if parent.nested or isinstance(parent, FunctionScope) \
@@ -331,6 +342,7 @@
     def visitFrom(self, node, scope):
         for name, asname in node.names:
             if name == "*":
+                scope.localsfullyknown = False 
                 continue
             scope.add_def(asname or name)
 

Modified: pypy/dist/pypy/lib/_stablecompiler/transformer.py
==============================================================================
--- pypy/dist/pypy/lib/_stablecompiler/transformer.py	(original)
+++ pypy/dist/pypy/lib/_stablecompiler/transformer.py	Thu Aug 25 22:18:06 2005
@@ -172,24 +172,26 @@
         raise WalkerError, ('unexpected node type', n)
 
     def single_input(self, node):
-        ### do we want to do anything about being "interactive" ?
         # NEWLINE | simple_stmt | compound_stmt NEWLINE
         n = node[0][0]
         if n != token.NEWLINE:
-            return self.com_stmt(node[0])
-
-        return Pass()
+            stmt = self.com_stmt(node[0])
+        else:
+            stmt = Pass()
+        return Module(None, stmt)
 
     def file_input(self, nodelist):
         doc = self.get_docstring(nodelist, symbol.file_input)
-        if doc is not None:
-            i = 1
-        else:
-            i = 0
         stmts = []
-        for node in nodelist[i:]:
+        for node in nodelist:
             if node[0] != token.ENDMARKER and node[0] != token.NEWLINE:
                 self.com_append_stmt(stmts, node)
+
+        if doc is not None:
+            assert isinstance(stmts[0], Discard)
+            assert isinstance(stmts[0].expr, Const)
+            del stmts[0]
+
         return Module(doc, Stmt(stmts))
 
     def eval_input(self, nodelist):
@@ -255,7 +257,8 @@
         if args[0] == symbol.varargslist:
             names, defaults, flags = self.com_arglist(args[1:])
         else:
-            names = defaults = ()
+            names = []
+            defaults = []
             flags = 0
         doc = self.get_docstring(nodelist[-1])
 
@@ -704,7 +707,7 @@
 
     def atom_lsqb(self, nodelist):
         if nodelist[1][0] == token.RSQB:
-            return List(())
+            return List([])
         return self.com_list_constructor(nodelist[1])
 
     def atom_lbrace(self, nodelist):
@@ -929,6 +932,7 @@
         l = self.com_node(node)
         if l.__class__ in (Name, Slice, Subscript, Getattr):
             return l
+        print node # XXX
         raise SyntaxError, "can't assign to %s" % l.__class__.__name__
 
     def com_assign(self, node, assigning):



More information about the Pypy-commit mailing list