Lichen

compiler/transformer.py

612:97ec110d65cf
2017-02-23 Paul Boddie Added a "reset all" option removing the data directory. Added option synonyms. 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