[Python-checkins] CVS: python/dist/src/Tools/compiler/compiler pycodegen.py,1.39,1.39.2.1

Jeremy Hylton jhylton@users.sourceforge.net
Mon, 17 Dec 2001 16:06:05 -0800


Update of /cvsroot/python/python/dist/src/Tools/compiler/compiler
In directory usw-pr-cvs1:/tmp/cvs-serv31507

Modified Files:
      Tag: release21-maint
	pycodegen.py 
Log Message:
Backport bugfixes since rev 1.39 from the trunk.

Add is_constant_false(), rev 1.41.
Fixed print handling, rev. 1.41.
Handle private names, 1.42.
Make sure JUMP_ABS and POP_BLOCK blocks are contiguous, rev. 1.44.
Make sure class object has no co_varnames, rev. 1.45.
Fix typo in visitDict(), rev. 1.46.
Generate correct code for continue in try/except, rev. 1.47.



Index: pycodegen.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Tools/compiler/compiler/Attic/pycodegen.py,v
retrieving revision 1.39
retrieving revision 1.39.2.1
diff -C2 -d -r1.39 -r1.39.2.1
*** pycodegen.py	2001/04/12 21:54:41	1.39
--- pycodegen.py	2001/12/18 00:06:03	1.39.2.1
***************
*** 12,17 ****
  from compiler import pyassem, misc, future, symbols
  from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
! from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,\
!      CO_NESTED, TupleArg
  
  # Do we have Python 1.x or Python 2.x?
--- 12,18 ----
  from compiler import pyassem, misc, future, symbols
  from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
! from compiler.consts import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,\
!      CO_NESTED
! from compiler.pyassem import TupleArg
  
  # Do we have Python 1.x or Python 2.x?
***************
*** 29,32 ****
--- 30,38 ----
  }
  
+ LOOP = 1
+ EXCEPT = 2
+ TRY_FINALLY = 3
+ END_FINALLY = 4
+ 
  def compile(filename, display=0):
      f = open(filename)
***************
*** 34,41 ****
      f.close()
      mod = Module(buf, filename)
!     mod.compile(display)
!     f = open(filename + "c", "wb")
!     mod.dump(f)
!     f.close()
  
  class Module:
--- 40,51 ----
      f.close()
      mod = Module(buf, filename)
!     try:
!         mod.compile(display)
!     except SyntaxError:
!         raise
!     else:
!         f = open(filename + "c", "wb")
!         mod.dump(f)
!         f.close()
  
  class Module:
***************
*** 116,119 ****
--- 126,135 ----
          self.names.add(node.name)
  
+ def is_constant_false(node):
+     if isinstance(node, ast.Const):
+         if not node.value:
+             return 1
+     return 0
+ 
  class CodeGenerator:
      """Defines basic code generator for Python bytecode
***************
*** 132,135 ****
--- 148,152 ----
      optimized = 0 # is namespace access optimized?
      __initialized = None
+     class_name = None # provide default for instance variable
  
      def __init__(self, filename):
***************
*** 140,144 ****
          self.filename = filename
          self.locals = misc.Stack()
!         self.loops = misc.Stack()
          self.curStack = 0
          self.maxStack = 0
--- 157,161 ----
          self.filename = filename
          self.locals = misc.Stack()
!         self.setups = misc.Stack()
          self.curStack = 0
          self.maxStack = 0
***************
*** 171,174 ****
--- 188,202 ----
          return self.graph.getCode()
  
+     def mangle(self, name):
+         if self.class_name is not None:
+             return misc.mangle(name, self.class_name)
+         else:
+             return name
+ 
+     def parseSymbols(self, tree):
+         s = symbols.SymbolVisitor()
+         walk(tree, s)
+         return s.scopes
+ 
      # Next five methods handle name access
  
***************
*** 186,196 ****
  
      def _nameOp(self, prefix, name):
!         if not self.optimized:
!             self.emit(prefix + '_NAME', name)
!             return
!         if self.isLocalName(name):
!             self.emit(prefix + '_FAST', name)
          else:
!             self.emit(prefix + '_GLOBAL', name)
  
      def _implicitNameOp(self, prefix, name):
--- 214,234 ----
  
      def _nameOp(self, prefix, name):
!         name = self.mangle(name)
!         scope = self.scope.check_name(name)
!         if scope == SC_LOCAL:
!             if not self.optimized:
!                 self.emit(prefix + '_NAME', name)
!             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)
!         elif scope == SC_FREE or scope == SC_CELL:
!             self.emit(prefix + '_DEREF', name)
          else:
!             raise RuntimeError, "unsupported scope for var %s: %d" % \
!                   (name, scope)
  
      def _implicitNameOp(self, prefix, name):
***************
*** 234,242 ****
  
      def visitModule(self, node):
          self.emit('SET_LINENO', 0)
-         lnf = walk(node.node, self.NameFinder(), 0)
-         self.locals.push(lnf.getLocals())
          if node.doc:
!             self.fixDocstring(node.node)
          self.visit(node.node)
          self.emit('LOAD_CONST', None)
--- 272,283 ----
  
      def visitModule(self, node):
+         self.scopes = self.parseSymbols(node)
+         self.scope = self.scopes[node]
          self.emit('SET_LINENO', 0)
          if node.doc:
!             self.emit('LOAD_CONST', node.doc)
!             self.storeName('__doc__')
!         lnf = walk(node.node, self.NameFinder(), verbose=0)
!         self.locals.push(lnf.getLocals())
          self.visit(node.node)
          self.emit('LOAD_CONST', None)
***************
*** 253,257 ****
  
      def _visitFuncOrLambda(self, node, isLambda=0):
!         gen = self.FunctionGen(node, self.filename, self.scopes, isLambda)
          walk(node.code, gen)
          gen.finish()
--- 294,299 ----
  
      def _visitFuncOrLambda(self, node, isLambda=0):
!         gen = self.FunctionGen(node, self.filename, self.scopes, isLambda,
!                                self.class_name)
          walk(node.code, gen)
          gen.finish()
***************
*** 263,269 ****
  
      def visitClass(self, node):
!         gen = self.ClassGen(node, self.filename, self.scopes)
!         if node.doc:
!             self.fixDocstring(node.code)
          walk(node.code, gen)
          gen.finish()
--- 305,309 ----
  
      def visitClass(self, node):
!         gen = self.ClassGen(node, self.scopes, self.filename)
          walk(node.code, gen)
          gen.finish()
***************
*** 279,295 ****
          self.storeName(node.name)
  
-     def fixDocstring(self, node):
-         """Rewrite the ast for a class with a docstring.
- 
-         The AST includes a Discard(Const(docstring)) node.  Replace
-         this with an Assign([AssName('__doc__', ...])
-         """
-         assert isinstance(node, ast.Stmt)
-         stmts = node.nodes
-         discard = stmts[0]
-         assert isinstance(discard, ast.Discard)
-         stmts[0] = ast.Assign([ast.AssName('__doc__', 'OP_ASSIGN')],
-                               discard.expr)
-         stmts[0].lineno = discard.lineno
      # The rest are standard visitor methods
  
--- 319,322 ----
***************
*** 301,304 ****
--- 328,333 ----
          for i in range(numtests):
              test, suite = node.tests[i]
+             if is_constant_false(test):
+                 continue
              self.set_lineno(test)
              self.visit(test)
***************
*** 325,329 ****
  
          self.nextBlock(loop)
!         self.loops.push(loop)
  
          self.set_lineno(node, force=1)
--- 354,358 ----
  
          self.nextBlock(loop)
!         self.setups.push((LOOP, loop))
  
          self.set_lineno(node, force=1)
***************
*** 339,343 ****
          self.emit('POP_TOP')
          self.emit('POP_BLOCK')
!         self.loops.pop()
          if node.else_:
              self.visit(node.else_)
--- 368,372 ----
          self.emit('POP_TOP')
          self.emit('POP_BLOCK')
!         self.setups.pop()
          if node.else_:
              self.visit(node.else_)
***************
*** 348,352 ****
          anchor = self.newBlock()
          after = self.newBlock()
!         self.loops.push(start)
  
          self.set_lineno(node)
--- 377,381 ----
          anchor = self.newBlock()
          after = self.newBlock()
!         self.setups.push((LOOP, start))
  
          self.set_lineno(node)
***************
*** 357,367 ****
          self.set_lineno(node, force=1)
          self.emit('FOR_LOOP', anchor)
!         self.nextBlock()
          self.visit(node.assign)
          self.visit(node.body)
          self.emit('JUMP_ABSOLUTE', start)
!         self.startBlock(anchor)
          self.emit('POP_BLOCK')
!         self.loops.pop()
          if node.else_:
              self.visit(node.else_)
--- 386,397 ----
          self.set_lineno(node, force=1)
          self.emit('FOR_LOOP', anchor)
! ##        self.nextBlock()
          self.visit(node.assign)
          self.visit(node.body)
          self.emit('JUMP_ABSOLUTE', start)
! ##        self.startBlock(anchor)
!         self.nextBlock(anchor)
          self.emit('POP_BLOCK')
!         self.setups.pop()
          if node.else_:
              self.visit(node.else_)
***************
*** 369,373 ****
  
      def visitBreak(self, node):
!         if not self.loops:
              raise SyntaxError, "'break' outside loop (%s, %d)" % \
                    (self.filename, node.lineno)
--- 399,403 ----
  
      def visitBreak(self, node):
!         if not self.setups:
              raise SyntaxError, "'break' outside loop (%s, %d)" % \
                    (self.filename, node.lineno)
***************
*** 376,386 ****
  
      def visitContinue(self, node):
!         if not self.loops:
              raise SyntaxError, "'continue' outside loop (%s, %d)" % \
                    (self.filename, node.lineno)
!         l = self.loops.top()
!         self.set_lineno(node)
!         self.emit('JUMP_ABSOLUTE', l)
!         self.nextBlock()
  
      def visitTest(self, node, jump):
--- 406,435 ----
  
      def visitContinue(self, node):
!         # XXX test_grammar.py, line 351
!         if not self.setups:
              raise SyntaxError, "'continue' outside loop (%s, %d)" % \
                    (self.filename, node.lineno)
!         kind, block = self.setups.top()
!         if kind == LOOP:
!             self.set_lineno(node)
!             self.emit('JUMP_ABSOLUTE', block)
!             self.nextBlock()
!         elif kind == EXCEPT or kind == TRY_FINALLY:
!             self.set_lineno(node)
!             # find the block that starts the loop
!             top = len(self.setups)
!             while top > 0:
!                 top = top - 1
!                 kind, loop_block = self.setups[top]
!                 if kind == LOOP:
!                     break
!             if kind != LOOP:
!                 raise SyntaxError, "'continue' outside loop (%s, %d)" % \
!                       (self.filename, node.lineno)
!             self.emit('CONTINUE_LOOP', loop_block)
!             self.nextBlock()
!         elif kind == END_FINALLY:
!             msg = "'continue' not allowed inside 'finally' clause (%s, %d)"
!             raise SyntaxError, msg % (self.filename, node.lineno)
  
      def visitTest(self, node, jump):
***************
*** 527,530 ****
--- 576,580 ----
  
      def visitTryExcept(self, node):
+         body = self.newBlock()
          handlers = self.newBlock()
          end = self.newBlock()
***************
*** 535,541 ****
          self.set_lineno(node)
          self.emit('SETUP_EXCEPT', handlers)
!         self.nextBlock()
          self.visit(node.body)
          self.emit('POP_BLOCK')
          self.emit('JUMP_FORWARD', lElse)
          self.startBlock(handlers)
--- 585,593 ----
          self.set_lineno(node)
          self.emit('SETUP_EXCEPT', handlers)
!         self.nextBlock(body)
!         self.setups.push((EXCEPT, body))
          self.visit(node.body)
          self.emit('POP_BLOCK')
+         self.setups.pop()
          self.emit('JUMP_FORWARD', lElse)
          self.startBlock(handlers)
***************
*** 573,586 ****
      
      def visitTryFinally(self, node):
          final = self.newBlock()
          self.set_lineno(node)
          self.emit('SETUP_FINALLY', final)
!         self.nextBlock()
          self.visit(node.body)
          self.emit('POP_BLOCK')
          self.emit('LOAD_CONST', None)
          self.nextBlock(final)
          self.visit(node.final)
          self.emit('END_FINALLY')
  
      # misc
--- 625,643 ----
      
      def visitTryFinally(self, node):
+         body = self.newBlock()
          final = self.newBlock()
          self.set_lineno(node)
          self.emit('SETUP_FINALLY', final)
!         self.nextBlock(body)
!         self.setups.push((TRY_FINALLY, body))
          self.visit(node.body)
          self.emit('POP_BLOCK')
+         self.setups.pop()
          self.emit('LOAD_CONST', None)
          self.nextBlock(final)
+         self.setups.push((END_FINALLY, final))
          self.visit(node.final)
          self.emit('END_FINALLY')
+         self.setups.pop()
  
      # misc
***************
*** 649,653 ****
      def visitGetattr(self, node):
          self.visit(node.expr)
!         self.emit('LOAD_ATTR', node.attrname)
  
      # next five implement assignments
--- 706,710 ----
      def visitGetattr(self, node):
          self.visit(node.expr)
!         self.emit('LOAD_ATTR', self.mangle(node.attrname))
  
      # next five implement assignments
***************
*** 668,671 ****
--- 725,729 ----
              self.storeName(node.name)
          elif node.flags == 'OP_DELETE':
+             self.set_lineno(node)
              self.delName(node.name)
          else:
***************
*** 675,681 ****
          self.visit(node.expr)
          if node.flags == 'OP_ASSIGN':
!             self.emit('STORE_ATTR', node.attrname)
          elif node.flags == 'OP_DELETE':
!             self.emit('DELETE_ATTR', node.attrname)
          else:
              print "warning: unexpected flags:", node.flags
--- 733,739 ----
          self.visit(node.expr)
          if node.flags == 'OP_ASSIGN':
!             self.emit('STORE_ATTR', self.mangle(node.attrname))
          elif node.flags == 'OP_DELETE':
!             self.emit('DELETE_ATTR', self.mangle(node.attrname))
          else:
              print "warning: unexpected flags:", node.flags
***************
*** 701,704 ****
--- 759,763 ----
  
      def visitAugAssign(self, node):
+         self.set_lineno(node)
          aug_node = wrap_aug(node.node)
          self.visit(aug_node, "load")
***************
*** 731,738 ****
              self.visit(node.expr)
              self.emit('DUP_TOP')
!             self.emit('LOAD_ATTR', node.attrname)
          elif mode == "store":
              self.emit('ROT_TWO')
!             self.emit('STORE_ATTR', node.attrname)
  
      def visitAugSlice(self, node, mode):
--- 790,797 ----
              self.visit(node.expr)
              self.emit('DUP_TOP')
!             self.emit('LOAD_ATTR', self.mangle(node.attrname))
          elif mode == "store":
              self.emit('ROT_TWO')
!             self.emit('STORE_ATTR', self.mangle(node.attrname))
  
      def visitAugSlice(self, node, mode):
***************
*** 794,798 ****
          self.emit(opcode, kw << 8 | pos)
  
!     def visitPrint(self, node):
          self.set_lineno(node)
          if node.dest:
--- 853,857 ----
          self.emit(opcode, kw << 8 | pos)
  
!     def visitPrint(self, node, newline=0):
          self.set_lineno(node)
          if node.dest:
***************
*** 807,813 ****
              else:
                  self.emit('PRINT_ITEM')
  
      def visitPrintnl(self, node):
!         self.visitPrint(node)
          if node.dest:
              self.emit('PRINT_NEWLINE_TO')
--- 866,874 ----
              else:
                  self.emit('PRINT_ITEM')
+         if node.dest and not newline:
+             self.emit('POP_TOP')
  
      def visitPrintnl(self, node):
!         self.visitPrint(node, newline=1)
          if node.dest:
              self.emit('PRINT_NEWLINE_TO')
***************
*** 942,945 ****
--- 1003,1007 ----
  
      def visitTuple(self, node):
+         self.set_lineno(node)
          for elt in node.nodes:
              self.visit(elt)
***************
*** 947,950 ****
--- 1009,1013 ----
  
      def visitList(self, node):
+         self.set_lineno(node)
          for elt in node.nodes:
              self.visit(elt)
***************
*** 959,963 ****
          lineno = getattr(node, 'lineno', None)
          if lineno:
!             set.emit('SET_LINENO', lineno)
          self.emit('BUILD_MAP', 0)
          for k, v in node.items:
--- 1022,1026 ----
          lineno = getattr(node, 'lineno', None)
          if lineno:
!             self.emit('SET_LINENO', lineno)
          self.emit('BUILD_MAP', 0)
          for k, v in node.items:
***************
*** 988,991 ****
--- 1051,1055 ----
  
      def _nameOp(self, prefix, name):
+         name = self.mangle(name)
          scope = self.scope.check_name(name)
          if scope == SC_LOCAL:
***************
*** 1003,1007 ****
  
      def _visitFuncOrLambda(self, node, isLambda=0):
!         gen = self.FunctionGen(node, self.filename, self.scopes, isLambda)
          walk(node.code, gen)
          gen.finish()
--- 1067,1072 ----
  
      def _visitFuncOrLambda(self, node, isLambda=0):
!         gen = self.FunctionGen(node, self.filename, self.scopes, isLambda,
!                                self.class_name)
          walk(node.code, gen)
          gen.finish()
***************
*** 1020,1026 ****
  
      def visitClass(self, node):
!         gen = self.ClassGen(node, self.filename, self.scopes)
!         if node.doc:
!             self.fixDocstring(node.code)
          walk(node.code, gen)
          gen.finish()
--- 1085,1089 ----
  
      def visitClass(self, node):
!         gen = self.ClassGen(node, self.scopes, self.filename)
          walk(node.code, gen)
          gen.finish()
***************
*** 1079,1083 ****
      lambdaCount = 0
  
!     def __init__(self, func, filename, scopes, isLambda):
          if isLambda:
              klass = FunctionCodeGenerator
--- 1142,1149 ----
      lambdaCount = 0
  
!     def __init__(self, func, filename, scopes, isLambda, class_name):
!         self.scopes = scopes
!         self.scope = scopes[func]
!         self.class_name = class_name
          if isLambda:
              klass = FunctionCodeGenerator
***************
*** 1095,1099 ****
              self.setDocstring(func.doc)
  
!         lnf = walk(func.code, self.NameFinder(args), 0)
          self.locals.push(lnf.getLocals())
          if func.varargs:
--- 1161,1165 ----
              self.setDocstring(func.doc)
  
!         lnf = walk(func.code, self.NameFinder(args), verbose=0)
          self.locals.push(lnf.getLocals())
          if func.varargs:
***************
*** 1142,1149 ****
      __super_init = AbstractFunctionCode.__init__
  
!     def __init__(self, func, filename, scopes, isLambda):
          self.scopes = scopes
          self.scope = scopes[func]
!         self.__super_init(func, filename, scopes, isLambda)
          self.graph.setFreeVars(self.scope.get_free_vars())
          self.graph.setCellVars(self.scope.get_cell_vars())
--- 1208,1215 ----
      __super_init = AbstractFunctionCode.__init__
  
!     def __init__(self, func, filename, scopes, isLambda, class_name):
          self.scopes = scopes
          self.scope = scopes[func]
!         self.__super_init(func, filename, scopes, isLambda, class_name)
          self.graph.setFreeVars(self.scope.get_free_vars())
          self.graph.setCellVars(self.scope.get_cell_vars())
***************
*** 1152,1156 ****
  class AbstractClassCode:
  
!     def __init__(self, klass, filename, scopes):
          self.graph = pyassem.PyFlowGraph(klass.name, filename,
                                             optimized=0)
--- 1218,1224 ----
  class AbstractClassCode:
  
!     def __init__(self, klass, scopes, filename):
!         assert isinstance(filename, types.StringType)
!         assert isinstance(scopes, types.DictType)
          self.graph = pyassem.PyFlowGraph(klass.name, filename,
                                             optimized=0)
***************
*** 1175,1178 ****
--- 1243,1255 ----
      scopes = None
  
+     __super_init = AbstractClassCode.__init__
+ 
+     def __init__(self, klass, scopes, filename):
+         self.scopes = scopes
+         self.scope = scopes[klass]
+         self.__super_init(klass, scopes, filename)
+         self.graph.setFreeVars(self.scope.get_free_vars())
+         self.graph.setCellVars(self.scope.get_cell_vars())
+ 
  class NestedClassCodeGenerator(AbstractClassCode,
                                 NestedScopeMixin,
***************
*** 1181,1188 ****
      __super_init = AbstractClassCode.__init__
  
!     def __init__(self, klass, filename, scopes):
          self.scopes = scopes
          self.scope = scopes[klass]
!         self.__super_init(klass, filename, scopes)
          self.graph.setFreeVars(self.scope.get_free_vars())
          self.graph.setCellVars(self.scope.get_cell_vars())
--- 1258,1266 ----
      __super_init = AbstractClassCode.__init__
  
!     def __init__(self, klass, scopes, filename):
!         assert isinstance(filename, types.StringType)
          self.scopes = scopes
          self.scope = scopes[klass]
!         self.__super_init(klass, scopes, filename)
          self.graph.setFreeVars(self.scope.get_free_vars())
          self.graph.setCellVars(self.scope.get_cell_vars())
***************
*** 1209,1213 ****
      """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
      v = OpFinder()
!     walk(node, v, 0)
      return v.op
  
--- 1287,1291 ----
      """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
      v = OpFinder()
!     walk(node, v, verbose=0)
      return v.op
  
***************
*** 1221,1224 ****
--- 1299,1303 ----
              raise ValueError, "mixed ops in stmt"
      visitAssAttr = visitAssName
+     visitSubscript = visitAssName
  
  class Delegator:
***************
*** 1250,1253 ****
--- 1329,1333 ----
  class AugSubscript(Delegator):
      pass
+ 
  
  wrapper = {