[Python-checkins] CVS: python/dist/src/Tools/compiler/compiler syntax.py,NONE,1.1 pycodegen.py,1.52,1.53

Jeremy Hylton jhylton@users.sourceforge.net
Mon, 17 Sep 2001 11:03:57 -0700


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

Modified Files:
	pycodegen.py 
Added Files:
	syntax.py 
Log Message:
Handle more syntax errors.

Invoke compiler.syntax.check() after building AST.  If a SyntaxError
occurs, print the error and exit without generating a .pyc file.

Refactor code to use compiler.misc.set_filename() rather than passing
filename argument around to each CodeGenerator instance.




--- NEW FILE: syntax.py ---
"""Check for errs in the AST.

The Python parser does not catch all syntax errors.  Others, like
assignments with invalid targets, are caught in the code generation
phase.

The compiler package catches some errors in the transformer module.
But it seems clearer to write checkers that use the AST to detect
errors.
"""

from compiler import ast, walk

def check(tree, multi=None):
    v = SyntaxErrorChecker(multi)
    walk(tree, v)
    return v.errors

class SyntaxErrorChecker:
    """A visitor to find syntax errors in the AST."""

    def __init__(self, multi=None):
        """Create new visitor object.

        If optional argument multi is not None, then print messages
        for each error rather than raising a SyntaxError for the
        first.
        """
        self.multi = multi
        self.errors = 0

    def error(self, node, msg):
        self.errors = self.errors + 1
        if self.multi is not None:
            print "%s:%s: %s" % (node.filename, node.lineno, msg)
        else:
            raise SyntaxError, "%s (%s:%s)" % (msg, node.filename, node.lineno)

    def visitAssign(self, node):
        # the transformer module handles many of these
        for target in node.nodes:
            if isinstance(target, ast.AssList):
                if target.lineno is None:
                    target.lineno = node.lineno
                self.error(target, "can't assign to list comprehension")

Index: pycodegen.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Tools/compiler/compiler/pycodegen.py,v
retrieving revision 1.52
retrieving revision 1.53
diff -C2 -d -r1.52 -r1.53
*** pycodegen.py	2001/09/17 16:41:02	1.52
--- pycodegen.py	2001/09/17 18:03:55	1.53
***************
*** 9,13 ****
  from cStringIO import StringIO
  
! from compiler import ast, parse, walk
  from compiler import pyassem, misc, future, symbols
  from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
--- 9,13 ----
  from cStringIO import StringIO
  
! from compiler import ast, parse, walk, syntax
  from compiler import pyassem, misc, future, symbols
  from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
***************
*** 42,47 ****
          self.loop = None
  
-     
- 
  def compile(filename, display=0):
      f = open(filename)
--- 42,45 ----
***************
*** 49,56 ****
      f.close()
      mod = Module(buf, filename)
!     mod.compile(display)
!     f = open(filename + "c", "wb")
!     mod.dump(f)
!     f.close()
  
  class Module:
--- 47,58 ----
      f.close()
      mod = Module(buf, filename)
!     try:
!         mod.compile(display)
!     except SyntaxError, err:
!         print "SyntaxError:", err
!     else:
!         f = open(filename + "c", "wb")
!         mod.dump(f)
!         f.close()
  
  class Module:
***************
*** 62,66 ****
      def compile(self, display=0):
          tree = parse(self.source)
!         gen = ModuleCodeGenerator(self.filename, tree)
          if display:
              import pprint
--- 64,70 ----
      def compile(self, display=0):
          tree = parse(self.source)
!         misc.set_filename(self.filename, tree)
!         syntax.check(tree)
!         gen = ModuleCodeGenerator(tree)
          if display:
              import pprint
***************
*** 150,159 ****
      class_name = None # provide default for instance variable
  
!     def __init__(self, filename):
          if self.__initialized is None:
              self.initClass()
              self.__class__.__initialized = 1
          self.checkClass()
-         self.filename = filename
          self.locals = misc.Stack()
          self.setups = misc.Stack()
--- 154,162 ----
      class_name = None # provide default for instance variable
  
!     def __init__(self):
          if self.__initialized is None:
              self.initClass()
              self.__class__.__initialized = 1
          self.checkClass()
          self.locals = misc.Stack()
          self.setups = misc.Stack()
***************
*** 307,311 ****
  
      def _visitFuncOrLambda(self, node, isLambda=0):
!         gen = self.FunctionGen(node, self.filename, self.scopes, isLambda,
                                 self.class_name, self.get_module())
          walk(node.code, gen)
--- 310,314 ----
  
      def _visitFuncOrLambda(self, node, isLambda=0):
!         gen = self.FunctionGen(node, self.scopes, isLambda,
                                 self.class_name, self.get_module())
          walk(node.code, gen)
***************
*** 325,329 ****
  
      def visitClass(self, node):
!         gen = self.ClassGen(node, self.filename, self.scopes,
                              self.get_module())
          if node.doc:
--- 328,332 ----
  
      def visitClass(self, node):
!         gen = self.ClassGen(node, self.scopes,
                              self.get_module())
          if node.doc:
***************
*** 431,435 ****
          if not self.setups:
              raise SyntaxError, "'break' outside loop (%s, %d)" % \
!                   (self.filename, node.lineno)
          self.set_lineno(node)
          self.emit('BREAK_LOOP')
--- 434,438 ----
          if not self.setups:
              raise SyntaxError, "'break' outside loop (%s, %d)" % \
!                   (node.filename, node.lineno)
          self.set_lineno(node)
          self.emit('BREAK_LOOP')
***************
*** 438,442 ****
          if not self.setups:
              raise SyntaxError, "'continue' outside loop (%s, %d)" % \
!                   (self.filename, node.lineno)
          kind, block = self.setups.top()
          if kind == LOOP:
--- 441,445 ----
          if not self.setups:
              raise SyntaxError, "'continue' outside loop (%s, %d)" % \
!                   (node.filename, node.lineno)
          kind, block = self.setups.top()
          if kind == LOOP:
***************
*** 455,464 ****
              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):
--- 458,467 ----
              if kind != LOOP:
                  raise SyntaxError, "'continue' outside loop (%s, %d)" % \
!                       (node.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 % (node.filename, node.lineno)
  
      def visitTest(self, node, jump):
***************
*** 1086,1093 ****
      scopes = None
      
!     def __init__(self, filename, tree):
!         self.graph = pyassem.PyFlowGraph("<module>", filename)
          self.futures = future.find_futures(tree)
!         self.__super_init(filename)
          walk(tree, self)
  
--- 1089,1096 ----
      scopes = None
      
!     def __init__(self, tree):
!         self.graph = pyassem.PyFlowGraph("<module>", tree.filename)
          self.futures = future.find_futures(tree)
!         self.__super_init()
          walk(tree, self)
  
***************
*** 1099,1103 ****
      lambdaCount = 0
  
!     def __init__(self, func, filename, scopes, isLambda, class_name, mod):
          self.class_name = class_name
          self.module = mod
--- 1102,1106 ----
      lambdaCount = 0
  
!     def __init__(self, func, scopes, isLambda, class_name, mod):
          self.class_name = class_name
          self.module = mod
***************
*** 1109,1116 ****
              name = func.name
          args, hasTupleArg = generateArgList(func.argnames)
!         self.graph = pyassem.PyFlowGraph(name, filename, args, 
                                           optimized=1) 
          self.isLambda = isLambda
!         self.super_init(filename)
  
          if not isLambda and func.doc:
--- 1112,1119 ----
              name = func.name
          args, hasTupleArg = generateArgList(func.argnames)
!         self.graph = pyassem.PyFlowGraph(name, func.filename, args, 
                                           optimized=1) 
          self.isLambda = isLambda
!         self.super_init()
  
          if not isLambda and func.doc:
***************
*** 1163,1170 ****
      __super_init = AbstractFunctionCode.__init__
  
!     def __init__(self, func, filename, scopes, isLambda, class_name, mod):
          self.scopes = scopes
          self.scope = scopes[func]
!         self.__super_init(func, filename, scopes, isLambda, class_name, mod)
          self.graph.setFreeVars(self.scope.get_free_vars())
          self.graph.setCellVars(self.scope.get_cell_vars())
--- 1166,1173 ----
      __super_init = AbstractFunctionCode.__init__
  
!     def __init__(self, func, scopes, isLambda, class_name, mod):
          self.scopes = scopes
          self.scope = scopes[func]
!         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())
***************
*** 1175,1184 ****
  class AbstractClassCode:
  
!     def __init__(self, klass, filename, scopes, module):
          self.class_name = klass.name
          self.module = module
!         self.graph = pyassem.PyFlowGraph(klass.name, filename,
                                             optimized=0, klass=1)
!         self.super_init(filename)
          lnf = walk(klass.code, self.NameFinder(), verbose=0)
          self.locals.push(lnf.getLocals())
--- 1178,1187 ----
  class AbstractClassCode:
  
!     def __init__(self, klass, scopes, module):
          self.class_name = klass.name
          self.module = module
!         self.graph = pyassem.PyFlowGraph(klass.name, klass.filename,
                                             optimized=0, klass=1)
!         self.super_init()
          lnf = walk(klass.code, self.NameFinder(), verbose=0)
          self.locals.push(lnf.getLocals())
***************
*** 1201,1208 ****
      __super_init = AbstractClassCode.__init__
  
!     def __init__(self, klass, filename, scopes, module):
          self.scopes = scopes
          self.scope = scopes[klass]
!         self.__super_init(klass, filename, scopes, module)
          self.graph.setFreeVars(self.scope.get_free_vars())
          self.graph.setCellVars(self.scope.get_cell_vars())
--- 1204,1211 ----
      __super_init = AbstractClassCode.__init__
  
!     def __init__(self, klass, scopes, module):
          self.scopes = scopes
          self.scope = scopes[klass]
!         self.__super_init(klass, scopes, module)
          self.graph.setFreeVars(self.scope.get_free_vars())
          self.graph.setCellVars(self.scope.get_cell_vars())