From: <pj...@us...> - 2009-04-08 01:14:15
|
Revision: 6187 http://jython.svn.sourceforge.net/jython/?rev=6187&view=rev Author: pjenvey Date: 2009-04-08 01:14:13 +0000 (Wed, 08 Apr 2009) Log Message: ----------- from: http://svn.python.org/projects/python/branches/release25-maint/Lib/compiler/pycodegen.py@53576 http://svn.python.org/projects/python/branches/release25-maint/Lib/compiler/transformer.py@53576 Modified Paths: -------------- trunk/jython/Lib/compiler/pycodegen.py trunk/jython/Lib/compiler/transformer.py Modified: trunk/jython/Lib/compiler/pycodegen.py =================================================================== --- trunk/jython/Lib/compiler/pycodegen.py 2009-04-07 13:09:48 UTC (rev 6186) +++ trunk/jython/Lib/compiler/pycodegen.py 2009-04-08 01:14:13 UTC (rev 6187) @@ -3,17 +3,15 @@ import marshal import struct import sys -import types from cStringIO import StringIO from compiler import ast, parse, walk, syntax -#from compiler import pyassem, misc, future, symbols -from compiler import misc, future, symbols +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, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION -#from compiler.pyassem import TupleArg -TupleArg = None +from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, + CO_NESTED, CO_GENERATOR, CO_FUTURE_DIVISION, + CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT) +from compiler.pyassem import TupleArg # XXX The version-specific code can go, since this code only works with 2.x. # Do we have Python 1.x or Python 2.x? @@ -121,8 +119,7 @@ f.write(self.getPycHeader()) marshal.dump(self.code, f) - #MAGIC = imp.get_magic() - MAGIC = None + MAGIC = imp.get_magic() def getPycHeader(self): # compile.c uses marshal to write a long directly, with @@ -207,8 +204,6 @@ self.checkClass() self.locals = misc.Stack() self.setups = misc.Stack() - self.curStack = 0 - self.maxStack = 0 self.last_lineno = None self._setupGraphDelegation() self._div_op = "BINARY_DIVIDE" @@ -219,8 +214,10 @@ if feature == "division": self.graph.setFlag(CO_FUTURE_DIVISION) self._div_op = "BINARY_TRUE_DIVIDE" - elif feature == "generators": - self.graph.setFlag(CO_GENERATOR_ALLOWED) + elif feature == "absolute_import": + self.graph.setFlag(CO_FUTURE_ABSIMPORT) + elif feature == "with_statement": + self.graph.setFlag(CO_FUTURE_WITH_STATEMENT) def initClass(self): """This method is called once for each class""" @@ -371,6 +368,13 @@ self._visitFuncOrLambda(node, isLambda=1) def _visitFuncOrLambda(self, node, isLambda=0): + if not isLambda and node.decorators: + for decorator in node.decorators.nodes: + self.visit(decorator) + ndecorators = len(node.decorators.nodes) + else: + ndecorators = 0 + gen = self.FunctionGen(node, self.scopes, isLambda, self.class_name, self.get_module()) walk(node.code, gen) @@ -378,15 +382,9 @@ self.set_lineno(node) for default in node.defaults: self.visit(default) - frees = gen.scope.get_free_vars() - if frees: - for name in frees: - self.emit('LOAD_CLOSURE', name) - self.emit('LOAD_CONST', gen) - self.emit('MAKE_CLOSURE', len(node.defaults)) - else: - self.emit('LOAD_CONST', gen) - self.emit('MAKE_FUNCTION', len(node.defaults)) + self._makeClosure(gen, len(node.defaults)) + for i in range(ndecorators): + self.emit('CALL_FUNCTION', 1) def visitClass(self, node): gen = self.ClassGen(node, self.scopes, @@ -398,14 +396,7 @@ for base in node.bases: self.visit(base) self.emit('BUILD_TUPLE', len(node.bases)) - frees = gen.scope.get_free_vars() - for name in frees: - self.emit('LOAD_CLOSURE', name) - self.emit('LOAD_CONST', gen) - if frees: - self.emit('MAKE_CLOSURE', 0) - else: - self.emit('MAKE_FUNCTION', 0) + self._makeClosure(gen, 0) self.emit('CALL_FUNCTION', 0) self.emit('BUILD_CLASS') self.storeName(node.name) @@ -539,6 +530,19 @@ def visitOr(self, node): self.visitTest(node, 'JUMP_IF_TRUE') + def visitIfExp(self, node): + endblock = self.newBlock() + elseblock = self.newBlock() + self.visit(node.test) + self.emit('JUMP_IF_FALSE', elseblock) + self.emit('POP_TOP') + self.visit(node.then) + self.emit('JUMP_FORWARD', endblock) + self.nextBlock(elseblock) + self.emit('POP_TOP') + self.visit(node.else_) + self.nextBlock(endblock) + def visitCompare(self, node): self.visit(node.expr) cleanup = self.newBlock() @@ -624,33 +628,116 @@ self.newBlock() self.emit('POP_TOP') - # exception related + def _makeClosure(self, gen, args): + frees = gen.scope.get_free_vars() + if frees: + for name in frees: + self.emit('LOAD_CLOSURE', name) + self.emit('BUILD_TUPLE', len(frees)) + self.emit('LOAD_CONST', gen) + self.emit('MAKE_CLOSURE', args) + else: + self.emit('LOAD_CONST', gen) + self.emit('MAKE_FUNCTION', args) - def visitAssert(self, node): - # XXX would be interesting to implement this via a - # transformation of the AST before this stage + def visitGenExpr(self, node): + gen = GenExprCodeGenerator(node, self.scopes, self.class_name, + self.get_module()) + walk(node.code, gen) + gen.finish() + self.set_lineno(node) + self._makeClosure(gen, 0) + # precomputation of outmost iterable + self.visit(node.code.quals[0].iter) + self.emit('GET_ITER') + self.emit('CALL_FUNCTION', 1) + + def visitGenExprInner(self, node): + self.set_lineno(node) + # setup list + + stack = [] + for i, for_ in zip(range(len(node.quals)), node.quals): + start, anchor, end = self.visit(for_) + cont = None + for if_ in for_.ifs: + if cont is None: + cont = self.newBlock() + self.visit(if_, cont) + stack.insert(0, (start, cont, anchor, end)) + + self.visit(node.expr) + self.emit('YIELD_VALUE') + self.emit('POP_TOP') + + for start, cont, anchor, end in stack: + if cont: + skip_one = self.newBlock() + self.emit('JUMP_FORWARD', skip_one) + self.startBlock(cont) + self.emit('POP_TOP') + self.nextBlock(skip_one) + self.emit('JUMP_ABSOLUTE', start) + self.startBlock(anchor) + self.emit('POP_BLOCK') + self.setups.pop() + self.startBlock(end) + + self.emit('LOAD_CONST', None) + + def visitGenExprFor(self, node): + start = self.newBlock() + anchor = self.newBlock() end = self.newBlock() - self.set_lineno(node) - # XXX __debug__ and AssertionError appear to be special cases - # -- they are always loaded as globals even if there are local - # names. I guess this is a sort of renaming op. - self.emit('LOAD_GLOBAL', '__debug__') - self.emit('JUMP_IF_FALSE', end) + + self.setups.push((LOOP, start)) + self.emit('SETUP_LOOP', end) + + if node.is_outmost: + self.loadName('.0') + else: + self.visit(node.iter) + self.emit('GET_ITER') + + self.nextBlock(start) + self.set_lineno(node, force=True) + self.emit('FOR_ITER', anchor) self.nextBlock() - self.emit('POP_TOP') + self.visit(node.assign) + return start, anchor, end + + def visitGenExprIf(self, node, branch): + self.set_lineno(node, force=True) self.visit(node.test) - self.emit('JUMP_IF_TRUE', end) - self.nextBlock() + self.emit('JUMP_IF_FALSE', branch) + self.newBlock() self.emit('POP_TOP') - self.emit('LOAD_GLOBAL', 'AssertionError') - if node.fail: - self.visit(node.fail) - self.emit('RAISE_VARARGS', 2) - else: - self.emit('RAISE_VARARGS', 1) - self.nextBlock(end) - self.emit('POP_TOP') + # exception related + + def visitAssert(self, node): + # XXX would be interesting to implement this via a + # transformation of the AST before this stage + if __debug__: + end = self.newBlock() + self.set_lineno(node) + # XXX AssertionError appears to be special case -- it is always + # loaded as a global even if there is a local name. I guess this + # is a sort of renaming op. + self.nextBlock() + self.visit(node.test) + self.emit('JUMP_IF_TRUE', end) + self.nextBlock() + self.emit('POP_TOP') + self.emit('LOAD_GLOBAL', 'AssertionError') + if node.fail: + self.visit(node.fail) + self.emit('RAISE_VARARGS', 2) + else: + self.emit('RAISE_VARARGS', 1) + self.nextBlock(end) + self.emit('POP_TOP') + def visitRaise(self, node): self.set_lineno(node) n = 0 @@ -732,6 +819,45 @@ self.emit('END_FINALLY') self.setups.pop() + __with_count = 0 + + def visitWith(self, node): + body = self.newBlock() + final = self.newBlock() + exitvar = "$exit%d" % self.__with_count + valuevar = "$value%d" % self.__with_count + self.__with_count += 1 + self.set_lineno(node) + self.visit(node.expr) + self.emit('DUP_TOP') + self.emit('LOAD_ATTR', '__exit__') + self._implicitNameOp('STORE', exitvar) + self.emit('LOAD_ATTR', '__enter__') + self.emit('CALL_FUNCTION', 0) + if node.vars is None: + self.emit('POP_TOP') + else: + self._implicitNameOp('STORE', valuevar) + self.emit('SETUP_FINALLY', final) + self.nextBlock(body) + self.setups.push((TRY_FINALLY, body)) + if node.vars is not None: + self._implicitNameOp('LOAD', valuevar) + self._implicitNameOp('DELETE', valuevar) + self.visit(node.vars) + 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._implicitNameOp('LOAD', exitvar) + self._implicitNameOp('DELETE', exitvar) + self.emit('WITH_CLEANUP') + self.emit('END_FINALLY') + self.setups.pop() + self.__with_count -= 1 + # misc def visitDiscard(self, node): @@ -759,8 +885,10 @@ def visitImport(self, node): self.set_lineno(node) + level = 0 if self.graph.checkFlag(CO_FUTURE_ABSIMPORT) else -1 for name, alias in node.names: if VERSION > 1: + self.emit('LOAD_CONST', level) self.emit('LOAD_CONST', None) self.emit('IMPORT_NAME', name) mod = name.split(".")[0] @@ -772,8 +900,12 @@ def visitFrom(self, node): self.set_lineno(node) + level = node.level + if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT): + level = -1 fromlist = map(lambda (name, alias): name, node.names) if VERSION > 1: + self.emit('LOAD_CONST', level) self.emit('LOAD_CONST', tuple(fromlist)) self.emit('IMPORT_NAME', node.modname) for name, alias in node.names: @@ -909,8 +1041,6 @@ self.emit('STORE_SLICE+%d' % slice) def visitAugSubscript(self, node, mode): - if len(node.subs) > 1: - raise SyntaxError, "augmented assignment to tuple is not possible" if mode == "load": self.visitSubscript(node, 1) elif mode == "store": @@ -1015,10 +1145,10 @@ self.visit(node.expr) for sub in node.subs: self.visit(sub) + if len(node.subs) > 1: + self.emit('BUILD_TUPLE', len(node.subs)) if aug_flag: self.emit('DUP_TOPX', 2) - if len(node.subs) > 1: - self.emit('BUILD_TUPLE', len(node.subs)) if node.flags == 'OP_APPLY': self.emit('BINARY_SUBSCR') elif node.flags == 'OP_ASSIGN': @@ -1204,6 +1334,7 @@ klass.lambdaCount = klass.lambdaCount + 1 else: name = func.name + args, hasTupleArg = generateArgList(func.argnames) self.graph = pyassem.PyFlowGraph(name, func.filename, args, optimized=1) @@ -1235,7 +1366,7 @@ def generateArgUnpack(self, args): for i in range(len(args)): arg = args[i] - if type(arg) == types.TupleType: + if isinstance(arg, tuple): self.emit('LOAD_FAST', '.%d' % (i * 2)) self.unpackSequence(arg) @@ -1245,7 +1376,7 @@ else: self.emit('UNPACK_TUPLE', len(tup)) for elt in tup: - if type(elt) == types.TupleType: + if isinstance(elt, tuple): self.unpackSequence(elt) else: self._nameOp('STORE', elt) @@ -1268,6 +1399,21 @@ if self.scope.generator is not None: self.graph.setFlag(CO_GENERATOR) +class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode, + CodeGenerator): + super_init = CodeGenerator.__init__ # call be other init + scopes = None + + __super_init = AbstractFunctionCode.__init__ + + def __init__(self, gexp, scopes, class_name, mod): + self.scopes = scopes + self.scope = scopes[gexp] + 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()) + self.graph.setFlag(CO_GENERATOR) + class AbstractClassCode: def __init__(self, klass, scopes, module): @@ -1316,9 +1462,9 @@ count = 0 for i in range(len(arglist)): elt = arglist[i] - if type(elt) == types.StringType: + if isinstance(elt, str): args.append(elt) - elif type(elt) == types.TupleType: + elif isinstance(elt, tuple): args.append(TupleArg(i * 2, elt)) extra.extend(misc.flatten(elt)) count = count + 1 Modified: trunk/jython/Lib/compiler/transformer.py =================================================================== --- trunk/jython/Lib/compiler/transformer.py 2009-04-07 13:09:48 UTC (rev 6186) +++ trunk/jython/Lib/compiler/transformer.py 2009-04-08 01:14:13 UTC (rev 6187) @@ -14,7 +14,10 @@ # # Modifications and improvements for Python 2.0 by Jeremy Hylton and # Mark Hammond - +# +# Some fixes to try to have correct line number on almost all nodes +# (except Module, Discard and Stmt) added by Sylvain Thenault +# # Portions of this file are: # Copyright (C) 1997-1998 Greg Stein. All Rights Reserved. # @@ -22,22 +25,20 @@ # http://www.opensource.org/licenses/bsd-license.html # and replace OWNER, ORGANIZATION, and YEAR as appropriate. -from ast import * -#import parser -parser = None -# Care must be taken to use only symbols and tokens defined in Python -# 1.5.2 for code branches executed in 1.5.2 +from compiler.ast import * +import parser import symbol import token import sys -error = 'walker.error' +class WalkerError(StandardError): + pass -from consts import CO_VARARGS, CO_VARKEYWORDS -from consts import OP_ASSIGN, OP_DELETE, OP_APPLY +from compiler.consts import CO_VARARGS, CO_VARKEYWORDS +from compiler.consts import OP_ASSIGN, OP_DELETE, OP_APPLY def parseFile(path): - f = open(path) + f = open(path, "U") # XXX The parser API tolerates files without a trailing newline, # but not strings without a trailing newline. Always add an extra # newline to the file contents, since we're going through the string @@ -69,6 +70,16 @@ l.append(item) return l +def extractLineNo(ast): + if not isinstance(ast[1], tuple): + # get a terminal node + return ast[2] + for child in ast[1:]: + if isinstance(child, tuple): + lineno = extractLineNo(child) + if lineno is not None: + return lineno + def Node(*args): kind = args[0] if nodes.has_key(kind): @@ -78,7 +89,7 @@ print nodes[kind], len(args), args raise else: - raise error, "Can't find appropriate Node type: %s" % str(args) + raise WalkerError, "Can't find appropriate Node type: %s" % str(args) #return apply(ast.Node, args) class Transformer: @@ -109,15 +120,12 @@ def transform(self, tree): """Transform an AST into a modified parse tree.""" - if type(tree) != type(()) and type(tree) != type([]): + if not (isinstance(tree, tuple) or isinstance(tree, list)): tree = parser.ast2tuple(tree, line_info=1) return self.compile_node(tree) def parsesuite(self, text): """Return a modified parse tree for the given suite text.""" - # Hack for handling non-native line endings on non-DOS like OSs. - # this can go now we have universal newlines? - text = text.replace('\x0d', '') return self.transform(parser.suite(text)) def parseexpr(self, text): @@ -157,7 +165,7 @@ if n == symbol.classdef: return self.classdef(node[1:]) - raise error, ('unexpected node type', n) + raise WalkerError, ('unexpected node type', n) def single_input(self, node): ### do we want to do anything about being "interactive" ? @@ -186,31 +194,77 @@ ### is this sufficient? return Expression(self.com_node(nodelist[0])) + def decorator_name(self, nodelist): + listlen = len(nodelist) + assert listlen >= 1 and listlen % 2 == 1 + + item = self.atom_name(nodelist) + i = 1 + while i < listlen: + assert nodelist[i][0] == token.DOT + assert nodelist[i + 1][0] == token.NAME + item = Getattr(item, nodelist[i + 1][1]) + i += 2 + + return item + + def decorator(self, nodelist): + # '@' dotted_name [ '(' [arglist] ')' ] + assert len(nodelist) in (3, 5, 6) + assert nodelist[0][0] == token.AT + assert nodelist[-1][0] == token.NEWLINE + + assert nodelist[1][0] == symbol.dotted_name + funcname = self.decorator_name(nodelist[1][1:]) + + if len(nodelist) > 3: + assert nodelist[2][0] == token.LPAR + expr = self.com_call_function(funcname, nodelist[3]) + else: + expr = funcname + + return expr + + def decorators(self, nodelist): + # decorators: decorator ([NEWLINE] decorator)* NEWLINE + items = [] + for dec_nodelist in nodelist: + assert dec_nodelist[0] == symbol.decorator + items.append(self.decorator(dec_nodelist[1:])) + return Decorators(items) + def funcdef(self, nodelist): - # funcdef: 'def' NAME parameters ':' suite + # -6 -5 -4 -3 -2 -1 + # funcdef: [decorators] 'def' NAME parameters ':' suite # parameters: '(' [varargslist] ')' - lineno = nodelist[1][2] - name = nodelist[1][1] - args = nodelist[2][2] + if len(nodelist) == 6: + assert nodelist[0][0] == symbol.decorators + decorators = self.decorators(nodelist[0][1:]) + else: + assert len(nodelist) == 5 + decorators = None + lineno = nodelist[-4][2] + name = nodelist[-4][1] + args = nodelist[-3][2] + if args[0] == symbol.varargslist: names, defaults, flags = self.com_arglist(args[1:]) else: names = defaults = () flags = 0 - doc = self.get_docstring(nodelist[4]) + doc = self.get_docstring(nodelist[-1]) # code for function - code = self.com_node(nodelist[4]) + code = self.com_node(nodelist[-1]) if doc is not None: assert isinstance(code, Stmt) assert isinstance(code.nodes[0], Discard) del code.nodes[0] - n = Function(name, names, defaults, flags, doc, code) - n.lineno = lineno - return n + return Function(decorators, name, names, defaults, flags, doc, code, + lineno=lineno) def lambdef(self, nodelist): # lambdef: 'lambda' [varargslist] ':' test @@ -223,17 +277,18 @@ # code for lambda code = self.com_node(nodelist[-1]) - n = Lambda(names, defaults, flags, code) - n.lineno = nodelist[1][2] - return n + return Lambda(names, defaults, flags, code, lineno=nodelist[1][2]) + old_lambdef = lambdef def classdef(self, nodelist): - # classdef: 'class' NAME ['(' testlist ')'] ':' suite + # classdef: 'class' NAME ['(' [testlist] ')'] ':' suite name = nodelist[1][1] doc = self.get_docstring(nodelist[-1]) if nodelist[2][0] == token.COLON: bases = [] + elif nodelist[3][0] == token.RPAR: + bases = [] else: bases = self.com_bases(nodelist[3]) @@ -245,9 +300,7 @@ assert isinstance(code.nodes[0], Discard) del code.nodes[0] - n = Class(name, bases, doc, code) - n.lineno = nodelist[1][2] - return n + return Class(name, bases, doc, code, lineno=nodelist[1][2]) def stmt(self, nodelist): return self.com_stmt(nodelist[0]) @@ -264,31 +317,31 @@ return Stmt(stmts) def parameters(self, nodelist): - raise error + raise WalkerError def varargslist(self, nodelist): - raise error + raise WalkerError def fpdef(self, nodelist): - raise error + raise WalkerError def fplist(self, nodelist): - raise error + raise WalkerError def dotted_name(self, nodelist): - raise error + raise WalkerError def comp_op(self, nodelist): - raise error + raise WalkerError def trailer(self, nodelist): - raise error + raise WalkerError def sliceop(self, nodelist): - raise error + raise WalkerError def argument(self, nodelist): - raise error + raise WalkerError # -------------------------------------------------------------- # @@ -300,21 +353,17 @@ en = nodelist[-1] exprNode = self.lookup_node(en)(en[1:]) if len(nodelist) == 1: - n = Discard(exprNode) - n.lineno = exprNode.lineno - return n + return Discard(exprNode, lineno=exprNode.lineno) if nodelist[1][0] == token.EQUAL: nodesl = [] for i in range(0, len(nodelist) - 2, 2): nodesl.append(self.com_assign(nodelist[i], OP_ASSIGN)) - n = Assign(nodesl, exprNode) - n.lineno = nodelist[1][2] + return Assign(nodesl, exprNode, lineno=nodelist[1][2]) else: lval = self.com_augassign(nodelist[0]) op = self.com_augassign_op(nodelist[1]) - n = AugAssign(lval, op[1], exprNode) - n.lineno = op[2] - return n + return AugAssign(lval, op[1], exprNode, lineno=op[2]) + raise WalkerError, "can't get here" def print_stmt(self, nodelist): # print ([ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ]) @@ -333,46 +382,38 @@ for i in range(start, len(nodelist), 2): items.append(self.com_node(nodelist[i])) if nodelist[-1][0] == token.COMMA: - n = Print(items, dest) - n.lineno = nodelist[0][2] - return n - n = Printnl(items, dest) - n.lineno = nodelist[0][2] - return n + return Print(items, dest, lineno=nodelist[0][2]) + return Printnl(items, dest, lineno=nodelist[0][2]) def del_stmt(self, nodelist): return self.com_assign(nodelist[1], OP_DELETE) def pass_stmt(self, nodelist): - n = Pass() - n.lineno = nodelist[0][2] - return n + return Pass(lineno=nodelist[0][2]) def break_stmt(self, nodelist): - n = Break() - n.lineno = nodelist[0][2] - return n + return Break(lineno=nodelist[0][2]) def continue_stmt(self, nodelist): - n = Continue() - n.lineno = nodelist[0][2] - return n + return Continue(lineno=nodelist[0][2]) def return_stmt(self, nodelist): # return: [testlist] if len(nodelist) < 2: - n = Return(Const(None)) - n.lineno = nodelist[0][2] - return n - n = Return(self.com_node(nodelist[1])) - n.lineno = nodelist[0][2] - return n + return Return(Const(None), lineno=nodelist[0][2]) + return Return(self.com_node(nodelist[1]), lineno=nodelist[0][2]) def yield_stmt(self, nodelist): - n = Yield(self.com_node(nodelist[1])) - n.lineno = nodelist[0][2] - return n + expr = self.com_node(nodelist[0]) + return Discard(expr, lineno=expr.lineno) + def yield_expr(self, nodelist): + if len(nodelist) > 1: + value = self.com_node(nodelist[1]) + else: + value = Const(None) + return Yield(value, lineno=nodelist[0][2]) + def raise_stmt(self, nodelist): # raise: [test [',' test [',' test]]] if len(nodelist) > 5: @@ -387,44 +428,46 @@ expr1 = self.com_node(nodelist[1]) else: expr1 = None - n = Raise(expr1, expr2, expr3) - n.lineno = nodelist[0][2] - return n + return Raise(expr1, expr2, expr3, lineno=nodelist[0][2]) def import_stmt(self, nodelist): - # import_stmt: 'import' dotted_as_name (',' dotted_as_name)* | - # from: 'from' dotted_name 'import' - # ('*' | import_as_name (',' import_as_name)*) - if nodelist[0][1] == 'from': - names = [] - if nodelist[3][0] == token.NAME: - for i in range(3, len(nodelist), 2): - names.append((nodelist[i][1], None)) - else: - for i in range(3, len(nodelist), 2): - names.append(self.com_import_as_name(nodelist[i])) - n = From(self.com_dotted_name(nodelist[1]), names) - n.lineno = nodelist[0][2] - return n + # import_stmt: import_name | import_from + assert len(nodelist) == 1 + return self.com_node(nodelist[0]) - if nodelist[1][0] == symbol.dotted_name: - names = [(self.com_dotted_name(nodelist[1][1:]), None)] + def import_name(self, nodelist): + # import_name: 'import' dotted_as_names + return Import(self.com_dotted_as_names(nodelist[1]), + lineno=nodelist[0][2]) + + def import_from(self, nodelist): + # import_from: 'from' ('.'* dotted_name | '.') 'import' ('*' | + # '(' import_as_names ')' | import_as_names) + assert nodelist[0][1] == 'from' + idx = 1 + while nodelist[idx][1] == '.': + idx += 1 + level = idx - 1 + if nodelist[idx][0] == symbol.dotted_name: + fromname = self.com_dotted_name(nodelist[idx]) + idx += 1 else: - names = [] - for i in range(1, len(nodelist), 2): - names.append(self.com_dotted_as_name(nodelist[i])) - n = Import(names) - n.lineno = nodelist[0][2] - return n + fromname = "" + assert nodelist[idx][1] == 'import' + if nodelist[idx + 1][0] == token.STAR: + return From(fromname, [('*', None)], level, + lineno=nodelist[0][2]) + else: + node = nodelist[idx + 1 + (nodelist[idx + 1][0] == token.LPAR)] + return From(fromname, self.com_import_as_names(node), level, + lineno=nodelist[0][2]) def global_stmt(self, nodelist): # global: NAME (',' NAME)* names = [] for i in range(1, len(nodelist), 2): names.append(nodelist[i][1]) - n = Global(names) - n.lineno = nodelist[0][2] - return n + return Global(names, lineno=nodelist[0][2]) def exec_stmt(self, nodelist): # exec_stmt: 'exec' expr ['in' expr [',' expr]] @@ -438,9 +481,7 @@ else: expr2 = expr3 = None - n = Exec(expr1, expr2, expr3) - n.lineno = nodelist[0][2] - return n + return Exec(expr1, expr2, expr3, lineno=nodelist[0][2]) def assert_stmt(self, nodelist): # 'assert': test, [',' test] @@ -449,9 +490,7 @@ expr2 = self.com_node(nodelist[3]) else: expr2 = None - n = Assert(expr1, expr2) - n.lineno = nodelist[0][2] - return n + return Assert(expr1, expr2, lineno=nodelist[0][2]) def if_stmt(self, nodelist): # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite] @@ -466,9 +505,7 @@ ## elseNode.lineno = nodelist[-1][1][2] else: elseNode = None - n = If(tests, elseNode) - n.lineno = nodelist[0][2] - return n + return If(tests, elseNode, lineno=nodelist[0][2]) def while_stmt(self, nodelist): # 'while' test ':' suite ['else' ':' suite] @@ -481,9 +518,7 @@ else: elseNode = None - n = While(testNode, bodyNode, elseNode) - n.lineno = nodelist[0][2] - return n + return While(testNode, bodyNode, elseNode, lineno=nodelist[0][2]) def for_stmt(self, nodelist): # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] @@ -497,18 +532,18 @@ else: elseNode = None - n = For(assignNode, listNode, bodyNode, elseNode) - n.lineno = nodelist[0][2] - return n + return For(assignNode, listNode, bodyNode, elseNode, + lineno=nodelist[0][2]) def try_stmt(self, nodelist): - # 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] - # | 'try' ':' suite 'finally' ':' suite - if nodelist[3][0] != symbol.except_clause: - return self.com_try_finally(nodelist) + return self.com_try_except_finally(nodelist) - return self.com_try_except(nodelist) + def with_stmt(self, nodelist): + return self.com_with(nodelist) + def with_var(self, nodelist): + return self.com_with_var(nodelist) + def suite(self, nodelist): # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT if len(nodelist) == 1: @@ -535,11 +570,32 @@ testlist1 = testlist exprlist = testlist + def testlist_gexp(self, nodelist): + if len(nodelist) == 2 and nodelist[1][0] == symbol.gen_for: + test = self.com_node(nodelist[0]) + return self.com_generator_expression(test, nodelist[1]) + return self.testlist(nodelist) + def test(self, nodelist): + # or_test ['if' or_test 'else' test] | lambdef + if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef: + return self.lambdef(nodelist[0]) + then = self.com_node(nodelist[0]) + if len(nodelist) > 1: + assert len(nodelist) == 5 + assert nodelist[1][1] == 'if' + assert nodelist[3][1] == 'else' + test = self.com_node(nodelist[2]) + else_ = self.com_node(nodelist[4]) + return IfExp(test, then, else_, lineno=nodelist[1][2]) + return then + + def or_test(self, nodelist): # and_test ('or' and_test)* | lambdef if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef: return self.lambdef(nodelist[0]) return self.com_binary(Or, nodelist) + old_test = or_test def and_test(self, nodelist): # not_test ('and' not_test)* @@ -549,9 +605,7 @@ # 'not' not_test | comparison result = self.com_node(nodelist[-1]) if len(nodelist) == 2: - n = Not(result) - n.lineno = nodelist[0][2] - return n + return Not(result, lineno=nodelist[0][2]) return result def comparison(self, nodelist): @@ -585,9 +639,7 @@ # the two have very different semantics and results (note that the # latter form is always true) - n = Compare(node, results) - n.lineno = lineno - return n + return Compare(node, results, lineno=lineno) def expr(self, nodelist): # xor_expr ('|' xor_expr)* @@ -607,11 +659,9 @@ for i in range(2, len(nodelist), 2): right = self.com_node(nodelist[i]) if nodelist[i-1][0] == token.LEFTSHIFT: - node = LeftShift([node, right]) - node.lineno = nodelist[1][2] + node = LeftShift([node, right], lineno=nodelist[1][2]) elif nodelist[i-1][0] == token.RIGHTSHIFT: - node = RightShift([node, right]) - node.lineno = nodelist[1][2] + node = RightShift([node, right], lineno=nodelist[1][2]) else: raise ValueError, "unexpected token: %s" % nodelist[i-1][0] return node @@ -621,11 +671,9 @@ for i in range(2, len(nodelist), 2): right = self.com_node(nodelist[i]) if nodelist[i-1][0] == token.PLUS: - node = Add([node, right]) - node.lineno = nodelist[1][2] + node = Add([node, right], lineno=nodelist[1][2]) elif nodelist[i-1][0] == token.MINUS: - node = Sub([node, right]) - node.lineno = nodelist[1][2] + node = Sub([node, right], lineno=nodelist[1][2]) else: raise ValueError, "unexpected token: %s" % nodelist[i-1][0] return node @@ -651,17 +699,14 @@ def factor(self, nodelist): elt = nodelist[0] t = elt[0] - node = self.com_node(nodelist[-1]) + node = self.lookup_node(nodelist[-1])(nodelist[-1][1:]) # need to handle (unary op)constant here... if t == token.PLUS: - node = UnaryAdd(node) - node.lineno = elt[2] + return UnaryAdd(node, lineno=elt[2]) elif t == token.MINUS: - node = UnarySub(node) - node.lineno = elt[2] + return UnarySub(node, lineno=elt[2]) elif t == token.TILDE: - node = Invert(node) - node.lineno = elt[2] + node = Invert(node, lineno=elt[2]) return node def power(self, nodelist): @@ -670,49 +715,38 @@ for i in range(1, len(nodelist)): elt = nodelist[i] if elt[0] == token.DOUBLESTAR: - n = Power([node, self.com_node(nodelist[i+1])]) - n.lineno = elt[2] - return n + return Power([node, self.com_node(nodelist[i+1])], + lineno=elt[2]) node = self.com_apply_trailer(node, elt) return node def atom(self, nodelist): - n = self._atom_dispatch[nodelist[0][0]](nodelist) - n.lineno = nodelist[0][2] - return n + return self._atom_dispatch[nodelist[0][0]](nodelist) def atom_lpar(self, nodelist): if nodelist[1][0] == token.RPAR: - n = Tuple(()) - n.lineno = nodelist[0][2] - return n + return Tuple((), lineno=nodelist[0][2]) return self.com_node(nodelist[1]) def atom_lsqb(self, nodelist): if nodelist[1][0] == token.RSQB: - n = List(()) - n.lineno = nodelist[0][2] - return n + return List((), lineno=nodelist[0][2]) return self.com_list_constructor(nodelist[1]) def atom_lbrace(self, nodelist): if nodelist[1][0] == token.RBRACE: - return Dict(()) + return Dict((), lineno=nodelist[0][2]) return self.com_dictmaker(nodelist[1]) def atom_backquote(self, nodelist): - n = Backquote(self.com_node(nodelist[1])) - n.lineno = nodelist[0][2] - return n + return Backquote(self.com_node(nodelist[1])) def atom_number(self, nodelist): ### need to verify this matches compile.c k = eval(nodelist[0][1]) - n = Const(k) - n.lineno = nodelist[0][2] - return n + return Const(k, lineno=nodelist[0][2]) def decode_literal(self, lit): if self.encoding: @@ -729,15 +763,10 @@ k = '' for node in nodelist: k += self.decode_literal(node[1]) - n = Const(k) - n.lineno = nodelist[0][2] - return n + return Const(k, lineno=nodelist[0][2]) def atom_name(self, nodelist): - ### any processing to do? - n = Name(nodelist[0][1]) - n.lineno = nodelist[0][2] - return n + return Name(nodelist[0][1], lineno=nodelist[0][2]) # -------------------------------------------------------------- # @@ -805,16 +834,15 @@ names.append(self.com_fpdef(node)) i = i + 1 - if i >= len(nodelist): - break - - if nodelist[i][0] == token.EQUAL: + if i < len(nodelist) and nodelist[i][0] == token.EQUAL: defaults.append(self.com_node(nodelist[i + 1])) i = i + 2 elif len(defaults): - # Treat "(a=1, b)" as "(a=1, b=None)" - defaults.append(Const(None)) + # we have already seen an argument with default, but here + # came one without + raise SyntaxError, "non-default argument follows default argument" + # skip the comma i = i + 1 return names, defaults, flags @@ -843,48 +871,62 @@ return name[:-1] def com_dotted_as_name(self, node): - dot = self.com_dotted_name(node[1]) - if len(node) <= 2: + assert node[0] == symbol.dotted_as_name + node = node[1:] + dot = self.com_dotted_name(node[0][1:]) + if len(node) == 1: return dot, None - if node[0] == symbol.dotted_name: - pass - else: - assert node[2][1] == 'as' - assert node[3][0] == token.NAME - return dot, node[3][1] + assert node[1][1] == 'as' + assert node[2][0] == token.NAME + return dot, node[2][1] + def com_dotted_as_names(self, node): + assert node[0] == symbol.dotted_as_names + node = node[1:] + names = [self.com_dotted_as_name(node[0])] + for i in range(2, len(node), 2): + names.append(self.com_dotted_as_name(node[i])) + return names + def com_import_as_name(self, node): - if node[0] == token.STAR: - return '*', None assert node[0] == symbol.import_as_name node = node[1:] + assert node[0][0] == token.NAME if len(node) == 1: - assert node[0][0] == token.NAME return node[0][1], None - assert node[1][1] == 'as', node assert node[2][0] == token.NAME return node[0][1], node[2][1] + def com_import_as_names(self, node): + assert node[0] == symbol.import_as_names + node = node[1:] + names = [self.com_import_as_name(node[0])] + for i in range(2, len(node), 2): + names.append(self.com_import_as_name(node[i])) + return names + def com_bases(self, node): bases = [] for i in range(1, len(node), 2): bases.append(self.com_node(node[i])) return bases - def com_try_finally(self, nodelist): - # try_fin_stmt: "try" ":" suite "finally" ":" suite - n = TryFinally(self.com_node(nodelist[2]), - self.com_node(nodelist[5])) - n.lineno = nodelist[0][2] - return n + def com_try_except_finally(self, nodelist): + # ('try' ':' suite + # ((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite] + # | 'finally' ':' suite)) - def com_try_except(self, nodelist): - # try_except: 'try' ':' suite (except_clause ':' suite)* ['else' suite] + if nodelist[3][0] == token.NAME: + # first clause is a finally clause: only try-finally + return TryFinally(self.com_node(nodelist[2]), + self.com_node(nodelist[5]), + lineno=nodelist[0][2]) + #tryexcept: [TryNode, [except_clauses], elseNode)] - stmt = self.com_node(nodelist[2]) clauses = [] elseNode = None + finallyNode = None for i in range(3, len(nodelist), 3): node = nodelist[i] if node[0] == symbol.except_clause: @@ -900,11 +942,31 @@ clauses.append((expr1, expr2, self.com_node(nodelist[i+2]))) if node[0] == token.NAME: - elseNode = self.com_node(nodelist[i+2]) - n = TryExcept(self.com_node(nodelist[2]), clauses, elseNode) - n.lineno = nodelist[0][2] - return n + if node[1] == 'else': + elseNode = self.com_node(nodelist[i+2]) + elif node[1] == 'finally': + finallyNode = self.com_node(nodelist[i+2]) + try_except = TryExcept(self.com_node(nodelist[2]), clauses, elseNode, + lineno=nodelist[0][2]) + if finallyNode: + return TryFinally(try_except, finallyNode, lineno=nodelist[0][2]) + else: + return try_except + def com_with(self, nodelist): + # with_stmt: 'with' expr [with_var] ':' suite + expr = self.com_node(nodelist[1]) + body = self.com_node(nodelist[-1]) + if nodelist[2][0] == token.COLON: + var = None + else: + var = self.com_assign(nodelist[2][2], OP_ASSIGN) + return With(expr, var, body, lineno=nodelist[0][2]) + + def com_with_var(self, nodelist): + # with_var: 'as' expr + return self.com_node(nodelist[1]) + def com_augassign_op(self, node): assert node[0] == symbol.augassign return node[1] @@ -924,7 +986,7 @@ # loop to avoid trivial recursion while 1: t = node[0] - if t == symbol.exprlist or t == symbol.testlist: + if t in (symbol.exprlist, symbol.testlist, symbol.testlist_safe, symbol.testlist_gexp): if len(node) > 2: return self.com_assign_tuple(node, assigning) node = node[1] @@ -961,13 +1023,13 @@ else: raise SyntaxError, "can't assign to literal" else: - raise SyntaxError, "bad assignment" + raise SyntaxError, "bad assignment (%s)" % t def com_assign_tuple(self, node, assigning): assigns = [] for i in range(1, len(node), 2): assigns.append(self.com_assign(node[i], assigning)) - return AssTuple(assigns) + return AssTuple(assigns, lineno=extractLineNo(node)) def com_assign_list(self, node, assigning): assigns = [] @@ -977,12 +1039,10 @@ raise SyntaxError, "can't assign to list comprehension" assert node[i + 1][0] == token.COMMA, node[i + 1] assigns.append(self.com_assign(node[i], assigning)) - return AssList(assigns) + return AssList(assigns, lineno=extractLineNo(node)) def com_assign_name(self, node, assigning): - n = AssName(node[1], assigning) - n.lineno = node[2] - return n + return AssName(node[1], assigning, lineno=node[2]) def com_assign_trailer(self, primary, node, assigning): t = node[1][0] @@ -995,7 +1055,7 @@ raise SyntaxError, "unknown trailer type: %s" % t def com_assign_attr(self, primary, node, assigning): - return AssAttr(primary, node[1], assigning) + return AssAttr(primary, node[1], assigning, lineno=node[-1]) def com_binary(self, constructor, nodelist): "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])." @@ -1007,7 +1067,7 @@ for i in range(0, l, 2): n = nodelist[i] items.append(self.lookup_node(n)(n[1:])) - return constructor(items) + return constructor(items, lineno=extractLineNo(nodelist)) def com_stmt(self, node): result = self.lookup_node(node)(node[1:]) @@ -1017,7 +1077,7 @@ return Stmt([result]) def com_append_stmt(self, stmts, node): - result = self.com_node(node) + result = self.lookup_node(node)(node[1:]) assert result is not None if isinstance(result, Stmt): stmts.extend(result.nodes) @@ -1036,7 +1096,7 @@ elif nodelist[i][0] == token.COMMA: continue values.append(self.com_node(nodelist[i])) - return List(values) + return List(values, lineno=values[0].lineno) def com_list_comprehension(self, expr, node): # list_iter: list_for | list_if @@ -1061,8 +1121,7 @@ node = self.com_list_iter(node[5]) elif t == 'if': test = self.com_node(node[2]) - newif = ListCompIf(test) - newif.lineno = node[1][2] + newif = ListCompIf(test, lineno=node[1][2]) newfor.ifs.append(newif) if len(node) == 3: node = None @@ -1072,9 +1131,7 @@ raise SyntaxError, \ ("unexpected list comprehension element: %s %d" % (node, lineno)) - n = ListComp(expr, fors) - n.lineno = lineno - return n + return ListComp(expr, fors, lineno=lineno) def com_list_iter(self, node): assert node[0] == symbol.list_iter @@ -1084,15 +1141,54 @@ values = [] for i in range(1, len(nodelist), 2): values.append(self.com_node(nodelist[i])) - return List(values) + return List(values, lineno=values[0].lineno) + if hasattr(symbol, 'gen_for'): + def com_generator_expression(self, expr, node): + # gen_iter: gen_for | gen_if + # gen_for: 'for' exprlist 'in' test [gen_iter] + # gen_if: 'if' test [gen_iter] + + lineno = node[1][2] + fors = [] + while node: + t = node[1][1] + if t == 'for': + assignNode = self.com_assign(node[2], OP_ASSIGN) + genNode = self.com_node(node[4]) + newfor = GenExprFor(assignNode, genNode, [], + lineno=node[1][2]) + fors.append(newfor) + if (len(node)) == 5: + node = None + else: + node = self.com_gen_iter(node[5]) + elif t == 'if': + test = self.com_node(node[2]) + newif = GenExprIf(test, lineno=node[1][2]) + newfor.ifs.append(newif) + if len(node) == 3: + node = None + else: + node = self.com_gen_iter(node[3]) + else: + raise SyntaxError, \ + ("unexpected generator expression element: %s %d" + % (node, lineno)) + fors[0].is_outmost = True + return GenExpr(GenExprInner(expr, fors), lineno=lineno) + + def com_gen_iter(self, node): + assert node[0] == symbol.gen_iter + return node[1] + def com_dictmaker(self, nodelist): # dictmaker: test ':' test (',' test ':' value)* [','] items = [] for i in range(1, len(nodelist), 4): items.append((self.com_node(nodelist[i]), self.com_node(nodelist[i+2]))) - return Dict(items) + return Dict(items, lineno=items[0][0].lineno) def com_apply_trailer(self, primaryNode, nodelist): t = nodelist[1][0] @@ -1108,13 +1204,11 @@ def com_select_member(self, primaryNode, nodelist): if nodelist[0] != token.NAME: raise SyntaxError, "member must be a name" - n = Getattr(primaryNode, nodelist[1]) - n.lineno = nodelist[2] - return n + return Getattr(primaryNode, nodelist[1], lineno=nodelist[2]) def com_call_function(self, primaryNode, nodelist): if nodelist[0] == token.RPAR: - return CallFunc(primaryNode, []) + return CallFunc(primaryNode, [], lineno=extractLineNo(nodelist)) args = [] kw = 0 len_nodelist = len(nodelist) @@ -1123,6 +1217,13 @@ if node[0] == token.STAR or node[0] == token.DOUBLESTAR: break kw, result = self.com_argument(node, kw) + + if len_nodelist != 2 and isinstance(result, GenExpr) \ + and len(node) == 3 and node[2][0] == symbol.gen_for: + # allow f(x for x in y), but reject f(x for x in y, 1) + # should use f((x for x in y), 1) instead of f(x for x in y, 1) + raise SyntaxError, 'generator expression needs parenthesis' + args.append(result) else: # No broken by star arg, so skip the last one we processed. @@ -1145,10 +1246,13 @@ dstar_node = self.com_node(ch) else: raise SyntaxError, 'unknown node type: %s' % tok + return CallFunc(primaryNode, args, star_node, dstar_node, + lineno=extractLineNo(nodelist)) - return CallFunc(primaryNode, args, star_node, dstar_node) - def com_argument(self, nodelist, kw): + if len(nodelist) == 3 and nodelist[2][0] == symbol.gen_for: + test = self.com_node(nodelist[1]) + return 0, self.com_generator_expression(test, nodelist[2]) if len(nodelist) == 2: if kw: raise SyntaxError, "non-keyword arg after keyword arg" @@ -1159,8 +1263,7 @@ n = n[1] if n[0] != token.NAME: raise SyntaxError, "keyword can't be an expression (%s)"%n[0] - node = Keyword(n[1], result) - node.lineno = n[2] + node = Keyword(n[1], result, lineno=n[2]) return 1, node def com_subscriptlist(self, primary, nodelist, assigning): @@ -1180,9 +1283,9 @@ subscripts = [] for i in range(1, len(nodelist), 2): subscripts.append(self.com_subscript(nodelist[i])) + return Subscript(primary, assigning, subscripts, + lineno=extractLineNo(nodelist)) - return Subscript(primary, assigning, subscripts) - def com_subscript(self, node): # slice_item: expression | proper_slice | ellipsis ch = node[1] @@ -1227,9 +1330,8 @@ items.append(Const(None)) else: items.append(self.com_node(ch[2])) + return Sliceobj(items, lineno=extractLineNo(node)) - return Sliceobj(items) - def com_slice(self, primary, node, assigning): # short_slice: [lower_bound] ":" [upper_bound] lower = upper = None @@ -1241,7 +1343,8 @@ elif len(node) == 4: lower = self.com_node(node[1]) upper = self.com_node(node[3]) - return Slice(primary, assigning, lower, upper) + return Slice(primary, assigning, lower, upper, + lineno=extractLineNo(node)) def get_docstring(self, node, n=None): if n is None: @@ -1279,6 +1382,7 @@ symbol.testlist, symbol.testlist_safe, symbol.test, + symbol.or_test, symbol.and_test, symbol.not_test, symbol.comparison, @@ -1328,6 +1432,7 @@ symbol.while_stmt, symbol.for_stmt, symbol.try_stmt, + symbol.with_stmt, symbol.suite, symbol.testlist, symbol.testlist_safe, @@ -1349,9 +1454,12 @@ if hasattr(symbol, 'yield_stmt'): _legal_node_types.append(symbol.yield_stmt) +if hasattr(symbol, 'yield_expr'): + _legal_node_types.append(symbol.yield_expr) _assign_types = [ symbol.test, + symbol.or_test, symbol.and_test, symbol.not_test, symbol.comparison, @@ -1364,7 +1472,6 @@ symbol.factor, ] -import types _names = {} for k, v in symbol.sym_name.items(): _names[k] = v @@ -1374,9 +1481,9 @@ def debug_tree(tree): l = [] for elt in tree: - if type(elt) == types.IntType: + if isinstance(elt, int): l.append(_names.get(elt, elt)) - elif type(elt) == types.StringType: + elif isinstance(elt, str): l.append(elt) else: l.append(debug_tree(elt)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |