GIF89a; EcchiShell v1.0
//lib64/lib64/lib64/lib64/python2.7/compiler/

AST parseFile(path) -> AST """ # Original version written by Greg Stein (gstein@lyra.org) # and Bill Tutt (rassilon@lima.mudlib.org) # February 1997. # # 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. # # This module is provided under a BSD-ish license. See # http://www.opensource.org/licenses/bsd-license.html # and replace OWNER, ORGANIZATION, and YEAR as appropriate. from compiler.ast import * import parser import symbol import token class WalkerError(StandardError): pass from compiler.consts import CO_VARARGS, CO_VARKEYWORDS from compiler.consts import OP_ASSIGN, OP_DELETE, OP_APPLY def parseFile(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 # version of the API. src = f.read() + "\n" f.close() return parse(src) def parse(buf, mode="exec"): if mode == "exec" or mode == "single": return Transformer().parsesuite(buf) elif mode == "eval": return Transformer().parseexpr(buf) else: raise ValueError("compile() arg 3 must be" " 'exec' or 'eval' or 'single'") def asList(nodes): l = [] for item in nodes: if hasattr(item, "asList"): l.append(item.asList()) else: if type(item) is type( (None, None) ): l.append(tuple(asList(item))) elif type(item) is type( [] ): l.append(asList(item)) else: 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 kind in nodes: try: return nodes[kind](*args[1:]) except TypeError: print nodes[kind], len(args), args raise else: raise WalkerError, "Can't find appropriate Node type: %s" % str(args) #return apply(ast.Node, args) class Transformer: """Utility object for transforming Python parse trees. Exposes the following methods: tree = transform(ast_tree) tree = parsesuite(text) tree = parseexpr(text) tree = parsefile(fileob | filename) """ def __init__(self): self._dispatch = {} for value, name in symbol.sym_name.items(): if hasattr(self, name): self._dispatch[value] = getattr(self, name) self._dispatch[token.NEWLINE] = self.com_NEWLINE self._atom_dispatch = {token.LPAR: self.atom_lpar, token.LSQB: self.atom_lsqb, token.LBRACE: self.atom_lbrace, token.BACKQUOTE: self.atom_backquote, token.NUMBER: self.atom_number, token.STRING: self.atom_string, token.NAME: self.atom_name, } self.encoding = None def transform(self, tree): """Transform an AST into a modified parse tree.""" if not (isinstance(tree, tuple) or isinstance(tree, list)): tree = parser.st2tuple(tree, line_info=1) return self.compile_node(tree) def parsesuite(self, text): """Return a modified parse tree for the given suite text.""" return self.transform(parser.suite(text)) def parseexpr(self, text): """Return a modified parse tree for the given expression text.""" return self.transform(parser.expr(text)) def parsefile(self, file): """Return a modified parse tree for the contents of the given file.""" if type(file) == type(''): file = open(file) return self.parsesuite(file.read()) # -------------------------------------------------------------- # # PRIVATE METHODS # def compile_node(self, node): ### emit a line-number node? n = node[0] if n == symbol.encoding_decl: self.encoding = node[2] node = node[1] n = node[0] if n == symbol.single_input: return self.single_input(node[1:]) if n == symbol.file_input: return self.file_input(node[1:]) if n == symbol.eval_input: return self.eval_input(node[1:]) if n == symbol.lambdef: return self.lambdef(node[1:]) if n == symbol.funcdef: return self.funcdef(node[1:]) if n == symbol.classdef: return self.classdef(node[1:]) 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() 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:]: if node[0] != token.ENDMARKER and node[0] != token.NEWLINE: self.com_append_stmt(stmts, node) return Module(doc, Stmt(stmts)) def eval_input(self, nodelist): # from the built-in function input() ### 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 decorated(self, nodelist): assert nodelist[0][0] == symbol.decorators if nodelist[1][0] == symbol.funcdef: n = [nodelist[0]] + list(nodelist[1][1:]) return self.funcdef(n) elif nodelist[1][0] == symbol.classdef: decorators = self.decorators(nodelist[0][1:]) cls = self.classdef(nodelist[1][1:]) cls.decorators = decorators return cls raise WalkerError() def funcdef(self, nodelist): # -6 -5 -4 -3 -2 -1 # funcdef: [decorators] 'def' NAME parameters ':' suite # parameters: '(' [varargslist] ')' 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[-1]) # code for function 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] return Function(decorators, name, names, defaults, flags, doc, code, lineno=lineno) def lambdef(self, nodelist): # lambdef: 'lambda' [varargslist] ':' test if nodelist[2][0] == symbol.varargslist: names, defaults, flags = self.com_arglist(nodelist[2][1:]) else: names = defaults = () flags = 0 # code for lambda code = self.com_node(nodelist[-1]) return Lambda(names, defaults, flags, code, lineno=nodelist[1][2]) old_lambdef = lambdef def classdef(self, nodelist): # 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]) # code for class 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] return Class(name, bases, doc, code, lineno=nodelist[1][2]) def stmt(self, nodelist): return self.com_stmt(nodelist[0]) small_stmt = stmt flow_stmt = stmt compound_stmt = stmt def simple_stmt(self, nodelist): # small_stmt (';' small_stmt)* [';'] NEWLINE stmts = [] for i in range(0, len(nodelist), 2): self.com_append_stmt(stmts, nodelist[i]) return Stmt(stmts) def parameters(self, nodelist): raise WalkerError def varargslist(self, nodelist): raise WalkerError def fpdef(self, nodelist): raise WalkerError def fplist(self, nodelist): raise WalkerError def dotted_name(self, nodelist): raise WalkerError def comp_op(self, nodelist): raise WalkerError def trailer(self, nodelist): raise WalkerError def sliceop(self, nodelist): raise WalkerError def argument(self, nodelist): raise WalkerError # -------------------------------------------------------------- # # STATEMENT NODES (invoked by com_node()) # def expr_stmt(self, nodelist): # augassign testlist | testlist ('=' testlist)* en = nodelist[-1] exprNode = self.lookup_node(en)(en[1:]) if len(nodelist) == 1: 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)) return Assign(nodesl, exprNode, lineno=nodelist[1][2]) else: lval = self.com_augassign(nodelist[0]) op = self.com_augassign_op(nodelist[1]) 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)+ [','] ]) items = [] if len(nodelist) == 1: start = 1 dest = None elif nodelist[1][0] == token.RIGHTSHIFT: assert len(nodelist) == 3 \ or nodelist[3][0] == token.COMMA dest = self.com_node(nodelist[2]) start = 4 else: dest = None start = 1 for i in range(start, len(nodelist), 2): items.append(self.com_node(nodelist[i])) if nodelist[-1][0] == token.COMMA: 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): return Pass(lineno=nodelist[0][2]) def break_stmt(self, nodelist): return Break(lineno=nodelist[0][2]) def continue_stmt(self, nodelist): return Continue(lineno=nodelist[0][2]) def return_stmt(self, nodelist): # return: [testlist] if len(nodelist) < 2: return Return(Const(None), lineno=nodelist[0][2]) return Return(self.com_node(nodelist[1]), lineno=nodelist[0][2]) def yield_stmt(self, nodelist): 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: expr3 = self.com_node(nodelist[5]) else: expr3 = None if len(nodelist) > 3: expr2 = self.com_node(nodelist[3]) else: expr2 = None if len(nodelist) > 1: expr1 = self.com_node(nodelist[1]) else: expr1 = None return Raise(expr1, expr2, expr3, lineno=nodelist[0][2]) def import_stmt(self, nodelist): # import_stmt: import_name | import_from assert len(nodelist) == 1 return self.com_node(nodelist[0]) 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: 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]) return Global(names, lineno=nodelist[0][2]) def exec_stmt(self, nodelist): # exec_stmt: 'exec' expr ['in' expr [',' expr]] expr1 = self.com_node(nodelist[1]) if len(nodelist) >= 4: expr2 = self.com_node(nodelist[3]) if len(nodelist) >= 6: expr3 = self.com_node(nodelist[5]) else: expr3 = None else: expr2 = expr3 = None return Exec(expr1, expr2, expr3, lineno=nodelist[0][2]) def assert_stmt(self, nodelist): # 'assert': test, [',' test] expr1 = self.com_node(nodelist[1]) if (len(nodelist) == 4): expr2 = self.com_node(nodelist[3]) else: expr2 = None return Assert(expr1, expr2, lineno=nodelist[0][2]) def if_stmt(self, nodelist): # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite] tests = [] for i in range(0, len(nodelist) - 3, 4): testNode = self.com_node(nodelist[i + 1]) suiteNode = self.com_node(nodelist[i + 3]) tests.append((testNode, suiteNode)) if len(nodelist) % 4 == 3: elseNode = self.com_node(nodelist[-1]) ## elseNode.lineno = nodelist[-1][1][2] else: elseNode = None return If(tests, elseNode, lineno=nodelist[0][2]) def while_stmt(self, nodelist): # 'while' test ':' suite ['else' ':' suite] testNode = self.com_node(nodelist[1]) bodyNode = self.com_node(nodelist[3]) if len(nodelist) > 4: elseNode = self.com_node(nodelist[6]) else: elseNode = None return While(testNode, bodyNode, elseNode, lineno=nodelist[0][2]) def for_stmt(self, nodelist): # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] assignNode = self.com_assign(nodelist[1], OP_ASSIGN) listNode = self.com_node(nodelist[3]) bodyNode = self.com_node(nodelist[5]) if len(nodelist) > 8: elseNode = self.com_node(nodelist[8]) else: elseNode = None return For(assignNode, listNode, bodyNode, elseNode, lineno=nodelist[0][2]) def try_stmt(self, nodelist): return self.com_try_except_finally(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: return self.com_stmt(nodelist[0]) stmts = [] for node in nodelist: if node[0] == symbol.stmt: self.com_append_stmt(stmts, node) return Stmt(stmts) # -------------------------------------------------------------- # # EXPRESSION NODES (invoked by com_node()) # def testlist(self, nodelist): # testlist: expr (',' expr)* [','] # testlist_safe: test [(',' test)+ [',']] # exprlist: expr (',' expr)* [','] return self.com_binary(Tuple, nodelist) testlist_safe = testlist # XXX testlist1 = testlist exprlist = testlist def testlist_comp(self, nodelist): # test ( comp_for | (',' test)* [','] ) assert nodelist[0][0] == symbol.test if len(nodelist) == 2 and nodelist[1][0] == symbol.comp_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)* return self.com_binary(And, nodelist) def not_test(self, nodelist): # 'not' not_test | comparison result = self.com_node(nodelist[-1]) if len(nodelist) == 2: return Not(result, lineno=nodelist[0][2]) return result def comparison(self, nodelist): # comparison: expr (comp_op expr)* node = self.com_node(nodelist[0]) if len(nodelist) == 1: return node results = [] for i in range(2, len(nodelist), 2): nl = nodelist[i-1] # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '==' # | 'in' | 'not' 'in' | 'is' | 'is' 'not' n = nl[1] if n[0] == token.NAME: type = n[1] if len(nl) == 3: if type == 'not': type = 'not in' else: type = 'is not' else: type = _cmp_types[n[0]] lineno = nl[1][2] results.append((type, self.com_node(nodelist[i]))) # we need a special "compare" node so that we can distinguish # 3 < x < 5 from (3 < x) < 5 # the two have very different semantics and results (note that the # latter form is always true) return Compare(node, results, lineno=lineno) def expr(self, nodelist): # xor_expr ('|' xor_expr)* return self.com_binary(Bitor, nodelist) def xor_expr(self, nodelist): # xor_expr ('^' xor_expr)* return self.com_binary(Bitxor, nodelist) def and_expr(self, nodelist): # xor_expr ('&' xor_expr)* return self.com_binary(Bitand, nodelist) def shift_expr(self, nodelist): # shift_expr ('<<'|'>>' shift_expr)* node = self.com_node(nodelist[0]) 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], lineno=nodelist[1][2]) elif nodelist[i-1][0] == token.RIGHTSHIFT: node = RightShift([node, right], lineno=nodelist[1][2]) else: raise ValueError, "unexpected token: %s" % nodelist[i-1][0] return node def arith_expr(self, nodelist): node = self.com_node(nodelist[0]) 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], lineno=nodelist[1][2]) elif nodelist[i-1][0] == token.MINUS: node = Sub([node, right], lineno=nodelist[1][2]) else: raise ValueError, "unexpected token: %s" % nodelist[i-1][0] return node def term(self, nodelist): node = self.com_node(nodelist[0]) for i in range(2, len(nodelist), 2): right = self.com_node(nodelist[i]) t = nodelist[i-1][0] if t == token.STAR: node = Mul([node, right]) elif t == token.SLASH: node = Div([node, right]) elif t == token.PERCENT: node = Mod([node, right]) elif t == token.DOUBLESLASH: node = FloorDiv([node, right]) else: raise ValueError, "unexpected token: %s" % t node.lineno = nodelist[1][2] return node def factor(self, nodelist): elt = nodelist[0] t = elt[0] node = self.lookup_node(nodelist[-1])(nodelist[-1][1:]) # need to handle (unary op)constant here... if t == token.PLUS: return UnaryAdd(node, lineno=elt[2]) elif t == token.MINUS: return UnarySub(node, lineno=elt[2]) elif t == token.TILDE: node = Invert(node, lineno=elt[2]) return node def power(self, nodelist): # power: atom trailer* ('**' factor)* node = self.com_node(nodelist[0]) for i in range(1, len(nodelist)): elt = nodelist[i] if elt[0] == token.DOUBLESTAR: 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): return self._atom_dispatch[nodelist[0][0]](nodelist) def atom_lpar(self, nodelist): if nodelist[1][0] == token.RPAR: return Tuple((), lineno=nodelist[0][2]) return self.com_node(nodelist[1]) def atom_lsqb(self, nodelist): if nodelist[1][0] == token.RSQB: 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((), lineno=nodelist[0][2]) return self.com_dictorsetmaker(nodelist[1]) def atom_backquote(self, nodelist): return Backquote(self.com_node(nodelist[1])) def atom_number(self, nodelist): ### need to verify this matches compile.c k = eval(nodelist[0][1]) return Const(k, lineno=nodelist[0][2]) def decode_literal(self, lit): if self.encoding: # this is particularly fragile & a bit of a # hack... changes in compile.c:parsestr and # tokenizer.c must be reflected here. if self.encoding not in ['utf-8', 'iso-8859-1']: lit = unicode(lit, 'utf-8').encode(self.encoding) return eval("# coding: %s\n%s" % (self.encoding, lit)) else: return eval(lit) def atom_string(self, nodelist): k = '' for node in nodelist: k += self.decode_literal(node[1]) return Const(k, lineno=nodelist[0][2]) def atom_name(self, nodelist): return Name(nodelist[0][1], lineno=nodelist[0][2]) # -------------------------------------------------------------- # # INTERNAL PARSING UTILITIES # # The use of com_node() introduces a lot of extra stack frames, # enough to cause a stack overflow compiling test.test_parser with # the standard interpreter recursionlimit. The com_node() is a # convenience function that hides the dispatch details, but comes # at a very high cost. It is more efficient to dispatch directly # in the callers. In these cases, use lookup_node() and call the # dispatched node directly. def lookup_node(self, node): return self._dispatch[node[0]] def com_node(self, node): # Note: compile.c has handling in com_node for del_stmt, pass_stmt, # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt, # and compound_stmt. # We'll just dispatch them. return self._dispatch[node[0]](node[1:]) def com_NEWLINE(self, *args): # A ';' at the end of a line can make a NEWLINE token appear # here, Render it harmless. (genc discards ('discard', # ('const', xxxx)) Nodes) return Discard(Const(None)) def com_arglist(self, nodelist): # varargslist: # (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) # | fpdef ['=' test] (',' fpdef ['=' test])* [','] # fpdef: NAME | '(' fplist ')' # fplist: fpdef (',' fpdef)* [','] names = [] defaults = [] flags = 0 i = 0 while i < len(nodelist): node = nodelist[i] if node[0] == token.STAR or node[0] == token.DOUBLESTAR: if node[0] == token.STAR: node = nodelist[i+1] if node[0] == token.NAME: names.append(node[1]) flags = flags | CO_VARARGS i = i + 3 if i < len(nodelist): # should be DOUBLESTAR t = nodelist[i][0] if t == token.DOUBLESTAR: node = nodelist[i+1] else: raise ValueError, "unexpected token: %s" % t names.append(node[1]) flags = flags | CO_VARKEYWORDS break # fpdef: NAME | '(' fplist ')' names.append(self.com_fpdef(node)) i = i + 1 if i < len(nodelist) and nodelist[i][0] == token.EQUAL: defaults.append(self.com_node(nodelist[i + 1])) i = i + 2 elif len(defaults): # 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 def com_fpdef(self, node): # fpdef: NAME | '(' fplist ')' if node[1][0] == token.LPAR: return self.com_fplist(node[2]) return node[1][1] def com_fplist(self, node): # fplist: fpdef (',' fpdef)* [','] if len(node) == 2: return self.com_fpdef(node[1]) list = [] for i in range(1, len(node), 2): list.append(self.com_fpdef(node[i])) return tuple(list) def com_dotted_name(self, node): # String together the dotted names and return the string name = "" for n in node: if type(n) == type(()) and n[0] == 1: name = name + n[1] + '.' return name[:-1] def com_dotted_as_name(self, node): 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 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): assert node[0] == symbol.import_as_name node = node[1:] assert node[0][0] == token.NAME if len(node) == 1: 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_except_finally(self, nodelist): # ('try' ':' suite # ((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite] # | 'finally' ':' 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)] clauses = [] elseNode = None finallyNode = None for i in range(3, len(nodelist), 3): node = nodelist[i] if node[0] == symbol.except_clause: # except_clause: 'except' [expr [(',' | 'as') expr]] */ if len(node) > 2: expr1 = self.com_node(node[2]) if len(node) > 4: expr2 = self.com_assign(node[4], OP_ASSIGN) else: expr2 = None else: expr1 = expr2 = None clauses.append((expr1, expr2, self.com_node(nodelist[i+2]))) if node[0] == token.NAME: 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' with_item (',' with_item)* ':' suite body = self.com_node(nodelist[-1]) for i in range(len(nodelist) - 3, 0, -2): ret = self.com_with_item(nodelist[i], body, nodelist[0][2]) if i == 1: return ret body = ret def com_with_item(self, nodelist, body, lineno): # with_item: test ['as' expr] if len(nodelist) == 4: var = self.com_assign(nodelist[3], OP_ASSIGN) else: var = None expr = self.com_node(nodelist[1]) return With(expr, var, body, lineno=lineno) def com_augassign_op(self, node): assert node[0] == symbol.augassign return node[1] def com_augassign(self, node): """Return node suitable for lvalue of augmented assignment Names, slices, and attributes are the only allowable nodes. """ l = self.com_node(node) if l.__class__ in (Name, Slice, Subscript, Getattr): return l raise SyntaxError, "can't assign to %s" % l.__class__.__name__ def com_assign(self, node, assigning): # return a node suitable for use as an "lvalue" # loop to avoid trivial recursion while 1: t = node[0] if t in (symbol.exprlist, symbol.testlist, symbol.testlist_safe, symbol.testlist_comp): if len(node) > 2: return self.com_assign_tuple(node, assigning) node = node[1] elif t in _assign_types: if len(node) > 2: raise SyntaxError, "can't assign to operator" node = node[1] elif t == symbol.power: if node[1][0] != symbol.atom: raise SyntaxError, "can't assign to operator" if len(node) > 2: primary = self.com_node(node[1]) for i in range(2, len(node)-1): ch = node[i] if ch[0] == token.DOUBLESTAR: raise SyntaxError, "can't assign to operator" primary = self.com_apply_trailer(primary, ch) return self.com_assign_trailer(primary, node[-1], assigning) node = node[1] elif t == symbol.atom: t = node[1][0] if t == token.LPAR: node = node[2] if node[0] == token.RPAR: raise SyntaxError, "can't assign to ()" elif t == token.LSQB: node = node[2] if node[0] == token.RSQB: raise SyntaxError, "can't assign to []" return self.com_assign_list(node, assigning) elif t == token.NAME: return self.com_assign_name(node[1], assigning) else: raise SyntaxError, "can't assign to literal" else: 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, lineno=extractLineNo(node)) def com_assign_list(self, node, assigning): assigns = [] for i in range(1, len(node), 2): if i + 1 < len(node): if node[i + 1][0] == symbol.list_for: 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, lineno=extractLineNo(node)) def com_assign_name(self, node, assigning): return AssName(node[1], assigning, lineno=node[2]) def com_assign_trailer(self, primary, node, assigning): t = node[1][0] if t == token.DOT: return self.com_assign_attr(primary, node[2], assigning) if t == token.LSQB: return self.com_subscriptlist(primary, node[2], assigning) if t == token.LPAR: raise SyntaxError, "can't assign to function call" raise SyntaxError, "unknown trailer type: %s" % t def com_assign_attr(self, primary, node, assigning): return AssAttr(primary, node[1], assigning, lineno=node[-1]) def com_binary(self, constructor, nodelist): "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])." l = len(nodelist) if l == 1: n = nodelist[0] return self.lookup_node(n)(n[1:]) items = [] for i in range(0, l, 2): n = nodelist[i] items.append(self.lookup_node(n)(n[1:])) return constructor(items, lineno=extractLineNo(nodelist)) def com_stmt(self, node): result = self.lookup_node(node)(node[1:]) assert result is not None if isinstance(result, Stmt): return result return Stmt([result]) def com_append_stmt(self, stmts, node): result = self.lookup_node(node)(node[1:]) assert result is not None if isinstance(result, Stmt): stmts.extend(result.nodes) else: stmts.append(result) def com_list_constructor(self, nodelist): # listmaker: test ( list_for | (',' test)* [','] ) values = [] for i in range(1, len(nodelist)): if nodelist[i][0] == symbol.list_for: assert len(nodelist[i:]) == 1 return self.com_list_comprehension(values[0], nodelist[i]) elif nodelist[i][0] == token.COMMA: continue values.append(self.com_node(nodelist[i])) return List(values, lineno=values[0].lineno) def com_list_comprehension(self, expr, node): return self.com_comprehension(expr, None, node, 'list') def com_comprehension(self, expr1, expr2, node, type): # list_iter: list_for | list_if # list_for: 'for' exprlist 'in' testlist [list_iter] # list_if: 'if' test [list_iter] # XXX should raise SyntaxError for assignment # XXX(avassalotti) Set and dict comprehensions should have generator # semantics. In other words, they shouldn't leak # variables outside of the comprehension's scope. lineno = node[1][2] fors = [] while node: t = node[1][1] if t == 'for': assignNode = self.com_assign(node[2], OP_ASSIGN) compNode = self.com_node(node[4]) newfor = ListCompFor(assignNode, compNode, []) newfor.lineno = node[1][2] fors.append(newfor) if len(node) == 5: node = None elif type == 'list': node = self.com_list_iter(node[5]) else: node = self.com_comp_iter(node[5]) elif t == 'if': test = self.com_node(node[2]) newif = ListCompIf(test, lineno=node[1][2]) newfor.ifs.append(newif) if len(node) == 3: node = None elif type == 'list': node = self.com_list_iter(node[3]) else: node = self.com_comp_iter(node[3]) else: raise SyntaxError, \ ("unexpected comprehension element: %s %d" % (node, lineno)) if type == 'list': return ListComp(expr1, fors, lineno=lineno) elif type == 'set': return SetComp(expr1, fors, lineno=lineno) elif type == 'dict': return DictComp(expr1, expr2, fors, lineno=lineno) else: raise ValueError("unexpected comprehension type: " + repr(type)) def com_list_iter(self, node): assert node[0] == symbol.list_iter return node[1] def com_comp_iter(self, node): assert node[0] == symbol.comp_iter return node[1] def com_generator_expression(self, expr, node): # comp_iter: comp_for | comp_if # comp_for: 'for' exprlist 'in' test [comp_iter] # comp_if: 'if' test [comp_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_comp_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_comp_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_dictorsetmaker(self, nodelist): # dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | # (test (comp_for | (',' test)* [','])) ) assert nodelist[0] == symbol.dictorsetmaker nodelist = nodelist[1:] if len(nodelist) == 1 or nodelist[1][0] == token.COMMA: # set literal items = [] for i in range(0, len(nodelist), 2): items.append(self.com_node(nodelist[i])) return Set(items, lineno=items[0].lineno) elif nodelist[1][0] == symbol.comp_for: # set comprehension expr = self.com_node(nodelist[0]) return self.com_comprehension(expr, None, nodelist[1], 'set') elif len(nodelist) > 3 and nodelist[3][0] == symbol.comp_for: # dict comprehension assert nodelist[1][0] == token.COLON key = self.com_node(nodelist[0]) value = self.com_node(nodelist[2]) return self.com_comprehension(key, value, nodelist[3], 'dict') else: # dict literal items = [] for i in range(0, len(nodelist), 4): items.append((self.com_node(nodelist[i]), self.com_node(nodelist[i+2]))) return Dict(items, lineno=items[0][0].lineno) def com_apply_trailer(self, primaryNode, nodelist): t = nodelist[1][0] if t == token.LPAR: return self.com_call_function(primaryNode, nodelist[2]) if t == token.DOT: return self.com_select_member(primaryNode, nodelist[2]) if t == token.LSQB: return self.com_subscriptlist(primaryNode, nodelist[2], OP_APPLY) raise SyntaxError, 'unknown node type: %s' % t def com_select_member(self, primaryNode, nodelist): if nodelist[0] != token.NAME: raise SyntaxError, "member must be a name" return Getattr(primaryNode, nodelist[1], lineno=nodelist[2]) def com_call_function(self, primaryNode, nodelist): if nodelist[0] == token.RPAR: return CallFunc(primaryNode, [], lineno=extractLineNo(nodelist)) args = [] kw = 0 star_node = dstar_node = None len_nodelist = len(nodelist) i = 1 while i < len_nodelist: node = nodelist[i] if node[0]==token.STAR: if star_node is not None: raise SyntaxError, 'already have the varargs indentifier' star_node = self.com_node(nodelist[i+1]) i = i + 3 continue elif node[0]==token.DOUBLESTAR: if dstar_node is not None: raise SyntaxError, 'already have the kwargs indentifier' dstar_node = self.com_node(nodelist[i+1]) i = i + 3 continue # positional or named parameters kw, result = self.com_argument(node, kw, star_node) if len_nodelist != 2 and isinstance(result, GenExpr) \ and len(node) == 3 and node[2][0] == symbol.comp_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) i = i + 2 return CallFunc(primaryNode, args, star_node, dstar_node, lineno=extractLineNo(nodelist)) def com_argument(self, nodelist, kw, star_node): if len(nodelist) == 3 and nodelist[2][0] == symbol.comp_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" if star_node: raise SyntaxError, "only named arguments may follow *expression" return 0, self.com_node(nodelist[1]) result = self.com_node(nodelist[3]) n = nodelist[1] while len(n) == 2 and n[0] != token.NAME: n = n[1] if n[0] != token.NAME: raise SyntaxError, "keyword can't be an expression (%s)"%n[0] node = Keyword(n[1], result, lineno=n[2]) return 1, node def com_subscriptlist(self, primary, nodelist, assigning): # slicing: simple_slicing | extended_slicing # simple_slicing: primary "[" short_slice "]" # extended_slicing: primary "[" slice_list "]" # slice_list: slice_item ("," slice_item)* [","] # backwards compat slice for '[i:j]' if len(nodelist) == 2: sub = nodelist[1] if (sub[1][0] == token.COLON or \ (len(sub) > 2 and sub[2][0] == token.COLON)) and \ sub[-1][0] != symbol.sliceop: return self.com_slice(primary, sub, assigning) subscripts = [] for i in range(1, len(nodelist), 2): subscripts.append(self.com_subscript(nodelist[i])) return Subscript(primary, assigning, subscripts, lineno=extractLineNo(nodelist)) def com_subscript(self, node): # slice_item: expression | proper_slice | ellipsis ch = node[1] t = ch[0] if t == token.DOT and node[2][0] == token.DOT: return Ellipsis() if t == token.COLON or len(node) > 2: return self.com_sliceobj(node) return self.com_node(ch) def com_sliceobj(self, node): # proper_slice: short_slice | long_slice # short_slice: [lower_bound] ":" [upper_bound] # long_slice: short_slice ":" [stride] # lower_bound: expression # upper_bound: expression # stride: expression # # Note: a stride may be further slicing... items = [] if node[1][0] == token.COLON: items.append(Const(None)) i = 2 else: items.append(self.com_node(node[1])) # i == 2 is a COLON i = 3 if i < len(node) and node[i][0] == symbol.test: items.append(self.com_node(node[i])) i = i + 1 else: items.append(Const(None)) # a short_slice has been built. look for long_slice now by looking # for strides... for j in range(i, len(node)): ch = node[j] if len(ch) == 2: items.append(Const(None)) else: items.append(self.com_node(ch[2])) return Sliceobj(items, lineno=extractLineNo(node)) def com_slice(self, primary, node, assigning): # short_slice: [lower_bound] ":" [upper_bound] lower = upper = None if len(node) == 3: if node[1][0] == token.COLON: upper = self.com_node(node[2]) else: lower = self.com_node(node[1]) elif len(node) == 4: lower = self.com_node(node[1]) upper = self.com_node(node[3]) return Slice(primary, assigning, lower, upper, lineno=extractLineNo(node)) def get_docstring(self, node, n=None): if n is None: n = node[0] node = node[1:] if n == symbol.suite: if len(node) == 1: return self.get_docstring(node[0]) for sub in node: if sub[0] == symbol.stmt: return self.get_docstring(sub) return None if n == symbol.file_input: for sub in node: if sub[0] == symbol.stmt: return self.get_docstring(sub) return None if n == symbol.atom: if node[0][0] == token.STRING: s = '' for t in node: s = s + eval(t[1]) return s return None if n == symbol.stmt or n == symbol.simple_stmt \ or n == symbol.small_stmt: return self.get_docstring(node[0]) if n in _doc_nodes and len(node) == 1: return self.get_docstring(node[0]) return None _doc_nodes = [ symbol.expr_stmt, symbol.testlist, symbol.testlist_safe, symbol.test, symbol.or_test, symbol.and_test, symbol.not_test, symbol.comparison, symbol.expr, symbol.xor_expr, symbol.and_expr, symbol.shift_expr, symbol.arith_expr, symbol.term, symbol.factor, symbol.power, ] # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '==' # | 'in' | 'not' 'in' | 'is' | 'is' 'not' _cmp_types = { token.LESS : '<', token.GREATER : '>', token.EQEQUAL : '==', token.EQUAL : '==', token.LESSEQUAL : '<=', token.GREATEREQUAL : '>=', token.NOTEQUAL : '!=', } _legal_node_types = [ symbol.funcdef, symbol.classdef, symbol.stmt, symbol.small_stmt, symbol.flow_stmt, symbol.simple_stmt, symbol.compound_stmt, symbol.expr_stmt, symbol.print_stmt, symbol.del_stmt, symbol.pass_stmt, symbol.break_stmt, symbol.continue_stmt, symbol.return_stmt, symbol.raise_stmt, symbol.import_stmt, symbol.global_stmt, symbol.exec_stmt, symbol.assert_stmt, symbol.if_stmt, symbol.while_stmt, symbol.for_stmt, symbol.try_stmt, symbol.with_stmt, symbol.suite, symbol.testlist, symbol.testlist_safe, symbol.test, symbol.and_test, symbol.not_test, symbol.comparison, symbol.exprlist, symbol.expr, symbol.xor_expr, symbol.and_expr, symbol.shift_expr, symbol.arith_expr, symbol.term, symbol.factor, symbol.power, symbol.atom, ] 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, symbol.expr, symbol.xor_expr, symbol.and_expr, symbol.shift_expr, symbol.arith_expr, symbol.term, symbol.factor, ] _names = {} for k, v in symbol.sym_name.items(): _names[k] = v for k, v in token.tok_name.items(): _names[k] = v def debug_tree(tree): l = [] for elt in tree: if isinstance(elt, int): l.append(_names.get(elt, elt)) elif isinstance(elt, str): l.append(elt) else: l.append(debug_tree(elt)) return l