paul@0 | 1 | """Check for errs in the AST. |
paul@0 | 2 | |
paul@0 | 3 | The Python parser does not catch all syntax errors. Others, like |
paul@0 | 4 | assignments with invalid targets, are caught in the code generation |
paul@0 | 5 | phase. |
paul@0 | 6 | |
paul@0 | 7 | The compiler package catches some errors in the transformer module. |
paul@0 | 8 | But it seems clearer to write checkers that use the AST to detect |
paul@0 | 9 | errors. |
paul@0 | 10 | """ |
paul@0 | 11 | |
paul@0 | 12 | from compiler import ast, walk |
paul@0 | 13 | |
paul@0 | 14 | def check(tree, multi=None): |
paul@0 | 15 | v = SyntaxErrorChecker(multi) |
paul@0 | 16 | walk(tree, v) |
paul@0 | 17 | return v.errors |
paul@0 | 18 | |
paul@0 | 19 | class SyntaxErrorChecker: |
paul@0 | 20 | """A visitor to find syntax errors in the AST.""" |
paul@0 | 21 | |
paul@0 | 22 | def __init__(self, multi=None): |
paul@0 | 23 | """Create new visitor object. |
paul@0 | 24 | |
paul@0 | 25 | If optional argument multi is not None, then print messages |
paul@0 | 26 | for each error rather than raising a SyntaxError for the |
paul@0 | 27 | first. |
paul@0 | 28 | """ |
paul@0 | 29 | self.multi = multi |
paul@0 | 30 | self.errors = 0 |
paul@0 | 31 | |
paul@0 | 32 | def error(self, node, msg): |
paul@0 | 33 | self.errors = self.errors + 1 |
paul@0 | 34 | if self.multi is not None: |
paul@0 | 35 | print "%s:%s: %s" % (node.filename, node.lineno, msg) |
paul@0 | 36 | else: |
paul@0 | 37 | raise SyntaxError, "%s (%s:%s)" % (msg, node.filename, node.lineno) |
paul@0 | 38 | |
paul@0 | 39 | def visitAssign(self, node): |
paul@0 | 40 | # the transformer module handles many of these |
paul@0 | 41 | pass |
paul@0 | 42 | ## for target in node.nodes: |
paul@0 | 43 | ## if isinstance(target, ast.AssList): |
paul@0 | 44 | ## if target.lineno is None: |
paul@0 | 45 | ## target.lineno = node.lineno |
paul@0 | 46 | ## self.error(target, "can't assign to list comprehension") |