1 """Parse tree transformation module.
3 Transforms Python source code into an abstract syntax tree (AST)
4 defined in the ast module.
6 The simplest ways to invoke this module are via parse and parseFile.
11 # Original version written by Greg Stein (gstein@lyra.org)
12 # and Bill Tutt (rassilon@lima.mudlib.org)
15 # Modifications and improvements for Python 2.0 by Jeremy Hylton and
18 # Portions of this file are:
19 # Copyright (C) 1997-1998 Greg Stein. All Rights Reserved.
21 # This module is provided under a BSD-ish license. See
22 # http://www.opensource.org/licenses/bsd-license.html
23 # and replace OWNER, ORGANIZATION, and YEAR as appropriate.
27 # Care must be taken to use only symbols and tokens defined in Python
28 # 1.5.2 for code branches executed in 1.5.2
33 error
= 'walker.error'
35 from consts
import CO_VARARGS
, CO_VARKEYWORDS
36 from consts
import OP_ASSIGN
, OP_DELETE
, OP_APPLY
44 def parse(buf
, mode
="exec"):
45 if mode
== "exec" or mode
== "single":
46 return Transformer().parsesuite(buf
)
48 return Transformer().parseexpr(buf
)
50 raise ValueError("compile() arg 3 must be"
51 " 'exec' or 'eval' or 'single'")
56 if hasattr(item
, "asList"):
57 l
.append(item
.asList())
59 if type(item
) is type( (None, None) ):
60 l
.append(tuple(asList(item
)))
61 elif type(item
) is type( [] ):
62 l
.append(asList(item
))
69 if nodes
.has_key(kind
):
71 return apply(nodes
[kind
], args
[1:])
73 print nodes
[kind
], len(args
), args
76 raise error
, "Can't find appropriate Node type: %s" % str(args
)
77 #return apply(ast.Node, args)
80 """Utility object for transforming Python parse trees.
82 Exposes the following methods:
83 tree = transform(ast_tree)
84 tree = parsesuite(text)
85 tree = parseexpr(text)
86 tree = parsefile(fileob | filename)
91 for value
, name
in symbol
.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
,
104 def transform(self
, tree
):
105 """Transform an AST into a modified parse tree."""
106 if type(tree
) != type(()) and type(tree
) != type([]):
107 tree
= parser
.ast2tuple(tree
, line_info
=1)
108 return self
.compile_node(tree
)
110 def parsesuite(self
, text
):
111 """Return a modified parse tree for the given suite text."""
112 # Hack for handling non-native line endings on non-DOS like OSs.
113 text
= text
.replace('\x0d', '')
114 return self
.transform(parser
.suite(text
))
116 def parseexpr(self
, text
):
117 """Return a modified parse tree for the given expression text."""
118 return self
.transform(parser
.expr(text
))
120 def parsefile(self
, file):
121 """Return a modified parse tree for the contents of the given file."""
122 if type(file) == type(''):
124 return self
.parsesuite(file.read())
126 # --------------------------------------------------------------
131 def compile_node(self
, node
):
132 ### emit a line-number node?
134 if n
== symbol
.single_input
:
135 return self
.single_input(node
[1:])
136 if n
== symbol
.file_input
:
137 return self
.file_input(node
[1:])
138 if n
== symbol
.eval_input
:
139 return self
.eval_input(node
[1:])
140 if n
== symbol
.lambdef
:
141 return self
.lambdef(node
[1:])
142 if n
== symbol
.funcdef
:
143 return self
.funcdef(node
[1:])
144 if n
== symbol
.classdef
:
145 return self
.classdef(node
[1:])
147 raise error
, ('unexpected node type', n
)
149 def single_input(self
, node
):
150 ### do we want to do anything about being "interactive" ?
152 # NEWLINE | simple_stmt | compound_stmt NEWLINE
154 if n
!= token
.NEWLINE
:
155 return self
.com_stmt(node
[0])
159 def file_input(self
, nodelist
):
160 doc
= self
.get_docstring(nodelist
, symbol
.file_input
)
166 for node
in nodelist
[i
:]:
167 if node
[0] != token
.ENDMARKER
and node
[0] != token
.NEWLINE
:
168 self
.com_append_stmt(stmts
, node
)
169 return Module(doc
, Stmt(stmts
))
171 def eval_input(self
, nodelist
):
172 # from the built-in function input()
173 ### is this sufficient?
174 return Expression(self
.com_node(nodelist
[0]))
176 def funcdef(self
, nodelist
):
177 # funcdef: 'def' NAME parameters ':' suite
178 # parameters: '(' [varargslist] ')'
180 lineno
= nodelist
[1][2]
181 name
= nodelist
[1][1]
182 args
= nodelist
[2][2]
184 if args
[0] == symbol
.varargslist
:
185 names
, defaults
, flags
= self
.com_arglist(args
[1:])
187 names
= defaults
= ()
189 doc
= self
.get_docstring(nodelist
[4])
192 code
= self
.com_node(nodelist
[4])
195 assert isinstance(code
, Stmt
)
196 assert isinstance(code
.nodes
[0], Discard
)
198 n
= Function(name
, names
, defaults
, flags
, doc
, code
)
202 def lambdef(self
, nodelist
):
203 # lambdef: 'lambda' [varargslist] ':' test
204 if nodelist
[2][0] == symbol
.varargslist
:
205 names
, defaults
, flags
= self
.com_arglist(nodelist
[2][1:])
207 names
= defaults
= ()
211 code
= self
.com_node(nodelist
[-1])
213 n
= Lambda(names
, defaults
, flags
, code
)
214 n
.lineno
= nodelist
[1][2]
217 def classdef(self
, nodelist
):
218 # classdef: 'class' NAME ['(' testlist ')'] ':' suite
220 name
= nodelist
[1][1]
221 doc
= self
.get_docstring(nodelist
[-1])
222 if nodelist
[2][0] == token
.COLON
:
225 bases
= self
.com_bases(nodelist
[3])
228 code
= self
.com_node(nodelist
[-1])
231 assert isinstance(code
, Stmt
)
232 assert isinstance(code
.nodes
[0], Discard
)
235 n
= Class(name
, bases
, doc
, code
)
236 n
.lineno
= nodelist
[1][2]
239 def stmt(self
, nodelist
):
240 return self
.com_stmt(nodelist
[0])
246 def simple_stmt(self
, nodelist
):
247 # small_stmt (';' small_stmt)* [';'] NEWLINE
249 for i
in range(0, len(nodelist
), 2):
250 self
.com_append_stmt(stmts
, nodelist
[i
])
253 def parameters(self
, nodelist
):
256 def varargslist(self
, nodelist
):
259 def fpdef(self
, nodelist
):
262 def fplist(self
, nodelist
):
265 def dotted_name(self
, nodelist
):
268 def comp_op(self
, nodelist
):
271 def trailer(self
, nodelist
):
274 def sliceop(self
, nodelist
):
277 def argument(self
, nodelist
):
280 # --------------------------------------------------------------
282 # STATEMENT NODES (invoked by com_node())
285 def expr_stmt(self
, nodelist
):
286 # augassign testlist | testlist ('=' testlist)*
288 exprNode
= self
.lookup_node(en
)(en
[1:])
289 if len(nodelist
) == 1:
290 n
= Discard(exprNode
)
291 n
.lineno
= exprNode
.lineno
293 if nodelist
[1][0] == token
.EQUAL
:
295 for i
in range(0, len(nodelist
) - 2, 2):
296 nodesl
.append(self
.com_assign(nodelist
[i
], OP_ASSIGN
))
297 n
= Assign(nodesl
, exprNode
)
298 n
.lineno
= nodelist
[1][2]
300 lval
= self
.com_augassign(nodelist
[0])
301 op
= self
.com_augassign_op(nodelist
[1])
302 n
= AugAssign(lval
, op
[1], exprNode
)
306 def print_stmt(self
, nodelist
):
307 # print ([ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ])
309 if len(nodelist
) == 1:
312 elif nodelist
[1][0] == token
.RIGHTSHIFT
:
313 assert len(nodelist
) == 3 \
314 or nodelist
[3][0] == token
.COMMA
315 dest
= self
.com_node(nodelist
[2])
320 for i
in range(start
, len(nodelist
), 2):
321 items
.append(self
.com_node(nodelist
[i
]))
322 if nodelist
[-1][0] == token
.COMMA
:
323 n
= Print(items
, dest
)
324 n
.lineno
= nodelist
[0][2]
326 n
= Printnl(items
, dest
)
327 n
.lineno
= nodelist
[0][2]
330 def del_stmt(self
, nodelist
):
331 return self
.com_assign(nodelist
[1], OP_DELETE
)
333 def pass_stmt(self
, nodelist
):
335 n
.lineno
= nodelist
[0][2]
338 def break_stmt(self
, nodelist
):
340 n
.lineno
= nodelist
[0][2]
343 def continue_stmt(self
, nodelist
):
345 n
.lineno
= nodelist
[0][2]
348 def return_stmt(self
, nodelist
):
350 if len(nodelist
) < 2:
351 n
= Return(Const(None))
352 n
.lineno
= nodelist
[0][2]
354 n
= Return(self
.com_node(nodelist
[1]))
355 n
.lineno
= nodelist
[0][2]
358 def yield_stmt(self
, nodelist
):
359 n
= Yield(self
.com_node(nodelist
[1]))
360 n
.lineno
= nodelist
[0][2]
363 def raise_stmt(self
, nodelist
):
364 # raise: [test [',' test [',' test]]]
365 if len(nodelist
) > 5:
366 expr3
= self
.com_node(nodelist
[5])
369 if len(nodelist
) > 3:
370 expr2
= self
.com_node(nodelist
[3])
373 if len(nodelist
) > 1:
374 expr1
= self
.com_node(nodelist
[1])
377 n
= Raise(expr1
, expr2
, expr3
)
378 n
.lineno
= nodelist
[0][2]
381 def import_stmt(self
, nodelist
):
382 # import_stmt: 'import' dotted_as_name (',' dotted_as_name)* |
383 # from: 'from' dotted_name 'import'
384 # ('*' | import_as_name (',' import_as_name)*)
385 if nodelist
[0][1] == 'from':
387 if nodelist
[3][0] == token
.NAME
:
388 for i
in range(3, len(nodelist
), 2):
389 names
.append((nodelist
[i
][1], None))
391 for i
in range(3, len(nodelist
), 2):
392 names
.append(self
.com_import_as_name(nodelist
[i
]))
393 n
= From(self
.com_dotted_name(nodelist
[1]), names
)
394 n
.lineno
= nodelist
[0][2]
397 if nodelist
[1][0] == symbol
.dotted_name
:
398 names
= [(self
.com_dotted_name(nodelist
[1][1:]), None)]
401 for i
in range(1, len(nodelist
), 2):
402 names
.append(self
.com_dotted_as_name(nodelist
[i
]))
404 n
.lineno
= nodelist
[0][2]
407 def global_stmt(self
, nodelist
):
408 # global: NAME (',' NAME)*
410 for i
in range(1, len(nodelist
), 2):
411 names
.append(nodelist
[i
][1])
413 n
.lineno
= nodelist
[0][2]
416 def exec_stmt(self
, nodelist
):
417 # exec_stmt: 'exec' expr ['in' expr [',' expr]]
418 expr1
= self
.com_node(nodelist
[1])
419 if len(nodelist
) >= 4:
420 expr2
= self
.com_node(nodelist
[3])
421 if len(nodelist
) >= 6:
422 expr3
= self
.com_node(nodelist
[5])
428 n
= Exec(expr1
, expr2
, expr3
)
429 n
.lineno
= nodelist
[0][2]
432 def assert_stmt(self
, nodelist
):
433 # 'assert': test, [',' test]
434 expr1
= self
.com_node(nodelist
[1])
435 if (len(nodelist
) == 4):
436 expr2
= self
.com_node(nodelist
[3])
439 n
= Assert(expr1
, expr2
)
440 n
.lineno
= nodelist
[0][2]
443 def if_stmt(self
, nodelist
):
444 # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
446 for i
in range(0, len(nodelist
) - 3, 4):
447 testNode
= self
.com_node(nodelist
[i
+ 1])
448 suiteNode
= self
.com_node(nodelist
[i
+ 3])
449 tests
.append((testNode
, suiteNode
))
451 if len(nodelist
) % 4 == 3:
452 elseNode
= self
.com_node(nodelist
[-1])
453 ## elseNode.lineno = nodelist[-1][1][2]
456 n
= If(tests
, elseNode
)
457 n
.lineno
= nodelist
[0][2]
460 def while_stmt(self
, nodelist
):
461 # 'while' test ':' suite ['else' ':' suite]
463 testNode
= self
.com_node(nodelist
[1])
464 bodyNode
= self
.com_node(nodelist
[3])
466 if len(nodelist
) > 4:
467 elseNode
= self
.com_node(nodelist
[6])
471 n
= While(testNode
, bodyNode
, elseNode
)
472 n
.lineno
= nodelist
[0][2]
475 def for_stmt(self
, nodelist
):
476 # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
478 assignNode
= self
.com_assign(nodelist
[1], OP_ASSIGN
)
479 listNode
= self
.com_node(nodelist
[3])
480 bodyNode
= self
.com_node(nodelist
[5])
482 if len(nodelist
) > 8:
483 elseNode
= self
.com_node(nodelist
[8])
487 n
= For(assignNode
, listNode
, bodyNode
, elseNode
)
488 n
.lineno
= nodelist
[0][2]
491 def try_stmt(self
, nodelist
):
492 # 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
493 # | 'try' ':' suite 'finally' ':' suite
494 if nodelist
[3][0] != symbol
.except_clause
:
495 return self
.com_try_finally(nodelist
)
497 return self
.com_try_except(nodelist
)
499 def suite(self
, nodelist
):
500 # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
501 if len(nodelist
) == 1:
502 return self
.com_stmt(nodelist
[0])
505 for node
in nodelist
:
506 if node
[0] == symbol
.stmt
:
507 self
.com_append_stmt(stmts
, node
)
510 # --------------------------------------------------------------
512 # EXPRESSION NODES (invoked by com_node())
515 def testlist(self
, nodelist
):
516 # testlist: expr (',' expr)* [',']
517 # testlist_safe: test [(',' test)+ [',']]
518 # exprlist: expr (',' expr)* [',']
519 return self
.com_binary(Tuple
, nodelist
)
521 testlist_safe
= testlist
# XXX
524 def test(self
, nodelist
):
525 # and_test ('or' and_test)* | lambdef
526 if len(nodelist
) == 1 and nodelist
[0][0] == symbol
.lambdef
:
527 return self
.lambdef(nodelist
[0])
528 return self
.com_binary(Or
, nodelist
)
530 def and_test(self
, nodelist
):
531 # not_test ('and' not_test)*
532 return self
.com_binary(And
, nodelist
)
534 def not_test(self
, nodelist
):
535 # 'not' not_test | comparison
536 result
= self
.com_node(nodelist
[-1])
537 if len(nodelist
) == 2:
539 n
.lineno
= nodelist
[0][2]
543 def comparison(self
, nodelist
):
544 # comparison: expr (comp_op expr)*
545 node
= self
.com_node(nodelist
[0])
546 if len(nodelist
) == 1:
550 for i
in range(2, len(nodelist
), 2):
553 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
554 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
556 if n
[0] == token
.NAME
:
564 type = _cmp_types
[n
[0]]
567 results
.append((type, self
.com_node(nodelist
[i
])))
569 # we need a special "compare" node so that we can distinguish
570 # 3 < x < 5 from (3 < x) < 5
571 # the two have very different semantics and results (note that the
572 # latter form is always true)
574 n
= Compare(node
, results
)
578 def expr(self
, nodelist
):
579 # xor_expr ('|' xor_expr)*
580 return self
.com_binary(Bitor
, nodelist
)
582 def xor_expr(self
, nodelist
):
583 # xor_expr ('^' xor_expr)*
584 return self
.com_binary(Bitxor
, nodelist
)
586 def and_expr(self
, nodelist
):
587 # xor_expr ('&' xor_expr)*
588 return self
.com_binary(Bitand
, nodelist
)
590 def shift_expr(self
, nodelist
):
591 # shift_expr ('<<'|'>>' shift_expr)*
592 node
= self
.com_node(nodelist
[0])
593 for i
in range(2, len(nodelist
), 2):
594 right
= self
.com_node(nodelist
[i
])
595 if nodelist
[i
-1][0] == token
.LEFTSHIFT
:
596 node
= LeftShift([node
, right
])
597 node
.lineno
= nodelist
[1][2]
598 elif nodelist
[i
-1][0] == token
.RIGHTSHIFT
:
599 node
= RightShift([node
, right
])
600 node
.lineno
= nodelist
[1][2]
602 raise ValueError, "unexpected token: %s" % nodelist
[i
-1][0]
605 def arith_expr(self
, nodelist
):
606 node
= self
.com_node(nodelist
[0])
607 for i
in range(2, len(nodelist
), 2):
608 right
= self
.com_node(nodelist
[i
])
609 if nodelist
[i
-1][0] == token
.PLUS
:
610 node
= Add([node
, right
])
611 node
.lineno
= nodelist
[1][2]
612 elif nodelist
[i
-1][0] == token
.MINUS
:
613 node
= Sub([node
, right
])
614 node
.lineno
= nodelist
[1][2]
616 raise ValueError, "unexpected token: %s" % nodelist
[i
-1][0]
619 def term(self
, nodelist
):
620 node
= self
.com_node(nodelist
[0])
621 for i
in range(2, len(nodelist
), 2):
622 right
= self
.com_node(nodelist
[i
])
625 node
= Mul([node
, right
])
626 elif t
== token
.SLASH
:
627 node
= Div([node
, right
])
628 elif t
== token
.PERCENT
:
629 node
= Mod([node
, right
])
630 elif t
== token
.DOUBLESLASH
:
631 node
= FloorDiv([node
, right
])
633 raise ValueError, "unexpected token: %s" % t
634 node
.lineno
= nodelist
[1][2]
637 def factor(self
, nodelist
):
640 node
= self
.com_node(nodelist
[-1])
642 node
= UnaryAdd(node
)
644 elif t
== token
.MINUS
:
645 node
= UnarySub(node
)
647 elif t
== token
.TILDE
:
652 def power(self
, nodelist
):
653 # power: atom trailer* ('**' factor)*
654 node
= self
.com_node(nodelist
[0])
655 for i
in range(1, len(nodelist
)):
657 if elt
[0] == token
.DOUBLESTAR
:
658 n
= Power([node
, self
.com_node(nodelist
[i
+1])])
662 node
= self
.com_apply_trailer(node
, elt
)
666 def atom(self
, nodelist
):
667 n
= self
._atom
_dispatch
[nodelist
[0][0]](nodelist
)
668 n
.lineno
= nodelist
[0][2]
671 def atom_lpar(self
, nodelist
):
672 if nodelist
[1][0] == token
.RPAR
:
674 n
.lineno
= nodelist
[0][2]
676 return self
.com_node(nodelist
[1])
678 def atom_lsqb(self
, nodelist
):
679 if nodelist
[1][0] == token
.RSQB
:
681 n
.lineno
= nodelist
[0][2]
683 return self
.com_list_constructor(nodelist
[1])
685 def atom_lbrace(self
, nodelist
):
686 if nodelist
[1][0] == token
.RBRACE
:
688 return self
.com_dictmaker(nodelist
[1])
690 def atom_backquote(self
, nodelist
):
691 n
= Backquote(self
.com_node(nodelist
[1]))
692 n
.lineno
= nodelist
[0][2]
695 def atom_number(self
, nodelist
):
696 ### need to verify this matches compile.c
697 k
= eval(nodelist
[0][1])
699 n
.lineno
= nodelist
[0][2]
702 def atom_string(self
, nodelist
):
703 ### need to verify this matches compile.c
705 for node
in nodelist
:
706 k
= k
+ eval(node
[1])
708 n
.lineno
= nodelist
[0][2]
711 def atom_name(self
, nodelist
):
712 ### any processing to do?
713 n
= Name(nodelist
[0][1])
714 n
.lineno
= nodelist
[0][2]
717 # --------------------------------------------------------------
719 # INTERNAL PARSING UTILITIES
722 # The use of com_node() introduces a lot of extra stack frames,
723 # enough to cause a stack overflow compiling test.test_parser with
724 # the standard interpreter recursionlimit. The com_node() is a
725 # convenience function that hides the dispatch details, but comes
726 # at a very high cost. It is more efficient to dispatch directly
727 # in the callers. In these cases, use lookup_node() and call the
728 # dispatched node directly.
730 def lookup_node(self
, node
):
731 return self
._dispatch
[node
[0]]
733 def com_node(self
, node
):
734 # Note: compile.c has handling in com_node for del_stmt, pass_stmt,
735 # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
737 # We'll just dispatch them.
738 return self
._dispatch
[node
[0]](node
[1:])
740 def com_NEWLINE(self
, *args
):
741 # A ';' at the end of a line can make a NEWLINE token appear
742 # here, Render it harmless. (genc discards ('discard',
743 # ('const', xxxx)) Nodes)
744 return Discard(Const(None))
746 def com_arglist(self
, nodelist
):
748 # (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME)
749 # | fpdef ['=' test] (',' fpdef ['=' test])* [',']
750 # fpdef: NAME | '(' fplist ')'
751 # fplist: fpdef (',' fpdef)* [',']
757 while i
< len(nodelist
):
759 if node
[0] == token
.STAR
or node
[0] == token
.DOUBLESTAR
:
760 if node
[0] == token
.STAR
:
762 if node
[0] == token
.NAME
:
763 names
.append(node
[1])
764 flags
= flags | CO_VARARGS
767 if i
< len(nodelist
):
768 # should be DOUBLESTAR
770 if t
== token
.DOUBLESTAR
:
773 raise ValueError, "unexpected token: %s" % t
774 names
.append(node
[1])
775 flags
= flags | CO_VARKEYWORDS
779 # fpdef: NAME | '(' fplist ')'
780 names
.append(self
.com_fpdef(node
))
783 if i
>= len(nodelist
):
786 if nodelist
[i
][0] == token
.EQUAL
:
787 defaults
.append(self
.com_node(nodelist
[i
+ 1]))
790 # Treat "(a=1, b)" as "(a=1, b=None)"
791 defaults
.append(Const(None))
795 return names
, defaults
, flags
797 def com_fpdef(self
, node
):
798 # fpdef: NAME | '(' fplist ')'
799 if node
[1][0] == token
.LPAR
:
800 return self
.com_fplist(node
[2])
803 def com_fplist(self
, node
):
804 # fplist: fpdef (',' fpdef)* [',']
806 return self
.com_fpdef(node
[1])
808 for i
in range(1, len(node
), 2):
809 list.append(self
.com_fpdef(node
[i
]))
812 def com_dotted_name(self
, node
):
813 # String together the dotted names and return the string
816 if type(n
) == type(()) and n
[0] == 1:
817 name
= name
+ n
[1] + '.'
820 def com_dotted_as_name(self
, node
):
821 dot
= self
.com_dotted_name(node
[1])
824 if node
[0] == symbol
.dotted_name
:
827 assert node
[2][1] == 'as'
828 assert node
[3][0] == token
.NAME
829 return dot
, node
[3][1]
831 def com_import_as_name(self
, node
):
832 if node
[0] == token
.STAR
:
834 assert node
[0] == symbol
.import_as_name
837 assert node
[0][0] == token
.NAME
838 return node
[0][1], None
840 assert node
[1][1] == 'as', node
841 assert node
[2][0] == token
.NAME
842 return node
[0][1], node
[2][1]
844 def com_bases(self
, node
):
846 for i
in range(1, len(node
), 2):
847 bases
.append(self
.com_node(node
[i
]))
850 def com_try_finally(self
, nodelist
):
851 # try_fin_stmt: "try" ":" suite "finally" ":" suite
852 n
= TryFinally(self
.com_node(nodelist
[2]),
853 self
.com_node(nodelist
[5]))
854 n
.lineno
= nodelist
[0][2]
857 def com_try_except(self
, nodelist
):
858 # try_except: 'try' ':' suite (except_clause ':' suite)* ['else' suite]
859 #tryexcept: [TryNode, [except_clauses], elseNode)]
860 stmt
= self
.com_node(nodelist
[2])
863 for i
in range(3, len(nodelist
), 3):
865 if node
[0] == symbol
.except_clause
:
866 # except_clause: 'except' [expr [',' expr]] */
868 expr1
= self
.com_node(node
[2])
870 expr2
= self
.com_assign(node
[4], OP_ASSIGN
)
875 clauses
.append((expr1
, expr2
, self
.com_node(nodelist
[i
+2])))
877 if node
[0] == token
.NAME
:
878 elseNode
= self
.com_node(nodelist
[i
+2])
879 n
= TryExcept(self
.com_node(nodelist
[2]), clauses
, elseNode
)
880 n
.lineno
= nodelist
[0][2]
883 def com_augassign_op(self
, node
):
884 assert node
[0] == symbol
.augassign
887 def com_augassign(self
, node
):
888 """Return node suitable for lvalue of augmented assignment
890 Names, slices, and attributes are the only allowable nodes.
892 l
= self
.com_node(node
)
893 if l
.__class
__ in (Name
, Slice
, Subscript
, Getattr
):
895 raise SyntaxError, "can't assign to %s" % l
.__class
__.__name
__
897 def com_assign(self
, node
, assigning
):
898 # return a node suitable for use as an "lvalue"
899 # loop to avoid trivial recursion
902 if t
== symbol
.exprlist
or t
== symbol
.testlist
:
904 return self
.com_assign_tuple(node
, assigning
)
906 elif t
in _assign_types
:
908 raise SyntaxError, "can't assign to operator"
910 elif t
== symbol
.power
:
911 if node
[1][0] != symbol
.atom
:
912 raise SyntaxError, "can't assign to operator"
914 primary
= self
.com_node(node
[1])
915 for i
in range(2, len(node
)-1):
917 if ch
[0] == token
.DOUBLESTAR
:
918 raise SyntaxError, "can't assign to operator"
919 primary
= self
.com_apply_trailer(primary
, ch
)
920 return self
.com_assign_trailer(primary
, node
[-1],
923 elif t
== symbol
.atom
:
927 if node
[0] == token
.RPAR
:
928 raise SyntaxError, "can't assign to ()"
929 elif t
== token
.LSQB
:
931 if node
[0] == token
.RSQB
:
932 raise SyntaxError, "can't assign to []"
933 return self
.com_assign_list(node
, assigning
)
934 elif t
== token
.NAME
:
935 return self
.com_assign_name(node
[1], assigning
)
937 raise SyntaxError, "can't assign to literal"
939 raise SyntaxError, "bad assignment"
941 def com_assign_tuple(self
, node
, assigning
):
943 for i
in range(1, len(node
), 2):
944 assigns
.append(self
.com_assign(node
[i
], assigning
))
945 return AssTuple(assigns
)
947 def com_assign_list(self
, node
, assigning
):
949 for i
in range(1, len(node
), 2):
950 if i
+ 1 < len(node
):
951 if node
[i
+ 1][0] == symbol
.list_for
:
952 raise SyntaxError, "can't assign to list comprehension"
953 assert node
[i
+ 1][0] == token
.COMMA
, node
[i
+ 1]
954 assigns
.append(self
.com_assign(node
[i
], assigning
))
955 return AssList(assigns
)
957 def com_assign_name(self
, node
, assigning
):
958 n
= AssName(node
[1], assigning
)
962 def com_assign_trailer(self
, primary
, node
, assigning
):
965 return self
.com_assign_attr(primary
, node
[2], assigning
)
967 return self
.com_subscriptlist(primary
, node
[2], assigning
)
969 raise SyntaxError, "can't assign to function call"
970 raise SyntaxError, "unknown trailer type: %s" % t
972 def com_assign_attr(self
, primary
, node
, assigning
):
973 return AssAttr(primary
, node
[1], assigning
)
975 def com_binary(self
, constructor
, nodelist
):
976 "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
980 return self
.lookup_node(n
)(n
[1:])
982 for i
in range(0, l
, 2):
984 items
.append(self
.lookup_node(n
)(n
[1:]))
985 return constructor(items
)
987 def com_stmt(self
, node
):
988 result
= self
.lookup_node(node
)(node
[1:])
989 assert result
is not None
990 if isinstance(result
, Stmt
):
992 return Stmt([result
])
994 def com_append_stmt(self
, stmts
, node
):
995 result
= self
.com_node(node
)
996 assert result
is not None
997 if isinstance(result
, Stmt
):
998 stmts
.extend(result
.nodes
)
1000 stmts
.append(result
)
1002 if hasattr(symbol
, 'list_for'):
1003 def com_list_constructor(self
, nodelist
):
1004 # listmaker: test ( list_for | (',' test)* [','] )
1006 for i
in range(1, len(nodelist
)):
1007 if nodelist
[i
][0] == symbol
.list_for
:
1008 assert len(nodelist
[i
:]) == 1
1009 return self
.com_list_comprehension(values
[0],
1011 elif nodelist
[i
][0] == token
.COMMA
:
1013 values
.append(self
.com_node(nodelist
[i
]))
1016 def com_list_comprehension(self
, expr
, node
):
1017 # list_iter: list_for | list_if
1018 # list_for: 'for' exprlist 'in' testlist [list_iter]
1019 # list_if: 'if' test [list_iter]
1021 # XXX should raise SyntaxError for assignment
1028 assignNode
= self
.com_assign(node
[2], OP_ASSIGN
)
1029 listNode
= self
.com_node(node
[4])
1030 newfor
= ListCompFor(assignNode
, listNode
, [])
1031 newfor
.lineno
= node
[1][2]
1036 node
= self
.com_list_iter(node
[5])
1038 test
= self
.com_node(node
[2])
1039 newif
= ListCompIf(test
)
1040 newif
.lineno
= node
[1][2]
1041 newfor
.ifs
.append(newif
)
1045 node
= self
.com_list_iter(node
[3])
1047 raise SyntaxError, \
1048 ("unexpected list comprehension element: %s %d"
1050 n
= ListComp(expr
, fors
)
1054 def com_list_iter(self
, node
):
1055 assert node
[0] == symbol
.list_iter
1058 def com_list_constructor(self
, nodelist
):
1060 for i
in range(1, len(nodelist
), 2):
1061 values
.append(self
.com_node(nodelist
[i
]))
1064 def com_dictmaker(self
, nodelist
):
1065 # dictmaker: test ':' test (',' test ':' value)* [',']
1067 for i
in range(1, len(nodelist
), 4):
1068 items
.append((self
.com_node(nodelist
[i
]),
1069 self
.com_node(nodelist
[i
+2])))
1072 def com_apply_trailer(self
, primaryNode
, nodelist
):
1075 return self
.com_call_function(primaryNode
, nodelist
[2])
1077 return self
.com_select_member(primaryNode
, nodelist
[2])
1079 return self
.com_subscriptlist(primaryNode
, nodelist
[2], OP_APPLY
)
1081 raise SyntaxError, 'unknown node type: %s' % t
1083 def com_select_member(self
, primaryNode
, nodelist
):
1084 if nodelist
[0] != token
.NAME
:
1085 raise SyntaxError, "member must be a name"
1086 n
= Getattr(primaryNode
, nodelist
[1])
1087 n
.lineno
= nodelist
[2]
1090 def com_call_function(self
, primaryNode
, nodelist
):
1091 if nodelist
[0] == token
.RPAR
:
1092 return CallFunc(primaryNode
, [])
1095 len_nodelist
= len(nodelist
)
1096 for i
in range(1, len_nodelist
, 2):
1098 if node
[0] == token
.STAR
or node
[0] == token
.DOUBLESTAR
:
1100 kw
, result
= self
.com_argument(node
, kw
)
1103 # No broken by star arg, so skip the last one we processed.
1105 if i
< len_nodelist
and nodelist
[i
][0] == token
.COMMA
:
1106 # need to accept an application that looks like "f(a, b,)"
1108 star_node
= dstar_node
= None
1109 while i
< len_nodelist
:
1113 if tok
[0]==token
.STAR
:
1114 if star_node
is not None:
1115 raise SyntaxError, 'already have the varargs indentifier'
1116 star_node
= self
.com_node(ch
)
1117 elif tok
[0]==token
.DOUBLESTAR
:
1118 if dstar_node
is not None:
1119 raise SyntaxError, 'already have the kwargs indentifier'
1120 dstar_node
= self
.com_node(ch
)
1122 raise SyntaxError, 'unknown node type: %s' % tok
1124 return CallFunc(primaryNode
, args
, star_node
, dstar_node
)
1126 def com_argument(self
, nodelist
, kw
):
1127 if len(nodelist
) == 2:
1129 raise SyntaxError, "non-keyword arg after keyword arg"
1130 return 0, self
.com_node(nodelist
[1])
1131 result
= self
.com_node(nodelist
[3])
1133 while len(n
) == 2 and n
[0] != token
.NAME
:
1135 if n
[0] != token
.NAME
:
1136 raise SyntaxError, "keyword can't be an expression (%s)"%n
[0]
1137 node
= Keyword(n
[1], result
)
1141 def com_subscriptlist(self
, primary
, nodelist
, assigning
):
1142 # slicing: simple_slicing | extended_slicing
1143 # simple_slicing: primary "[" short_slice "]"
1144 # extended_slicing: primary "[" slice_list "]"
1145 # slice_list: slice_item ("," slice_item)* [","]
1147 # backwards compat slice for '[i:j]'
1148 if len(nodelist
) == 2:
1150 if (sub
[1][0] == token
.COLON
or \
1151 (len(sub
) > 2 and sub
[2][0] == token
.COLON
)) and \
1152 sub
[-1][0] != symbol
.sliceop
:
1153 return self
.com_slice(primary
, sub
, assigning
)
1156 for i
in range(1, len(nodelist
), 2):
1157 subscripts
.append(self
.com_subscript(nodelist
[i
]))
1159 return Subscript(primary
, assigning
, subscripts
)
1161 def com_subscript(self
, node
):
1162 # slice_item: expression | proper_slice | ellipsis
1165 if t
== token
.DOT
and node
[2][0] == token
.DOT
:
1167 if t
== token
.COLON
or len(node
) > 2:
1168 return self
.com_sliceobj(node
)
1169 return self
.com_node(ch
)
1171 def com_sliceobj(self
, node
):
1172 # proper_slice: short_slice | long_slice
1173 # short_slice: [lower_bound] ":" [upper_bound]
1174 # long_slice: short_slice ":" [stride]
1175 # lower_bound: expression
1176 # upper_bound: expression
1177 # stride: expression
1179 # Note: a stride may be further slicing...
1183 if node
[1][0] == token
.COLON
:
1184 items
.append(Const(None))
1187 items
.append(self
.com_node(node
[1]))
1191 if i
< len(node
) and node
[i
][0] == symbol
.test
:
1192 items
.append(self
.com_node(node
[i
]))
1195 items
.append(Const(None))
1197 # a short_slice has been built. look for long_slice now by looking
1199 for j
in range(i
, len(node
)):
1202 items
.append(Const(None))
1204 items
.append(self
.com_node(ch
[2]))
1206 return Sliceobj(items
)
1208 def com_slice(self
, primary
, node
, assigning
):
1209 # short_slice: [lower_bound] ":" [upper_bound]
1210 lower
= upper
= None
1212 if node
[1][0] == token
.COLON
:
1213 upper
= self
.com_node(node
[2])
1215 lower
= self
.com_node(node
[1])
1216 elif len(node
) == 4:
1217 lower
= self
.com_node(node
[1])
1218 upper
= self
.com_node(node
[3])
1219 return Slice(primary
, assigning
, lower
, upper
)
1221 def get_docstring(self
, node
, n
=None):
1225 if n
== symbol
.suite
:
1227 return self
.get_docstring(node
[0])
1229 if sub
[0] == symbol
.stmt
:
1230 return self
.get_docstring(sub
)
1232 if n
== symbol
.file_input
:
1234 if sub
[0] == symbol
.stmt
:
1235 return self
.get_docstring(sub
)
1237 if n
== symbol
.atom
:
1238 if node
[0][0] == token
.STRING
:
1244 if n
== symbol
.stmt
or n
== symbol
.simple_stmt \
1245 or n
== symbol
.small_stmt
:
1246 return self
.get_docstring(node
[0])
1247 if n
in _doc_nodes
and len(node
) == 1:
1248 return self
.get_docstring(node
[0])
1255 symbol
.testlist_safe
,
1270 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
1271 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
1274 token
.GREATER
: '>',
1275 token
.EQEQUAL
: '==',
1277 token
.LESSEQUAL
: '<=',
1278 token
.GREATEREQUAL
: '>=',
1279 token
.NOTEQUAL
: '!=',
1282 _legal_node_types
= [
1289 symbol
.compound_stmt
,
1295 symbol
.continue_stmt
,
1308 symbol
.testlist_safe
,
1325 if hasattr(symbol
, 'yield_stmt'):
1326 _legal_node_types
.append(symbol
.yield_stmt
)
1344 for k
, v
in symbol
.sym_name
.items():
1346 for k
, v
in token
.tok_name
.items():
1349 def debug_tree(tree
):
1352 if type(elt
) == types
.IntType
:
1353 l
.append(_names
.get(elt
, elt
))
1354 elif type(elt
) == types
.StringType
:
1357 l
.append(debug_tree(elt
))