Lichen

compiler/transformer.py

609:3a80900f08ff
2017-02-21 Paul Boddie Only copy changed template files and only generate updated program files, removing the "make clean" invocation and permitting incremental builds. Changed constant labelling to employ content digests so that constant names remain stable and do not confuse already-generated code. method-wrapper-for-context
     1 """Parse tree transformation module.     2      3 Transforms Python source code into an abstract syntax tree (AST)     4 defined in the ast module.     5      6 The simplest ways to invoke this module are via parse and parseFile.     7 parse(buf) -> AST     8 parseFile(path) -> AST     9 """    10     11 # Original version written by Greg Stein (gstein@lyra.org)    12 #                         and Bill Tutt (rassilon@lima.mudlib.org)    13 # February 1997.    14 #    15 # Modifications and improvements for Python 2.0 by Jeremy Hylton and    16 # Mark Hammond    17 #    18 # Some fixes to try to have correct line number on almost all nodes    19 # (except Module, Discard and Stmt) added by Sylvain Thenault    20 #    21 # Portions of this file are:    22 # Copyright (C) 1997-1998 Greg Stein. All Rights Reserved.    23 #    24 # This module is provided under a BSD-ish license. See    25 #   http://www.opensource.org/licenses/bsd-license.html    26 # and replace OWNER, ORGANIZATION, and YEAR as appropriate.    27     28 from compiler.ast import *    29 from pyparser.pygram import syms as symbol, sym_name, tokens as token, tok_name    30 import pyparser.pyparse as parser    31     32 class WalkerError(StandardError):    33     pass    34     35 from compiler.consts import CO_VARARGS, CO_VARKEYWORDS    36 from compiler.consts import OP_ASSIGN, OP_DELETE, OP_APPLY    37     38 def parseFile(path):    39     f = open(path, "U")    40     # XXX The parser API tolerates files without a trailing newline,    41     # but not strings without a trailing newline.  Always add an extra    42     # newline to the file contents, since we're going through the string    43     # version of the API.    44     src = f.read() + "\n"    45     f.close()    46     return parse(src)    47     48 def parse(buf, mode="exec"):    49     if mode == "exec" or mode == "single":    50         return Transformer().parsesuite(buf)    51     elif mode == "eval":    52         return Transformer().parseexpr(buf)    53     else:    54         raise ValueError("compile() arg 3 must be"    55                          " 'exec' or 'eval' or 'single'")    56     57 def extractLineNo(ast):    58     if not isinstance(ast[1], tuple):    59         # get a terminal node    60         return ast[2]    61     for child in ast[1:]:    62         if isinstance(child, tuple):    63             lineno = extractLineNo(child)    64             if lineno is not None:    65                 return lineno    66     67 def Node(*args):    68     kind = args[0]    69     if kind in nodes:    70         try:    71             return nodes[kind](*args[1:])    72         except TypeError:    73             print nodes[kind], len(args), args    74             raise    75     else:    76         raise WalkerError, "Can't find appropriate Node type: %s" % str(args)    77         #return apply(ast.Node, args)    78     79 class Transformer:    80     """Utility object for transforming Python parse trees.    81     82     Exposes the following methods:    83         tree = transform(ast_tree)    84         tree = parsesuite(text)    85         tree = parseexpr(text)    86         tree = parsefile(fileob | filename)    87     """    88     89     def __init__(self):    90         self._dispatch = {}    91         for value, name in sym_name.items():    92             if hasattr(self, name):    93                 self._dispatch[value] = getattr(self, name)    94         self._dispatch[token["NEWLINE"]] = self.com_NEWLINE    95         self._atom_dispatch = {token["LPAR"]: self.atom_lpar,    96                                token["LSQB"]: self.atom_lsqb,    97                                token["LBRACE"]: self.atom_lbrace,    98                                token["BACKQUOTE"]: self.atom_backquote,    99                                token["NUMBER"]: self.atom_number,   100                                token["STRING"]: self.atom_string,   101                                token["NAME"]: self.atom_name,   102                                }   103         self.encoding = None   104    105     def transform(self, tree):   106         """Transform an AST into a modified parse tree."""   107         if not (isinstance(tree, tuple) or isinstance(tree, list)):   108             tree = parser.st2tuple(tree, line_info=1)   109         return self.compile_node(tree)   110    111     def parsesuite(self, text):   112         """Return a modified parse tree for the given suite text."""   113         return self.transform(parser.suite(text))   114    115     def parseexpr(self, text):   116         """Return a modified parse tree for the given expression text."""   117         return self.transform(parser.expr(text))   118    119     def parsefile(self, file):   120         """Return a modified parse tree for the contents of the given file."""   121         if type(file) == type(''):   122             file = open(file)   123         return self.parsesuite(file.read())   124    125     # --------------------------------------------------------------   126     #   127     # PRIVATE METHODS   128     #   129    130     def compile_node(self, node):   131         ### emit a line-number node?   132         n = node[0]   133    134         if n == symbol["encoding_decl"]:   135             self.encoding = node[2]   136             node = node[1]   137             n = node[0]   138    139         if n == symbol["single_input"]:   140             return self.single_input(node[1:])   141         if n == symbol["file_input"]:   142             return self.file_input(node[1:])   143         if n == symbol["eval_input"]:   144             return self.eval_input(node[1:])   145         if n == symbol["lambdef"]:   146             return self.lambdef(node[1:])   147         if n == symbol["funcdef"]:   148             return self.funcdef(node[1:])   149         if n == symbol["classdef"]:   150             return self.classdef(node[1:])   151    152         raise WalkerError, ('unexpected node type', n)   153    154     def single_input(self, node):   155         ### do we want to do anything about being "interactive" ?   156    157         # NEWLINE | simple_stmt | compound_stmt NEWLINE   158         n = node[0][0]   159         if n != token["NEWLINE"]:   160             return self.com_stmt(node[0])   161    162         return Pass()   163    164     def file_input(self, nodelist):   165         doc = self.get_docstring(nodelist, symbol["file_input"])   166         if doc is not None:   167             i = 1   168         else:   169             i = 0   170         stmts = []   171         for node in nodelist[i:]:   172             if node[0] != token["ENDMARKER"] and node[0] != token["NEWLINE"]:   173                 self.com_append_stmt(stmts, node)   174         return Module(doc, Stmt(stmts))   175    176     def eval_input(self, nodelist):   177         # from the built-in function input()   178         ### is this sufficient?   179         return Expression(self.com_node(nodelist[0]))   180    181     def funcdef(self, nodelist):   182         #          -5    -4   -3         -2  -1   183         # funcdef: 'def' NAME parameters ':' suite   184         # parameters: '(' [varargslist] ')'   185    186         assert len(nodelist) == 5   187         decorators = None   188    189         lineno = nodelist[-4][2]   190         name = nodelist[-4][1]   191         args = nodelist[-3][2]   192    193         if args[0] == symbol["varargslist"]:   194             names, defaults, flags = self.com_arglist(args[1:])   195         else:   196             names = defaults = ()   197             flags = 0   198         doc = self.get_docstring(nodelist[-1])   199    200         # code for function   201         code = self.com_node(nodelist[-1])   202    203         if doc is not None:   204             assert isinstance(code, Stmt)   205             assert isinstance(code.nodes[0], Discard)   206             del code.nodes[0]   207         return Function(decorators, name, names, defaults, flags, doc, code,   208                      lineno=lineno)   209    210     def lambdef(self, nodelist):   211         # lambdef: 'lambda' [varargslist] ':' test   212         if nodelist[2][0] == symbol["varargslist"]:   213             names, defaults, flags = self.com_arglist(nodelist[2][1:])   214         else:   215             names = defaults = ()   216             flags = 0   217    218         # code for lambda   219         code = self.com_node(nodelist[-1])   220    221         return Lambda(names, defaults, flags, code, lineno=nodelist[1][2])   222     old_lambdef = lambdef   223    224     def classdef(self, nodelist):   225         # classdef: 'class' NAME ['(' [testlist] ')'] ':' suite   226    227         name = nodelist[1][1]   228         doc = self.get_docstring(nodelist[-1])   229         if nodelist[2][0] == token["COLON"]:   230             bases = []   231         elif nodelist[3][0] == token["RPAR"]:   232             bases = []   233         else:   234             bases = self.com_bases(nodelist[3])   235    236         # code for class   237         code = self.com_node(nodelist[-1])   238    239         if doc is not None:   240             assert isinstance(code, Stmt)   241             assert isinstance(code.nodes[0], Discard)   242             del code.nodes[0]   243    244         return Class(name, bases, doc, code, lineno=nodelist[1][2])   245    246     def stmt(self, nodelist):   247         return self.com_stmt(nodelist[0])   248    249     small_stmt = stmt   250     flow_stmt = stmt   251     compound_stmt = stmt   252    253     def simple_stmt(self, nodelist):   254         # small_stmt (';' small_stmt)* [';'] NEWLINE   255         stmts = []   256         for i in range(0, len(nodelist), 2):   257             self.com_append_stmt(stmts, nodelist[i])   258         return Stmt(stmts)   259    260     def parameters(self, nodelist):   261         raise WalkerError   262    263     def varargslist(self, nodelist):   264         raise WalkerError   265    266     def fpdef(self, nodelist):   267         raise WalkerError   268    269     def fplist(self, nodelist):   270         raise WalkerError   271    272     def dotted_name(self, nodelist):   273         raise WalkerError   274    275     def comp_op(self, nodelist):   276         raise WalkerError   277    278     def trailer(self, nodelist):   279         raise WalkerError   280    281     def sliceop(self, nodelist):   282         raise WalkerError   283    284     def argument(self, nodelist):   285         raise WalkerError   286    287     # --------------------------------------------------------------   288     #   289     # STATEMENT NODES  (invoked by com_node())   290     #   291    292     def expr_stmt(self, nodelist):   293         # augassign testlist | testlist ('=' testlist)*   294         en = nodelist[-1]   295         exprNode = self.lookup_node(en)(en[1:])   296         if len(nodelist) == 1:   297             return Discard(exprNode, lineno=exprNode.lineno)   298         if nodelist[1][0] == token["EQUAL"]:   299             nodesl = []   300             for i in range(0, len(nodelist) - 2, 2):   301                 nodesl.append(self.com_assign(nodelist[i], OP_ASSIGN))   302             return Assign(nodesl, exprNode, lineno=nodelist[1][2])   303         else:   304             lval = self.com_augassign(nodelist[0])   305             op = self.com_augassign_op(nodelist[1])   306             return AugAssign(lval, op[1], exprNode, lineno=op[2])   307         raise WalkerError, "can't get here"   308    309     def print_stmt(self, nodelist):   310         # print ([ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ])   311         items = []   312         if len(nodelist) == 1:   313             start = 1   314             dest = None   315         elif nodelist[1][0] == token["RIGHTSHIFT"]:   316             assert len(nodelist) == 3 \   317                    or nodelist[3][0] == token["COMMA"]   318             dest = self.com_node(nodelist[2])   319             start = 4   320         else:   321             dest = None   322             start = 1   323         for i in range(start, len(nodelist), 2):   324             items.append(self.com_node(nodelist[i]))   325         if nodelist[-1][0] == token["COMMA"]:   326             return Print(items, dest, lineno=nodelist[0][2])   327         return Printnl(items, dest, lineno=nodelist[0][2])   328    329     def del_stmt(self, nodelist):   330         return self.com_assign(nodelist[1], OP_DELETE)   331    332     def pass_stmt(self, nodelist):   333         return Pass(lineno=nodelist[0][2])   334    335     def break_stmt(self, nodelist):   336         return Break(lineno=nodelist[0][2])   337    338     def continue_stmt(self, nodelist):   339         return Continue(lineno=nodelist[0][2])   340    341     def return_stmt(self, nodelist):   342         # return: [testlist]   343         if len(nodelist) < 2:   344             return Return(Const(None), lineno=nodelist[0][2])   345         return Return(self.com_node(nodelist[1]), lineno=nodelist[0][2])   346    347     def raise_stmt(self, nodelist):   348         # raise: [test [',' test [',' test]]]   349         if len(nodelist) > 5:   350             expr3 = self.com_node(nodelist[5])   351         else:   352             expr3 = None   353         if len(nodelist) > 3:   354             expr2 = self.com_node(nodelist[3])   355         else:   356             expr2 = None   357         if len(nodelist) > 1:   358             expr1 = self.com_node(nodelist[1])   359         else:   360             expr1 = None   361         return Raise(expr1, expr2, expr3, lineno=nodelist[0][2])   362    363     def import_stmt(self, nodelist):   364         # import_stmt: import_name | import_from   365         assert len(nodelist) == 1   366         return self.com_node(nodelist[0])   367    368     def import_name(self, nodelist):   369         # import_name: 'import' dotted_as_names   370         return Import(self.com_dotted_as_names(nodelist[1]),   371                       lineno=nodelist[0][2])   372    373     def import_from(self, nodelist):   374         # import_from: 'from' ('.'* dotted_name | '.') 'import' ('*' |   375         #    '(' import_as_names ')' | import_as_names)   376         assert nodelist[0][1] == 'from'   377         idx = 1   378         while nodelist[idx][1] == '.':   379             idx += 1   380         level = idx - 1   381         if nodelist[idx][0] == symbol["dotted_name"]:   382             fromname = self.com_dotted_name(nodelist[idx])   383             idx += 1   384         else:   385             fromname = ""   386         assert nodelist[idx][1] == 'import'   387         if nodelist[idx + 1][0] == token["STAR"]:   388             return From(fromname, [('*', None)], level,   389                         lineno=nodelist[0][2])   390         else:   391             node = nodelist[idx + 1 + (nodelist[idx + 1][0] == token["LPAR"])]   392             return From(fromname, self.com_import_as_names(node), level,   393                         lineno=nodelist[0][2])   394    395     def global_stmt(self, nodelist):   396         # global: NAME (',' NAME)*   397         names = []   398         for i in range(1, len(nodelist), 2):   399             names.append(nodelist[i][1])   400         return Global(names, lineno=nodelist[0][2])   401    402     def exec_stmt(self, nodelist):   403         # exec_stmt: 'exec' expr ['in' expr [',' expr]]   404         expr1 = self.com_node(nodelist[1])   405         if len(nodelist) >= 4:   406             expr2 = self.com_node(nodelist[3])   407             if len(nodelist) >= 6:   408                 expr3 = self.com_node(nodelist[5])   409             else:   410                 expr3 = None   411         else:   412             expr2 = expr3 = None   413    414         return Exec(expr1, expr2, expr3, lineno=nodelist[0][2])   415    416     def assert_stmt(self, nodelist):   417         # 'assert': test, [',' test]   418         expr1 = self.com_node(nodelist[1])   419         if (len(nodelist) == 4):   420             expr2 = self.com_node(nodelist[3])   421         else:   422             expr2 = None   423         return Assert(expr1, expr2, lineno=nodelist[0][2])   424    425     def if_stmt(self, nodelist):   426         # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]   427         tests = []   428         for i in range(0, len(nodelist) - 3, 4):   429             testNode = self.com_node(nodelist[i + 1])   430             suiteNode = self.com_node(nodelist[i + 3])   431             tests.append((testNode, suiteNode))   432    433         if len(nodelist) % 4 == 3:   434             elseNode = self.com_node(nodelist[-1])   435 ##      elseNode.lineno = nodelist[-1][1][2]   436         else:   437             elseNode = None   438         return If(tests, elseNode, lineno=nodelist[0][2])   439    440     def while_stmt(self, nodelist):   441         # 'while' test ':' suite ['else' ':' suite]   442    443         testNode = self.com_node(nodelist[1])   444         bodyNode = self.com_node(nodelist[3])   445    446         if len(nodelist) > 4:   447             elseNode = self.com_node(nodelist[6])   448         else:   449             elseNode = None   450    451         return While(testNode, bodyNode, elseNode, lineno=nodelist[0][2])   452    453     def for_stmt(self, nodelist):   454         # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]   455    456         assignNode = self.com_assign(nodelist[1], OP_ASSIGN)   457         listNode = self.com_node(nodelist[3])   458         bodyNode = self.com_node(nodelist[5])   459    460         if len(nodelist) > 8:   461             elseNode = self.com_node(nodelist[8])   462         else:   463             elseNode = None   464    465         return For(assignNode, listNode, bodyNode, elseNode,   466                    lineno=nodelist[0][2])   467    468     def try_stmt(self, nodelist):   469         return self.com_try_except_finally(nodelist)   470    471     def with_stmt(self, nodelist):   472         return self.com_with(nodelist)   473    474     def suite(self, nodelist):   475         # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT   476         if len(nodelist) == 1:   477             return self.com_stmt(nodelist[0])   478    479         stmts = []   480         for node in nodelist:   481             if node[0] == symbol["stmt"]:   482                 self.com_append_stmt(stmts, node)   483         return Stmt(stmts)   484    485     # --------------------------------------------------------------   486     #   487     # EXPRESSION NODES  (invoked by com_node())   488     #   489    490     def testlist(self, nodelist):   491         # testlist: expr (',' expr)* [',']   492         # testlist_safe: test [(',' test)+ [',']]   493         # exprlist: expr (',' expr)* [',']   494         return self.com_binary(Tuple, nodelist)   495    496     testlist_safe = testlist # XXX   497     testlist1 = testlist   498     exprlist = testlist   499    500     def testlist_comp(self, nodelist):   501         # test ( (',' test)* [','] )   502         assert nodelist[0][0] == symbol["test"]   503         return self.testlist(nodelist)   504    505     def test(self, nodelist):   506         # or_test | lambdef   507         if len(nodelist) == 1 and nodelist[0][0] == symbol["lambdef"]:   508             return self.lambdef(nodelist[0])   509         then = self.com_node(nodelist[0])   510         return then   511    512     def or_test(self, nodelist):   513         # and_test ('or' and_test)* | lambdef   514         if len(nodelist) == 1 and nodelist[0][0] == symbol["lambdef"]:   515             return self.lambdef(nodelist[0])   516         return self.com_binary(Or, nodelist)   517     old_test = or_test   518    519     def and_test(self, nodelist):   520         # not_test ('and' not_test)*   521         return self.com_binary(And, nodelist)   522    523     def not_test(self, nodelist):   524         # 'not' not_test | comparison   525         result = self.com_node(nodelist[-1])   526         if len(nodelist) == 2:   527             return Not(result, lineno=nodelist[0][2])   528         return result   529    530     def comparison(self, nodelist):   531         # comparison: expr (comp_op expr)*   532         node = self.com_node(nodelist[0])   533         if len(nodelist) == 1:   534             return node   535    536         results = []   537         for i in range(2, len(nodelist), 2):   538             nl = nodelist[i-1]   539    540             # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='   541             #          | 'in' | 'not' 'in' | 'is' | 'is' 'not'   542             n = nl[1]   543             if n[0] == token["NAME"]:   544                 type = n[1]   545                 if len(nl) == 3:   546                     if type == 'not':   547                         type = 'not in'   548                     else:   549                         type = 'is not'   550             else:   551                 type = _cmp_types[n[0]]   552    553             lineno = nl[1][2]   554             results.append((type, self.com_node(nodelist[i])))   555    556         # we need a special "compare" node so that we can distinguish   557         #   3 < x < 5   from    (3 < x) < 5   558         # the two have very different semantics and results (note that the   559         # latter form is always true)   560    561         return Compare(node, results, lineno=lineno)   562    563     def expr(self, nodelist):   564         # xor_expr ('|' xor_expr)*   565         return self.com_binary(Bitor, nodelist)   566    567     def xor_expr(self, nodelist):   568         # xor_expr ('^' xor_expr)*   569         return self.com_binary(Bitxor, nodelist)   570    571     def and_expr(self, nodelist):   572         # xor_expr ('&' xor_expr)*   573         return self.com_binary(Bitand, nodelist)   574    575     def shift_expr(self, nodelist):   576         # shift_expr ('<<'|'>>' shift_expr)*   577         node = self.com_node(nodelist[0])   578         for i in range(2, len(nodelist), 2):   579             right = self.com_node(nodelist[i])   580             if nodelist[i-1][0] == token["LEFTSHIFT"]:   581                 node = LeftShift([node, right], lineno=nodelist[1][2])   582             elif nodelist[i-1][0] == token["RIGHTSHIFT"]:   583                 node = RightShift([node, right], lineno=nodelist[1][2])   584             else:   585                 raise ValueError, "unexpected token: %s" % nodelist[i-1][0]   586         return node   587    588     def arith_expr(self, nodelist):   589         node = self.com_node(nodelist[0])   590         for i in range(2, len(nodelist), 2):   591             right = self.com_node(nodelist[i])   592             if nodelist[i-1][0] == token["PLUS"]:   593                 node = Add([node, right], lineno=nodelist[1][2])   594             elif nodelist[i-1][0] == token["MINUS"]:   595                 node = Sub([node, right], lineno=nodelist[1][2])   596             else:   597                 raise ValueError, "unexpected token: %s" % nodelist[i-1][0]   598         return node   599    600     def term(self, nodelist):   601         node = self.com_node(nodelist[0])   602         for i in range(2, len(nodelist), 2):   603             right = self.com_node(nodelist[i])   604             t = nodelist[i-1][0]   605             if t == token["STAR"]:   606                 node = Mul([node, right])   607             elif t == token["SLASH"]:   608                 node = Div([node, right])   609             elif t == token["PERCENT"]:   610                 node = Mod([node, right])   611             elif t == token["DOUBLESLASH"]:   612                 node = FloorDiv([node, right])   613             else:   614                 raise ValueError, "unexpected token: %s" % t   615             node.lineno = nodelist[1][2]   616         return node   617    618     def factor(self, nodelist):   619         elt = nodelist[0]   620         t = elt[0]   621         node = self.lookup_node(nodelist[-1])(nodelist[-1][1:])   622         # need to handle (unary op)constant here...   623         if t == token["PLUS"]:   624             return UnaryAdd(node, lineno=elt[2])   625         elif t == token["MINUS"]:   626             return UnarySub(node, lineno=elt[2])   627         elif t == token["TILDE"]:   628             node = Invert(node, lineno=elt[2])   629         return node   630    631     def power(self, nodelist):   632         # power: atom trailer* ('**' factor)*   633         node = self.com_node(nodelist[0])   634         for i in range(1, len(nodelist)):   635             elt = nodelist[i]   636             if elt[0] == token["DOUBLESTAR"]:   637                 return Power([node, self.com_node(nodelist[i+1])],   638                              lineno=elt[2])   639    640             node = self.com_apply_trailer(node, elt)   641    642         return node   643    644     def atom(self, nodelist):   645         return self._atom_dispatch[nodelist[0][0]](nodelist)   646    647     def atom_lpar(self, nodelist):   648         if nodelist[1][0] == token["RPAR"]:   649             return Tuple((), lineno=nodelist[0][2])   650         return self.com_node(nodelist[1])   651    652     def atom_lsqb(self, nodelist):   653         if nodelist[1][0] == token["RSQB"]:   654             return List((), lineno=nodelist[0][2])   655         return self.com_list_constructor(nodelist[1])   656    657     def atom_lbrace(self, nodelist):   658         if nodelist[1][0] == token["RBRACE"]:   659             return Dict((), lineno=nodelist[0][2])   660         return self.com_dictorsetmaker(nodelist[1])   661    662     def atom_backquote(self, nodelist):   663         return Backquote(self.com_node(nodelist[1]))   664    665     def atom_number(self, nodelist):   666         ### need to verify this matches compile.c   667         k = eval(nodelist[0][1])   668         return Const(k, nodelist[0][1], lineno=nodelist[0][2])   669    670     def decode_literal(self, lit):   671         if self.encoding:   672             # this is particularly fragile & a bit of a   673             # hack... changes in compile.c:parsestr and   674             # tokenizer.c must be reflected here.   675             if self.encoding != 'utf-8':   676                 lit = unicode(lit, 'utf-8').encode(self.encoding)   677             return eval("# coding: %s\n%s" % (self.encoding, lit))   678         else:   679             return eval(lit)   680    681     def atom_string(self, nodelist):   682         k = ''   683         l = []   684         for node in nodelist:   685             k += self.decode_literal(node[1])   686             l.append(node[1])   687         return Const(k, l, lineno=nodelist[0][2])   688    689     def atom_name(self, nodelist):   690         return Name(nodelist[0][1], lineno=nodelist[0][2])   691    692     # --------------------------------------------------------------   693     #   694     # INTERNAL PARSING UTILITIES   695     #   696    697     # The use of com_node() introduces a lot of extra stack frames,   698     # enough to cause a stack overflow compiling test.test_parser with   699     # the standard interpreter recursionlimit.  The com_node() is a   700     # convenience function that hides the dispatch details, but comes   701     # at a very high cost.  It is more efficient to dispatch directly   702     # in the callers.  In these cases, use lookup_node() and call the   703     # dispatched node directly.   704    705     def lookup_node(self, node):   706         return self._dispatch[node[0]]   707    708     def com_node(self, node):   709         # Note: compile.c has handling in com_node for del_stmt, pass_stmt,   710         #       break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,   711         #       and compound_stmt.   712         #       We'll just dispatch them.   713         return self._dispatch[node[0]](node[1:])   714    715     def com_NEWLINE(self, *args):   716         # A ';' at the end of a line can make a NEWLINE token appear   717         # here, Render it harmless. (genc discards ('discard',   718         # ('const', xxxx)) Nodes)   719         return Discard(Const(None))   720    721     def com_arglist(self, nodelist):   722         # varargslist:   723         #     (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME)   724         #   | fpdef ['=' test] (',' fpdef ['=' test])* [',']   725         # fpdef: NAME | '(' fplist ')'   726         # fplist: fpdef (',' fpdef)* [',']   727         names = []   728         defaults = []   729         flags = 0   730    731         i = 0   732         while i < len(nodelist):   733             node = nodelist[i]   734             if node[0] == token["STAR"] or node[0] == token["DOUBLESTAR"]:   735                 if node[0] == token["STAR"]:   736                     node = nodelist[i+1]   737                     if node[0] == token["NAME"]:   738                         names.append(node[1])   739                         flags = flags | CO_VARARGS   740                         i = i + 3   741    742                 if i < len(nodelist):   743                     # should be DOUBLESTAR   744                     t = nodelist[i][0]   745                     if t == token["DOUBLESTAR"]:   746                         node = nodelist[i+1]   747                     else:   748                         raise ValueError, "unexpected token: %s" % t   749                     names.append(node[1])   750                     flags = flags | CO_VARKEYWORDS   751    752                 break   753    754             # fpdef: NAME | '(' fplist ')'   755             names.append(self.com_fpdef(node))   756    757             i = i + 1   758             if i < len(nodelist) and nodelist[i][0] == token["EQUAL"]:   759                 defaults.append(self.com_node(nodelist[i + 1]))   760                 i = i + 2   761             elif len(defaults):   762                 # we have already seen an argument with default, but here   763                 # came one without   764                 raise SyntaxError, "non-default argument follows default argument"   765    766             # skip the comma   767             i = i + 1   768    769         return names, defaults, flags   770    771     def com_fpdef(self, node):   772         # fpdef: NAME | '(' fplist ')'   773         if node[1][0] == token["LPAR"]:   774             return self.com_fplist(node[2])   775         return node[1][1]   776    777     def com_fplist(self, node):   778         # fplist: fpdef (',' fpdef)* [',']   779         if len(node) == 2:   780             return self.com_fpdef(node[1])   781         list = []   782         for i in range(1, len(node), 2):   783             list.append(self.com_fpdef(node[i]))   784         return tuple(list)   785    786     def com_dotted_name(self, node):   787         # String together the dotted names and return the string   788         name = ""   789         for n in node:   790             if type(n) == type(()) and n[0] == 1:   791                 name = name + n[1] + '.'   792         return name[:-1]   793    794     def com_dotted_as_name(self, node):   795         assert node[0] == symbol["dotted_as_name"]   796         node = node[1:]   797         dot = self.com_dotted_name(node[0][1:])   798         if len(node) == 1:   799             return dot, None   800         assert node[1][1] == 'as'   801         assert node[2][0] == token["NAME"]   802         return dot, node[2][1]   803    804     def com_dotted_as_names(self, node):   805         assert node[0] == symbol["dotted_as_names"]   806         node = node[1:]   807         names = [self.com_dotted_as_name(node[0])]   808         for i in range(2, len(node), 2):   809             names.append(self.com_dotted_as_name(node[i]))   810         return names   811    812     def com_import_as_name(self, node):   813         assert node[0] == symbol["import_as_name"]   814         node = node[1:]   815         assert node[0][0] == token["NAME"]   816         if len(node) == 1:   817             return node[0][1], None   818         assert node[1][1] == 'as', node   819         assert node[2][0] == token["NAME"]   820         return node[0][1], node[2][1]   821    822     def com_import_as_names(self, node):   823         assert node[0] == symbol["import_as_names"]   824         node = node[1:]   825         names = [self.com_import_as_name(node[0])]   826         for i in range(2, len(node), 2):   827             names.append(self.com_import_as_name(node[i]))   828         return names   829    830     def com_bases(self, node):   831         bases = []   832         for i in range(1, len(node), 2):   833             bases.append(self.com_node(node[i]))   834         return bases   835    836     def com_try_except_finally(self, nodelist):   837         # ('try' ':' suite   838         #  ((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite]   839         #   | 'finally' ':' suite))   840    841         if nodelist[3][0] == token["NAME"]:   842             # first clause is a finally clause: only try-finally   843             return TryFinally(self.com_node(nodelist[2]),   844                               self.com_node(nodelist[5]),   845                               lineno=nodelist[0][2])   846    847         #tryexcept:  [TryNode, [except_clauses], elseNode)]   848         clauses = []   849         elseNode = None   850         finallyNode = None   851         for i in range(3, len(nodelist), 3):   852             node = nodelist[i]   853             if node[0] == symbol["except_clause"]:   854                 # except_clause: 'except' [expr [(',' | 'as') expr]] */   855                 if len(node) > 2:   856                     expr1 = self.com_node(node[2])   857                     if len(node) > 4:   858                         expr2 = self.com_assign(node[4], OP_ASSIGN)   859                     else:   860                         expr2 = None   861                 else:   862                     expr1 = expr2 = None   863                 clauses.append((expr1, expr2, self.com_node(nodelist[i+2])))   864    865             if node[0] == token["NAME"]:   866                 if node[1] == 'else':   867                     elseNode = self.com_node(nodelist[i+2])   868                 elif node[1] == 'finally':   869                     finallyNode = self.com_node(nodelist[i+2])   870         try_except = TryExcept(self.com_node(nodelist[2]), clauses, elseNode,   871                                lineno=nodelist[0][2])   872         if finallyNode:   873             return TryFinally(try_except, finallyNode, lineno=nodelist[0][2])   874         else:   875             return try_except   876    877     def com_with(self, nodelist):   878         # with_stmt: 'with' with_item (',' with_item)* ':' suite   879         body = self.com_node(nodelist[-1])   880         for i in range(len(nodelist) - 3, 0, -2):   881             ret = self.com_with_item(nodelist[i], body, nodelist[0][2])   882             if i == 1:   883                 return ret   884             body = ret   885    886     def com_with_item(self, nodelist, body, lineno):   887         # with_item: test ['as' expr]   888         if len(nodelist) == 4:   889             var = self.com_assign(nodelist[3], OP_ASSIGN)   890         else:   891             var = None   892         expr = self.com_node(nodelist[1])   893         return With(expr, var, body, lineno=lineno)   894    895     def com_augassign_op(self, node):   896         assert node[0] == symbol["augassign"]   897         return node[1]   898    899     def com_augassign(self, node):   900         """Return node suitable for lvalue of augmented assignment   901    902         Names, slices, and attributes are the only allowable nodes.   903         """   904         l = self.com_node(node)   905         if l.__class__ in (Name, Slice, Subscript, Getattr):   906             return l   907         raise SyntaxError, "can't assign to %s" % l.__class__.__name__   908    909     def com_assign(self, node, assigning):   910         # return a node suitable for use as an "lvalue"   911         # loop to avoid trivial recursion   912         while 1:   913             t = node[0]   914             if t in (symbol["exprlist"], symbol["testlist"], symbol["testlist_safe"], symbol["testlist_comp"]):   915                 if len(node) > 2:   916                     return self.com_assign_tuple(node, assigning)   917                 node = node[1]   918             elif t in _assign_types:   919                 if len(node) > 2:   920                     raise SyntaxError, "can't assign to operator"   921                 node = node[1]   922             elif t == symbol["power"]:   923                 if node[1][0] != symbol["atom"]:   924                     raise SyntaxError, "can't assign to operator"   925                 if len(node) > 2:   926                     primary = self.com_node(node[1])   927                     for i in range(2, len(node)-1):   928                         ch = node[i]   929                         if ch[0] == token["DOUBLESTAR"]:   930                             raise SyntaxError, "can't assign to operator"   931                         primary = self.com_apply_trailer(primary, ch)   932                     return self.com_assign_trailer(primary, node[-1],   933                                                    assigning)   934                 node = node[1]   935             elif t == symbol["atom"]:   936                 t = node[1][0]   937                 if t == token["LPAR"]:   938                     node = node[2]   939                     if node[0] == token["RPAR"]:   940                         raise SyntaxError, "can't assign to ()"   941                 elif t == token["LSQB"]:   942                     node = node[2]   943                     if node[0] == token["RSQB"]:   944                         raise SyntaxError, "can't assign to []"   945                     return self.com_assign_list(node, assigning)   946                 elif t == token["NAME"]:   947                     return self.com_assign_name(node[1], assigning)   948                 else:   949                     raise SyntaxError, "can't assign to literal"   950             else:   951                 raise SyntaxError, "bad assignment (%s)" % t   952    953     def com_assign_tuple(self, node, assigning):   954         assigns = []   955         for i in range(1, len(node), 2):   956             assigns.append(self.com_assign(node[i], assigning))   957         return AssTuple(assigns, lineno=extractLineNo(node))   958    959     def com_assign_list(self, node, assigning):   960         assigns = []   961         for i in range(1, len(node), 2):   962             if i + 1 < len(node):   963                 if node[i + 1][0] == symbol["list_for"]:   964                     raise SyntaxError, "can't assign to list comprehension"   965                 assert node[i + 1][0] == token["COMMA"], node[i + 1]   966             assigns.append(self.com_assign(node[i], assigning))   967         return AssList(assigns, lineno=extractLineNo(node))   968    969     def com_assign_name(self, node, assigning):   970         return AssName(node[1], assigning, lineno=node[2])   971    972     def com_assign_trailer(self, primary, node, assigning):   973         t = node[1][0]   974         if t == token["DOT"]:   975             return self.com_assign_attr(primary, node[2], assigning)   976         if t == token["LSQB"]:   977             return self.com_subscriptlist(primary, node[2], assigning)   978         if t == token["LPAR"]:   979             raise SyntaxError, "can't assign to function call"   980         raise SyntaxError, "unknown trailer type: %s" % t   981    982     def com_assign_attr(self, primary, node, assigning):   983         return AssAttr(primary, node[1], assigning, lineno=node[-1])   984    985     def com_binary(self, constructor, nodelist):   986         "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."   987         l = len(nodelist)   988         if l == 1:   989             n = nodelist[0]   990             return self.lookup_node(n)(n[1:])   991         items = []   992         for i in range(0, l, 2):   993             n = nodelist[i]   994             items.append(self.lookup_node(n)(n[1:]))   995         return constructor(items, lineno=extractLineNo(nodelist))   996    997     def com_stmt(self, node):   998         result = self.lookup_node(node)(node[1:])   999         assert result is not None  1000         if isinstance(result, Stmt):  1001             return result  1002         return Stmt([result])  1003   1004     def com_append_stmt(self, stmts, node):  1005         result = self.lookup_node(node)(node[1:])  1006         assert result is not None  1007         if isinstance(result, Stmt):  1008             stmts.extend(result.nodes)  1009         else:  1010             stmts.append(result)  1011   1012     def com_list_constructor(self, nodelist):  1013         # listmaker: test ( (',' test)* [','] )  1014         values = []  1015         for i in range(1, len(nodelist)):  1016             if nodelist[i][0] == token["COMMA"]:  1017                 continue  1018             values.append(self.com_node(nodelist[i]))  1019         return List(values, lineno=values[0].lineno)  1020   1021     def com_dictorsetmaker(self, nodelist):  1022         # dictorsetmaker: ( (test ':' test ( (',' test ':' test)* [','])) |  1023         #                   (test ( (',' test)* [','])) )  1024         assert nodelist[0] == symbol["dictorsetmaker"]  1025         nodelist = nodelist[1:]  1026         if len(nodelist) == 1 or nodelist[1][0] == token["COMMA"]:  1027             # set literal  1028             items = []  1029             for i in range(0, len(nodelist), 2):  1030                 items.append(self.com_node(nodelist[i]))  1031             return Set(items, lineno=items[0].lineno)  1032         else:  1033             # dict literal  1034             items = []  1035             for i in range(0, len(nodelist), 4):  1036                 items.append((self.com_node(nodelist[i]),  1037                               self.com_node(nodelist[i+2])))  1038             return Dict(items, lineno=items[0][0].lineno)  1039   1040     def com_apply_trailer(self, primaryNode, nodelist):  1041         t = nodelist[1][0]  1042         if t == token["LPAR"]:  1043             return self.com_call_function(primaryNode, nodelist[2])  1044         if t == token["DOT"]:  1045             return self.com_select_member(primaryNode, nodelist[2])  1046         if t == token["LSQB"]:  1047             return self.com_subscriptlist(primaryNode, nodelist[2], OP_APPLY)  1048   1049         raise SyntaxError, 'unknown node type: %s' % t  1050   1051     def com_select_member(self, primaryNode, nodelist):  1052         if nodelist[0] != token["NAME"]:  1053             raise SyntaxError, "member must be a name"  1054         return Getattr(primaryNode, nodelist[1], lineno=nodelist[2])  1055   1056     def com_call_function(self, primaryNode, nodelist):  1057         if nodelist[0] == token["RPAR"]:  1058             return CallFunc(primaryNode, [], lineno=extractLineNo(nodelist))  1059         args = []  1060         kw = 0  1061         star_node = dstar_node = None  1062         len_nodelist = len(nodelist)  1063         i = 1  1064         while i < len_nodelist:  1065             node = nodelist[i]  1066   1067             if node[0]==token["STAR"]:  1068                 if star_node is not None:  1069                     raise SyntaxError, 'already have the varargs indentifier'  1070                 star_node = self.com_node(nodelist[i+1])  1071                 i = i + 3  1072                 continue  1073             elif node[0]==token["DOUBLESTAR"]:  1074                 if dstar_node is not None:  1075                     raise SyntaxError, 'already have the kwargs indentifier'  1076                 dstar_node = self.com_node(nodelist[i+1])  1077                 i = i + 3  1078                 continue  1079   1080             # positional or named parameters  1081             kw, result = self.com_argument(node, kw, star_node)  1082   1083             args.append(result)  1084             i = i + 2  1085   1086         return CallFunc(primaryNode, args, star_node, dstar_node,  1087                         lineno=extractLineNo(nodelist))  1088   1089     def com_argument(self, nodelist, kw, star_node):  1090         if len(nodelist) == 2:  1091             if kw:  1092                 raise SyntaxError, "non-keyword arg after keyword arg"  1093             if star_node:  1094                 raise SyntaxError, "only named arguments may follow *expression"  1095             return 0, self.com_node(nodelist[1])  1096         result = self.com_node(nodelist[3])  1097         n = nodelist[1]  1098         while len(n) == 2 and n[0] != token["NAME"]:  1099             n = n[1]  1100         if n[0] != token["NAME"]:  1101             raise SyntaxError, "keyword can't be an expression (%s)"%n[0]  1102         node = Keyword(n[1], result, lineno=n[2])  1103         return 1, node  1104   1105     def com_subscriptlist(self, primary, nodelist, assigning):  1106         # slicing:      simple_slicing | extended_slicing  1107         # simple_slicing:   primary "[" short_slice "]"  1108         # extended_slicing: primary "[" slice_list "]"  1109         # slice_list:   slice_item ("," slice_item)* [","]  1110   1111         # backwards compat slice for '[i:j]'  1112         if len(nodelist) == 2:  1113             sub = nodelist[1]  1114             if (sub[1][0] == token["COLON"] or \  1115                             (len(sub) > 2 and sub[2][0] == token["COLON"])) and \  1116                             sub[-1][0] != symbol["sliceop"]:  1117                 return self.com_slice(primary, sub, assigning)  1118   1119         subscripts = []  1120         for i in range(1, len(nodelist), 2):  1121             subscripts.append(self.com_subscript(nodelist[i]))  1122         return Subscript(primary, assigning, subscripts,  1123                          lineno=extractLineNo(nodelist))  1124   1125     def com_subscript(self, node):  1126         # slice_item: expression | proper_slice | ellipsis  1127         ch = node[1]  1128         t = ch[0]  1129         if t == token["DOT"] and node[2][0] == token["DOT"]:  1130             return Ellipsis()  1131         if t == token["COLON"] or len(node) > 2:  1132             return self.com_sliceobj(node)  1133         return self.com_node(ch)  1134   1135     def com_sliceobj(self, node):  1136         # proper_slice: short_slice | long_slice  1137         # short_slice:  [lower_bound] ":" [upper_bound]  1138         # long_slice:   short_slice ":" [stride]  1139         # lower_bound:  expression  1140         # upper_bound:  expression  1141         # stride:       expression  1142         #  1143         # Note: a stride may be further slicing...  1144   1145         items = []  1146   1147         if node[1][0] == token["COLON"]:  1148             items.append(Const(None))  1149             i = 2  1150         else:  1151             items.append(self.com_node(node[1]))  1152             # i == 2 is a COLON  1153             i = 3  1154   1155         if i < len(node) and node[i][0] == symbol["test"]:  1156             items.append(self.com_node(node[i]))  1157             i = i + 1  1158         else:  1159             items.append(Const(None))  1160   1161         # a short_slice has been built. look for long_slice now by looking  1162         # for strides...  1163         for j in range(i, len(node)):  1164             ch = node[j]  1165             if len(ch) == 2:  1166                 items.append(Const(None))  1167             else:  1168                 items.append(self.com_node(ch[2]))  1169         return Sliceobj(items, lineno=extractLineNo(node))  1170   1171     def com_slice(self, primary, node, assigning):  1172         # short_slice:  [lower_bound] ":" [upper_bound]  1173         lower = upper = None  1174         if len(node) == 3:  1175             if node[1][0] == token["COLON"]:  1176                 upper = self.com_node(node[2])  1177             else:  1178                 lower = self.com_node(node[1])  1179         elif len(node) == 4:  1180             lower = self.com_node(node[1])  1181             upper = self.com_node(node[3])  1182         return Slice(primary, assigning, lower, upper,  1183                      lineno=extractLineNo(node))  1184   1185     def get_docstring(self, node, n=None):  1186         if n is None:  1187             n = node[0]  1188             node = node[1:]  1189         if n == symbol["suite"]:  1190             if len(node) == 1:  1191                 return self.get_docstring(node[0])  1192             for sub in node:  1193                 if sub[0] == symbol["stmt"]:  1194                     return self.get_docstring(sub)  1195             return None  1196         if n == symbol["file_input"]:  1197             for sub in node:  1198                 if sub[0] == symbol["stmt"]:  1199                     return self.get_docstring(sub)  1200             return None  1201         if n == symbol["atom"]:  1202             if node[0][0] == token["STRING"]:  1203                 s = ''  1204                 for t in node:  1205                     s = s + eval(t[1])  1206                 return s  1207             return None  1208         if n == symbol["stmt"] or n == symbol["simple_stmt"] \  1209            or n == symbol["small_stmt"]:  1210             return self.get_docstring(node[0])  1211         if n in _doc_nodes and len(node) == 1:  1212             return self.get_docstring(node[0])  1213         return None  1214   1215   1216 _doc_nodes = [  1217     symbol["expr_stmt"],  1218     symbol["testlist"],  1219     symbol["testlist_safe"],  1220     symbol["test"],  1221     symbol["or_test"],  1222     symbol["and_test"],  1223     symbol["not_test"],  1224     symbol["comparison"],  1225     symbol["expr"],  1226     symbol["xor_expr"],  1227     symbol["and_expr"],  1228     symbol["shift_expr"],  1229     symbol["arith_expr"],  1230     symbol["term"],  1231     symbol["factor"],  1232     symbol["power"],  1233     ]  1234   1235 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='  1236 #             | 'in' | 'not' 'in' | 'is' | 'is' 'not'  1237 _cmp_types = {  1238     token["LESS"] : '<',  1239     token["GREATER"] : '>',  1240     token["EQEQUAL"] : '==',  1241     token["EQUAL"] : '==',  1242     token["LESSEQUAL"] : '<=',  1243     token["GREATEREQUAL"] : '>=',  1244     token["NOTEQUAL"] : '!=',  1245     }  1246   1247 _legal_node_types = [  1248     symbol["funcdef"],  1249     symbol["classdef"],  1250     symbol["stmt"],  1251     symbol["small_stmt"],  1252     symbol["flow_stmt"],  1253     symbol["simple_stmt"],  1254     symbol["compound_stmt"],  1255     symbol["expr_stmt"],  1256     symbol["print_stmt"],  1257     symbol["del_stmt"],  1258     symbol["pass_stmt"],  1259     symbol["break_stmt"],  1260     symbol["continue_stmt"],  1261     symbol["return_stmt"],  1262     symbol["raise_stmt"],  1263     symbol["import_stmt"],  1264     symbol["global_stmt"],  1265     symbol["exec_stmt"],  1266     symbol["assert_stmt"],  1267     symbol["if_stmt"],  1268     symbol["while_stmt"],  1269     symbol["for_stmt"],  1270     symbol["try_stmt"],  1271     symbol["with_stmt"],  1272     symbol["suite"],  1273     symbol["testlist"],  1274     symbol["testlist_safe"],  1275     symbol["test"],  1276     symbol["and_test"],  1277     symbol["not_test"],  1278     symbol["comparison"],  1279     symbol["exprlist"],  1280     symbol["expr"],  1281     symbol["xor_expr"],  1282     symbol["and_expr"],  1283     symbol["shift_expr"],  1284     symbol["arith_expr"],  1285     symbol["term"],  1286     symbol["factor"],  1287     symbol["power"],  1288     symbol["atom"],  1289     ]  1290   1291 _assign_types = [  1292     symbol["test"],  1293     symbol["or_test"],  1294     symbol["and_test"],  1295     symbol["not_test"],  1296     symbol["comparison"],  1297     symbol["expr"],  1298     symbol["xor_expr"],  1299     symbol["and_expr"],  1300     symbol["shift_expr"],  1301     symbol["arith_expr"],  1302     symbol["term"],  1303     symbol["factor"],  1304     ]  1305   1306 _names = {}  1307 for k, v in sym_name.items():  1308     _names[k] = v  1309 for k, v in tok_name.items():  1310     _names[k] = v  1311   1312 def debug_tree(tree):  1313     l = []  1314     for elt in tree:  1315         if isinstance(elt, int):  1316             l.append(_names.get(elt, elt))  1317         elif isinstance(elt, str):  1318             l.append(elt)  1319         else:  1320             l.append(debug_tree(elt))  1321     return l