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
34 error
= 'walker.error'
36 from consts
import CO_VARARGS
, CO_VARKEYWORDS
37 from consts
import OP_ASSIGN
, OP_DELETE
, OP_APPLY
45 def parse(buf
, mode
="exec"):
46 if mode
== "exec" or mode
== "single":
47 return Transformer().parsesuite(buf
)
49 return Transformer().parseexpr(buf
)
51 raise ValueError("compile() arg 3 must be"
52 " 'exec' or 'eval' or 'single'")
57 if hasattr(item
, "asList"):
58 l
.append(item
.asList())
60 if type(item
) is type( (None, None) ):
61 l
.append(tuple(asList(item
)))
62 elif type(item
) is type( [] ):
63 l
.append(asList(item
))
70 if nodes
.has_key(kind
):
72 return apply(nodes
[kind
], args
[1:])
74 print nodes
[kind
], len(args
), args
77 raise error
, "Can't find appropriate Node type: %s" % str(args
)
78 #return apply(ast.Node, args)
81 """Utility object for transforming Python parse trees.
83 Exposes the following methods:
84 tree = transform(ast_tree)
85 tree = parsesuite(text)
86 tree = parseexpr(text)
87 tree = parsefile(fileob | filename)
92 for value
, name
in symbol
.sym_name
.items():
93 if hasattr(self
, name
):
94 self
._dispatch
[value
] = getattr(self
, name
)
95 self
._dispatch
[token
.NEWLINE
] = self
.com_NEWLINE
96 self
._atom
_dispatch
= {token
.LPAR
: self
.atom_lpar
,
97 token
.LSQB
: self
.atom_lsqb
,
98 token
.LBRACE
: self
.atom_lbrace
,
99 token
.BACKQUOTE
: self
.atom_backquote
,
100 token
.NUMBER
: self
.atom_number
,
101 token
.STRING
: self
.atom_string
,
102 token
.NAME
: self
.atom_name
,
105 def transform(self
, tree
):
106 """Transform an AST into a modified parse tree."""
107 if type(tree
) != type(()) and type(tree
) != type([]):
108 tree
= parser
.ast2tuple(tree
, line_info
=1)
109 return self
.compile_node(tree
)
111 def parsesuite(self
, text
):
112 """Return a modified parse tree for the given suite text."""
113 # Hack for handling non-native line endings on non-DOS like OSs.
114 text
= string
.replace(text
, '\x0d', '')
115 return self
.transform(parser
.suite(text
))
117 def parseexpr(self
, text
):
118 """Return a modified parse tree for the given expression text."""
119 return self
.transform(parser
.expr(text
))
121 def parsefile(self
, file):
122 """Return a modified parse tree for the contents of the given file."""
123 if type(file) == type(''):
125 return self
.parsesuite(file.read())
127 # --------------------------------------------------------------
132 def compile_node(self
, node
):
133 ### emit a line-number node?
135 if n
== symbol
.single_input
:
136 return self
.single_input(node
[1:])
137 if n
== symbol
.file_input
:
138 return self
.file_input(node
[1:])
139 if n
== symbol
.eval_input
:
140 return self
.eval_input(node
[1:])
141 if n
== symbol
.lambdef
:
142 return self
.lambdef(node
[1:])
143 if n
== symbol
.funcdef
:
144 return self
.funcdef(node
[1:])
145 if n
== symbol
.classdef
:
146 return self
.classdef(node
[1:])
148 raise error
, ('unexpected node type', n
)
150 def single_input(self
, node
):
151 ### do we want to do anything about being "interactive" ?
153 # NEWLINE | simple_stmt | compound_stmt NEWLINE
155 if n
!= token
.NEWLINE
:
156 return self
.com_stmt(node
[0])
160 def file_input(self
, nodelist
):
161 doc
= self
.get_docstring(nodelist
, symbol
.file_input
)
167 for node
in nodelist
[i
:]:
168 if node
[0] != token
.ENDMARKER
and node
[0] != token
.NEWLINE
:
169 self
.com_append_stmt(stmts
, node
)
170 return Module(doc
, Stmt(stmts
))
172 def eval_input(self
, nodelist
):
173 # from the built-in function input()
174 ### is this sufficient?
175 return Expression(self
.com_node(nodelist
[0]))
177 def funcdef(self
, nodelist
):
178 # funcdef: 'def' NAME parameters ':' suite
179 # parameters: '(' [varargslist] ')'
181 lineno
= nodelist
[1][2]
182 name
= nodelist
[1][1]
183 args
= nodelist
[2][2]
185 if args
[0] == symbol
.varargslist
:
186 names
, defaults
, flags
= self
.com_arglist(args
[1:])
188 names
= defaults
= ()
190 doc
= self
.get_docstring(nodelist
[4])
193 code
= self
.com_node(nodelist
[4])
196 assert isinstance(code
, Stmt
)
197 assert isinstance(code
.nodes
[0], Discard
)
199 n
= Function(name
, names
, defaults
, flags
, doc
, code
)
203 def lambdef(self
, nodelist
):
204 # lambdef: 'lambda' [varargslist] ':' test
205 if nodelist
[2][0] == symbol
.varargslist
:
206 names
, defaults
, flags
= self
.com_arglist(nodelist
[2][1:])
208 names
= defaults
= ()
212 code
= self
.com_node(nodelist
[-1])
214 n
= Lambda(names
, defaults
, flags
, code
)
215 n
.lineno
= nodelist
[1][2]
218 def classdef(self
, nodelist
):
219 # classdef: 'class' NAME ['(' testlist ')'] ':' suite
221 name
= nodelist
[1][1]
222 doc
= self
.get_docstring(nodelist
[-1])
223 if nodelist
[2][0] == token
.COLON
:
226 bases
= self
.com_bases(nodelist
[3])
229 code
= self
.com_node(nodelist
[-1])
232 assert isinstance(code
, Stmt
)
233 assert isinstance(code
.nodes
[0], Discard
)
236 n
= Class(name
, bases
, doc
, code
)
237 n
.lineno
= nodelist
[1][2]
240 def stmt(self
, nodelist
):
241 return self
.com_stmt(nodelist
[0])
247 def simple_stmt(self
, nodelist
):
248 # small_stmt (';' small_stmt)* [';'] NEWLINE
250 for i
in range(0, len(nodelist
), 2):
251 self
.com_append_stmt(stmts
, nodelist
[i
])
254 def parameters(self
, nodelist
):
257 def varargslist(self
, nodelist
):
260 def fpdef(self
, nodelist
):
263 def fplist(self
, nodelist
):
266 def dotted_name(self
, nodelist
):
269 def comp_op(self
, nodelist
):
272 def trailer(self
, nodelist
):
275 def sliceop(self
, nodelist
):
278 def argument(self
, nodelist
):
281 # --------------------------------------------------------------
283 # STATEMENT NODES (invoked by com_node())
286 def expr_stmt(self
, nodelist
):
287 # augassign testlist | testlist ('=' testlist)*
289 exprNode
= self
.lookup_node(en
)(en
[1:])
290 if len(nodelist
) == 1:
291 n
= Discard(exprNode
)
292 n
.lineno
= exprNode
.lineno
294 if nodelist
[1][0] == token
.EQUAL
:
296 for i
in range(0, len(nodelist
) - 2, 2):
297 nodes
.append(self
.com_assign(nodelist
[i
], OP_ASSIGN
))
298 n
= Assign(nodes
, exprNode
)
299 n
.lineno
= nodelist
[1][2]
301 lval
= self
.com_augassign(nodelist
[0])
302 op
= self
.com_augassign_op(nodelist
[1])
303 n
= AugAssign(lval
, op
[1], exprNode
)
307 def print_stmt(self
, nodelist
):
308 # print ([ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ])
310 if len(nodelist
) == 1:
313 elif nodelist
[1][0] == token
.RIGHTSHIFT
:
314 assert len(nodelist
) == 3 \
315 or nodelist
[3][0] == token
.COMMA
316 dest
= self
.com_node(nodelist
[2])
321 for i
in range(start
, len(nodelist
), 2):
322 items
.append(self
.com_node(nodelist
[i
]))
323 if nodelist
[-1][0] == token
.COMMA
:
324 n
= Print(items
, dest
)
325 n
.lineno
= nodelist
[0][2]
327 n
= Printnl(items
, dest
)
328 n
.lineno
= nodelist
[0][2]
331 def del_stmt(self
, nodelist
):
332 return self
.com_assign(nodelist
[1], OP_DELETE
)
334 def pass_stmt(self
, nodelist
):
336 n
.lineno
= nodelist
[0][2]
339 def break_stmt(self
, nodelist
):
341 n
.lineno
= nodelist
[0][2]
344 def continue_stmt(self
, nodelist
):
346 n
.lineno
= nodelist
[0][2]
349 def return_stmt(self
, nodelist
):
351 if len(nodelist
) < 2:
352 n
= Return(Const(None))
353 n
.lineno
= nodelist
[0][2]
355 n
= Return(self
.com_node(nodelist
[1]))
356 n
.lineno
= nodelist
[0][2]
359 def yield_stmt(self
, nodelist
):
360 n
= Yield(self
.com_node(nodelist
[1]))
361 n
.lineno
= nodelist
[0][2]
364 def raise_stmt(self
, nodelist
):
365 # raise: [test [',' test [',' test]]]
366 if len(nodelist
) > 5:
367 expr3
= self
.com_node(nodelist
[5])
370 if len(nodelist
) > 3:
371 expr2
= self
.com_node(nodelist
[3])
374 if len(nodelist
) > 1:
375 expr1
= self
.com_node(nodelist
[1])
378 n
= Raise(expr1
, expr2
, expr3
)
379 n
.lineno
= nodelist
[0][2]
382 def import_stmt(self
, nodelist
):
383 # import_stmt: 'import' dotted_as_name (',' dotted_as_name)* |
384 # from: 'from' dotted_name 'import'
385 # ('*' | import_as_name (',' import_as_name)*)
386 if nodelist
[0][1] == 'from':
388 if nodelist
[3][0] == token
.NAME
:
389 for i
in range(3, len(nodelist
), 2):
390 names
.append((nodelist
[i
][1], None))
392 for i
in range(3, len(nodelist
), 2):
393 names
.append(self
.com_import_as_name(nodelist
[i
]))
394 n
= From(self
.com_dotted_name(nodelist
[1]), names
)
395 n
.lineno
= nodelist
[0][2]
398 if nodelist
[1][0] == symbol
.dotted_name
:
399 names
= [(self
.com_dotted_name(nodelist
[1][1:]), None)]
402 for i
in range(1, len(nodelist
), 2):
403 names
.append(self
.com_dotted_as_name(nodelist
[i
]))
405 n
.lineno
= nodelist
[0][2]
408 def global_stmt(self
, nodelist
):
409 # global: NAME (',' NAME)*
411 for i
in range(1, len(nodelist
), 2):
412 names
.append(nodelist
[i
][1])
414 n
.lineno
= nodelist
[0][2]
417 def exec_stmt(self
, nodelist
):
418 # exec_stmt: 'exec' expr ['in' expr [',' expr]]
419 expr1
= self
.com_node(nodelist
[1])
420 if len(nodelist
) >= 4:
421 expr2
= self
.com_node(nodelist
[3])
422 if len(nodelist
) >= 6:
423 expr3
= self
.com_node(nodelist
[5])
429 n
= Exec(expr1
, expr2
, expr3
)
430 n
.lineno
= nodelist
[0][2]
433 def assert_stmt(self
, nodelist
):
434 # 'assert': test, [',' test]
435 expr1
= self
.com_node(nodelist
[1])
436 if (len(nodelist
) == 4):
437 expr2
= self
.com_node(nodelist
[3])
440 n
= Assert(expr1
, expr2
)
441 n
.lineno
= nodelist
[0][2]
444 def if_stmt(self
, nodelist
):
445 # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
447 for i
in range(0, len(nodelist
) - 3, 4):
448 testNode
= self
.com_node(nodelist
[i
+ 1])
449 suiteNode
= self
.com_node(nodelist
[i
+ 3])
450 tests
.append((testNode
, suiteNode
))
452 if len(nodelist
) % 4 == 3:
453 elseNode
= self
.com_node(nodelist
[-1])
454 ## elseNode.lineno = nodelist[-1][1][2]
457 n
= If(tests
, elseNode
)
458 n
.lineno
= nodelist
[0][2]
461 def while_stmt(self
, nodelist
):
462 # 'while' test ':' suite ['else' ':' suite]
464 testNode
= self
.com_node(nodelist
[1])
465 bodyNode
= self
.com_node(nodelist
[3])
467 if len(nodelist
) > 4:
468 elseNode
= self
.com_node(nodelist
[6])
472 n
= While(testNode
, bodyNode
, elseNode
)
473 n
.lineno
= nodelist
[0][2]
476 def for_stmt(self
, nodelist
):
477 # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
479 assignNode
= self
.com_assign(nodelist
[1], OP_ASSIGN
)
480 listNode
= self
.com_node(nodelist
[3])
481 bodyNode
= self
.com_node(nodelist
[5])
483 if len(nodelist
) > 8:
484 elseNode
= self
.com_node(nodelist
[8])
488 n
= For(assignNode
, listNode
, bodyNode
, elseNode
)
489 n
.lineno
= nodelist
[0][2]
492 def try_stmt(self
, nodelist
):
493 # 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
494 # | 'try' ':' suite 'finally' ':' suite
495 if nodelist
[3][0] != symbol
.except_clause
:
496 return self
.com_try_finally(nodelist
)
498 return self
.com_try_except(nodelist
)
500 def suite(self
, nodelist
):
501 # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
502 if len(nodelist
) == 1:
503 return self
.com_stmt(nodelist
[0])
506 for node
in nodelist
:
507 if node
[0] == symbol
.stmt
:
508 self
.com_append_stmt(stmts
, node
)
511 # --------------------------------------------------------------
513 # EXPRESSION NODES (invoked by com_node())
516 def testlist(self
, nodelist
):
517 # testlist: expr (',' expr)* [',']
518 # testlist_safe: test [(',' test)+ [',']]
519 # exprlist: expr (',' expr)* [',']
520 return self
.com_binary(Tuple
, nodelist
)
522 testlist_safe
= testlist
# XXX
525 def test(self
, nodelist
):
526 # and_test ('or' and_test)* | lambdef
527 if len(nodelist
) == 1 and nodelist
[0][0] == symbol
.lambdef
:
528 return self
.lambdef(nodelist
[0])
529 return self
.com_binary(Or
, nodelist
)
531 def and_test(self
, nodelist
):
532 # not_test ('and' not_test)*
533 return self
.com_binary(And
, nodelist
)
535 def not_test(self
, nodelist
):
536 # 'not' not_test | comparison
537 result
= self
.com_node(nodelist
[-1])
538 if len(nodelist
) == 2:
540 n
.lineno
= nodelist
[0][2]
544 def comparison(self
, nodelist
):
545 # comparison: expr (comp_op expr)*
546 node
= self
.com_node(nodelist
[0])
547 if len(nodelist
) == 1:
551 for i
in range(2, len(nodelist
), 2):
554 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
555 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
557 if n
[0] == token
.NAME
:
565 type = _cmp_types
[n
[0]]
568 results
.append((type, self
.com_node(nodelist
[i
])))
570 # we need a special "compare" node so that we can distinguish
571 # 3 < x < 5 from (3 < x) < 5
572 # the two have very different semantics and results (note that the
573 # latter form is always true)
575 n
= Compare(node
, results
)
579 def expr(self
, nodelist
):
580 # xor_expr ('|' xor_expr)*
581 return self
.com_binary(Bitor
, nodelist
)
583 def xor_expr(self
, nodelist
):
584 # xor_expr ('^' xor_expr)*
585 return self
.com_binary(Bitxor
, nodelist
)
587 def and_expr(self
, nodelist
):
588 # xor_expr ('&' xor_expr)*
589 return self
.com_binary(Bitand
, nodelist
)
591 def shift_expr(self
, nodelist
):
592 # shift_expr ('<<'|'>>' shift_expr)*
593 node
= self
.com_node(nodelist
[0])
594 for i
in range(2, len(nodelist
), 2):
595 right
= self
.com_node(nodelist
[i
])
596 if nodelist
[i
-1][0] == token
.LEFTSHIFT
:
597 node
= LeftShift([node
, right
])
598 node
.lineno
= nodelist
[1][2]
599 elif nodelist
[i
-1][0] == token
.RIGHTSHIFT
:
600 node
= RightShift([node
, right
])
601 node
.lineno
= nodelist
[1][2]
603 raise ValueError, "unexpected token: %s" % nodelist
[i
-1][0]
606 def arith_expr(self
, nodelist
):
607 node
= self
.com_node(nodelist
[0])
608 for i
in range(2, len(nodelist
), 2):
609 right
= self
.com_node(nodelist
[i
])
610 if nodelist
[i
-1][0] == token
.PLUS
:
611 node
= Add([node
, right
])
612 node
.lineno
= nodelist
[1][2]
613 elif nodelist
[i
-1][0] == token
.MINUS
:
614 node
= Sub([node
, right
])
615 node
.lineno
= nodelist
[1][2]
617 raise ValueError, "unexpected token: %s" % nodelist
[i
-1][0]
620 def term(self
, nodelist
):
621 node
= self
.com_node(nodelist
[0])
622 for i
in range(2, len(nodelist
), 2):
623 right
= self
.com_node(nodelist
[i
])
626 node
= Mul([node
, right
])
627 elif t
== token
.SLASH
:
628 node
= Div([node
, right
])
629 elif t
== token
.PERCENT
:
630 node
= Mod([node
, right
])
631 elif t
== token
.DOUBLESLASH
:
632 node
= FloorDiv([node
, right
])
634 raise ValueError, "unexpected token: %s" % t
635 node
.lineno
= nodelist
[1][2]
638 def factor(self
, nodelist
):
641 node
= self
.com_node(nodelist
[-1])
643 node
= UnaryAdd(node
)
645 elif t
== token
.MINUS
:
646 node
= UnarySub(node
)
648 elif t
== token
.TILDE
:
653 def power(self
, nodelist
):
654 # power: atom trailer* ('**' factor)*
655 node
= self
.com_node(nodelist
[0])
656 for i
in range(1, len(nodelist
)):
658 if elt
[0] == token
.DOUBLESTAR
:
659 n
= Power([node
, self
.com_node(nodelist
[i
+1])])
663 node
= self
.com_apply_trailer(node
, elt
)
667 def atom(self
, nodelist
):
668 n
= self
._atom
_dispatch
[nodelist
[0][0]](nodelist
)
669 n
.lineno
= nodelist
[0][2]
672 def atom_lpar(self
, nodelist
):
673 if nodelist
[1][0] == token
.RPAR
:
675 n
.lineno
= nodelist
[0][2]
677 return self
.com_node(nodelist
[1])
679 def atom_lsqb(self
, nodelist
):
680 if nodelist
[1][0] == token
.RSQB
:
682 n
.lineno
= nodelist
[0][2]
684 return self
.com_list_constructor(nodelist
[1])
686 def atom_lbrace(self
, nodelist
):
687 if nodelist
[1][0] == token
.RBRACE
:
689 return self
.com_dictmaker(nodelist
[1])
691 def atom_backquote(self
, nodelist
):
692 n
= Backquote(self
.com_node(nodelist
[1]))
693 n
.lineno
= nodelist
[0][2]
696 def atom_number(self
, nodelist
):
697 ### need to verify this matches compile.c
698 k
= eval(nodelist
[0][1])
700 n
.lineno
= nodelist
[0][2]
703 def atom_string(self
, nodelist
):
704 ### need to verify this matches compile.c
706 for node
in nodelist
:
707 k
= k
+ eval(node
[1])
709 n
.lineno
= nodelist
[0][2]
712 def atom_name(self
, nodelist
):
713 ### any processing to do?
714 n
= Name(nodelist
[0][1])
715 n
.lineno
= nodelist
[0][2]
718 # --------------------------------------------------------------
720 # INTERNAL PARSING UTILITIES
723 # The use of com_node() introduces a lot of extra stack frames,
724 # enough to cause a stack overflow compiling test.test_parser with
725 # the standard interpreter recursionlimit. The com_node() is a
726 # convenience function that hides the dispatch details, but comes
727 # at a very high cost. It is more efficient to dispatch directly
728 # in the callers. In these cases, use lookup_node() and call the
729 # dispatched node directly.
731 def lookup_node(self
, node
):
732 return self
._dispatch
[node
[0]]
734 def com_node(self
, node
):
735 # Note: compile.c has handling in com_node for del_stmt, pass_stmt,
736 # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
738 # We'll just dispatch them.
739 return self
._dispatch
[node
[0]](node
[1:])
741 def com_NEWLINE(self
, *args
):
742 # A ';' at the end of a line can make a NEWLINE token appear
743 # here, Render it harmless. (genc discards ('discard',
744 # ('const', xxxx)) Nodes)
745 return Discard(Const(None))
747 def com_arglist(self
, nodelist
):
749 # (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME]
750 # | fpdef ['=' test] (',' fpdef ['=' test])* [',']
751 # | ('**'|'*' '*') NAME)
752 # fpdef: NAME | '(' fplist ')'
753 # fplist: fpdef (',' fpdef)* [',']
759 while i
< len(nodelist
):
761 if node
[0] == token
.STAR
or node
[0] == token
.DOUBLESTAR
:
762 if node
[0] == token
.STAR
:
764 if node
[0] == token
.NAME
:
765 names
.append(node
[1])
766 flags
= flags | CO_VARARGS
769 if i
< len(nodelist
):
770 # should be DOUBLESTAR or STAR STAR
772 if t
== token
.DOUBLESTAR
:
774 elif t
== token
.STARSTAR
:
777 raise ValueError, "unexpected token: %s" % t
778 names
.append(node
[1])
779 flags
= flags | CO_VARKEYWORDS
783 # fpdef: NAME | '(' fplist ')'
784 names
.append(self
.com_fpdef(node
))
787 if i
>= len(nodelist
):
790 if nodelist
[i
][0] == token
.EQUAL
:
791 defaults
.append(self
.com_node(nodelist
[i
+ 1]))
794 # Treat "(a=1, b)" as "(a=1, b=None)"
795 defaults
.append(Const(None))
799 return names
, defaults
, flags
801 def com_fpdef(self
, node
):
802 # fpdef: NAME | '(' fplist ')'
803 if node
[1][0] == token
.LPAR
:
804 return self
.com_fplist(node
[2])
807 def com_fplist(self
, node
):
808 # fplist: fpdef (',' fpdef)* [',']
810 return self
.com_fpdef(node
[1])
812 for i
in range(1, len(node
), 2):
813 list.append(self
.com_fpdef(node
[i
]))
816 def com_dotted_name(self
, node
):
817 # String together the dotted names and return the string
820 if type(n
) == type(()) and n
[0] == 1:
821 name
= name
+ n
[1] + '.'
824 def com_dotted_as_name(self
, node
):
825 dot
= self
.com_dotted_name(node
[1])
828 if node
[0] == symbol
.dotted_name
:
831 assert node
[2][1] == 'as'
832 assert node
[3][0] == token
.NAME
833 return dot
, node
[3][1]
835 def com_import_as_name(self
, node
):
836 if node
[0] == token
.STAR
:
838 assert node
[0] == symbol
.import_as_name
841 assert node
[0][0] == token
.NAME
842 return node
[0][1], None
844 assert node
[1][1] == 'as', node
845 assert node
[2][0] == token
.NAME
846 return node
[0][1], node
[2][1]
848 def com_bases(self
, node
):
850 for i
in range(1, len(node
), 2):
851 bases
.append(self
.com_node(node
[i
]))
854 def com_try_finally(self
, nodelist
):
855 # try_fin_stmt: "try" ":" suite "finally" ":" suite
856 n
= TryFinally(self
.com_node(nodelist
[2]),
857 self
.com_node(nodelist
[5]))
858 n
.lineno
= nodelist
[0][2]
861 def com_try_except(self
, nodelist
):
862 # try_except: 'try' ':' suite (except_clause ':' suite)* ['else' suite]
863 #tryexcept: [TryNode, [except_clauses], elseNode)]
864 stmt
= self
.com_node(nodelist
[2])
867 for i
in range(3, len(nodelist
), 3):
869 if node
[0] == symbol
.except_clause
:
870 # except_clause: 'except' [expr [',' expr]] */
872 expr1
= self
.com_node(node
[2])
874 expr2
= self
.com_assign(node
[4], OP_ASSIGN
)
879 clauses
.append((expr1
, expr2
, self
.com_node(nodelist
[i
+2])))
881 if node
[0] == token
.NAME
:
882 elseNode
= self
.com_node(nodelist
[i
+2])
883 n
= TryExcept(self
.com_node(nodelist
[2]), clauses
, elseNode
)
884 n
.lineno
= nodelist
[0][2]
887 def com_augassign_op(self
, node
):
888 assert node
[0] == symbol
.augassign
891 def com_augassign(self
, node
):
892 """Return node suitable for lvalue of augmented assignment
894 Names, slices, and attributes are the only allowable nodes.
896 l
= self
.com_node(node
)
897 if l
.__class
__ in (Name
, Slice
, Subscript
, Getattr
):
899 raise SyntaxError, "can't assign to %s" % l
.__class
__.__name
__
901 def com_assign(self
, node
, assigning
):
902 # return a node suitable for use as an "lvalue"
903 # loop to avoid trivial recursion
906 if t
== symbol
.exprlist
or t
== symbol
.testlist
:
908 return self
.com_assign_tuple(node
, assigning
)
910 elif t
in _assign_types
:
912 raise SyntaxError, "can't assign to operator"
914 elif t
== symbol
.power
:
915 if node
[1][0] != symbol
.atom
:
916 raise SyntaxError, "can't assign to operator"
918 primary
= self
.com_node(node
[1])
919 for i
in range(2, len(node
)-1):
921 if ch
[0] == token
.DOUBLESTAR
:
922 raise SyntaxError, "can't assign to operator"
923 primary
= self
.com_apply_trailer(primary
, ch
)
924 return self
.com_assign_trailer(primary
, node
[-1],
927 elif t
== symbol
.atom
:
931 if node
[0] == token
.RPAR
:
932 raise SyntaxError, "can't assign to ()"
933 elif t
== token
.LSQB
:
935 if node
[0] == token
.RSQB
:
936 raise SyntaxError, "can't assign to []"
937 return self
.com_assign_list(node
, assigning
)
938 elif t
== token
.NAME
:
939 return self
.com_assign_name(node
[1], assigning
)
941 raise SyntaxError, "can't assign to literal"
943 raise SyntaxError, "bad assignment"
945 def com_assign_tuple(self
, node
, assigning
):
947 for i
in range(1, len(node
), 2):
948 assigns
.append(self
.com_assign(node
[i
], assigning
))
949 return AssTuple(assigns
)
951 def com_assign_list(self
, node
, assigning
):
953 for i
in range(1, len(node
), 2):
954 if i
+ 1 < len(node
):
955 if node
[i
+ 1][0] == symbol
.list_for
:
956 raise SyntaxError, "can't assign to list comprehension"
957 assert node
[i
+ 1][0] == token
.COMMA
, node
[i
+ 1]
958 assigns
.append(self
.com_assign(node
[i
], assigning
))
959 return AssList(assigns
)
961 def com_assign_name(self
, node
, assigning
):
962 n
= AssName(node
[1], assigning
)
966 def com_assign_trailer(self
, primary
, node
, assigning
):
969 return self
.com_assign_attr(primary
, node
[2], assigning
)
971 return self
.com_subscriptlist(primary
, node
[2], assigning
)
973 raise SyntaxError, "can't assign to function call"
974 raise SyntaxError, "unknown trailer type: %s" % t
976 def com_assign_attr(self
, primary
, node
, assigning
):
977 return AssAttr(primary
, node
[1], assigning
)
979 def com_binary(self
, constructor
, nodelist
):
980 "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
984 return self
.lookup_node(n
)(n
[1:])
986 for i
in range(0, l
, 2):
988 items
.append(self
.lookup_node(n
)(n
[1:]))
989 return constructor(items
)
991 def com_stmt(self
, node
):
992 result
= self
.lookup_node(node
)(node
[1:])
993 assert result
is not None
994 if isinstance(result
, Stmt
):
996 return Stmt([result
])
998 def com_append_stmt(self
, stmts
, node
):
999 result
= self
.com_node(node
)
1000 assert result
is not None
1001 if isinstance(result
, Stmt
):
1002 stmts
.extend(result
.nodes
)
1004 stmts
.append(result
)
1006 if hasattr(symbol
, 'list_for'):
1007 def com_list_constructor(self
, nodelist
):
1008 # listmaker: test ( list_for | (',' test)* [','] )
1010 for i
in range(1, len(nodelist
)):
1011 if nodelist
[i
][0] == symbol
.list_for
:
1012 assert len(nodelist
[i
:]) == 1
1013 return self
.com_list_comprehension(values
[0],
1015 elif nodelist
[i
][0] == token
.COMMA
:
1017 values
.append(self
.com_node(nodelist
[i
]))
1020 def com_list_comprehension(self
, expr
, node
):
1021 # list_iter: list_for | list_if
1022 # list_for: 'for' exprlist 'in' testlist [list_iter]
1023 # list_if: 'if' test [list_iter]
1025 # XXX should raise SyntaxError for assignment
1032 assignNode
= self
.com_assign(node
[2], OP_ASSIGN
)
1033 listNode
= self
.com_node(node
[4])
1034 newfor
= ListCompFor(assignNode
, listNode
, [])
1035 newfor
.lineno
= node
[1][2]
1040 node
= self
.com_list_iter(node
[5])
1042 test
= self
.com_node(node
[2])
1043 newif
= ListCompIf(test
)
1044 newif
.lineno
= node
[1][2]
1045 newfor
.ifs
.append(newif
)
1049 node
= self
.com_list_iter(node
[3])
1051 raise SyntaxError, \
1052 ("unexpected list comprehension element: %s %d"
1054 n
= ListComp(expr
, fors
)
1058 def com_list_iter(self
, node
):
1059 assert node
[0] == symbol
.list_iter
1062 def com_list_constructor(self
, nodelist
):
1064 for i
in range(1, len(nodelist
), 2):
1065 values
.append(self
.com_node(nodelist
[i
]))
1068 def com_dictmaker(self
, nodelist
):
1069 # dictmaker: test ':' test (',' test ':' value)* [',']
1071 for i
in range(1, len(nodelist
), 4):
1072 items
.append((self
.com_node(nodelist
[i
]),
1073 self
.com_node(nodelist
[i
+2])))
1076 def com_apply_trailer(self
, primaryNode
, nodelist
):
1079 return self
.com_call_function(primaryNode
, nodelist
[2])
1081 return self
.com_select_member(primaryNode
, nodelist
[2])
1083 return self
.com_subscriptlist(primaryNode
, nodelist
[2], OP_APPLY
)
1085 raise SyntaxError, 'unknown node type: %s' % t
1087 def com_select_member(self
, primaryNode
, nodelist
):
1088 if nodelist
[0] != token
.NAME
:
1089 raise SyntaxError, "member must be a name"
1090 n
= Getattr(primaryNode
, nodelist
[1])
1091 n
.lineno
= nodelist
[2]
1094 def com_call_function(self
, primaryNode
, nodelist
):
1095 if nodelist
[0] == token
.RPAR
:
1096 return CallFunc(primaryNode
, [])
1099 len_nodelist
= len(nodelist
)
1100 for i
in range(1, len_nodelist
, 2):
1102 if node
[0] == token
.STAR
or node
[0] == token
.DOUBLESTAR
:
1104 kw
, result
= self
.com_argument(node
, kw
)
1107 # No broken by star arg, so skip the last one we processed.
1109 if i
< len_nodelist
and nodelist
[i
][0] == token
.COMMA
:
1110 # need to accept an application that looks like "f(a, b,)"
1112 star_node
= dstar_node
= None
1113 while i
< len_nodelist
:
1117 if tok
[0]==token
.STAR
:
1118 if star_node
is not None:
1119 raise SyntaxError, 'already have the varargs indentifier'
1120 star_node
= self
.com_node(ch
)
1121 elif tok
[0]==token
.DOUBLESTAR
:
1122 if dstar_node
is not None:
1123 raise SyntaxError, 'already have the kwargs indentifier'
1124 dstar_node
= self
.com_node(ch
)
1126 raise SyntaxError, 'unknown node type: %s' % tok
1128 return CallFunc(primaryNode
, args
, star_node
, dstar_node
)
1130 def com_argument(self
, nodelist
, kw
):
1131 if len(nodelist
) == 2:
1133 raise SyntaxError, "non-keyword arg after keyword arg"
1134 return 0, self
.com_node(nodelist
[1])
1135 result
= self
.com_node(nodelist
[3])
1137 while len(n
) == 2 and n
[0] != token
.NAME
:
1139 if n
[0] != token
.NAME
:
1140 raise SyntaxError, "keyword can't be an expression (%s)"%n
[0]
1141 node
= Keyword(n
[1], result
)
1145 def com_subscriptlist(self
, primary
, nodelist
, assigning
):
1146 # slicing: simple_slicing | extended_slicing
1147 # simple_slicing: primary "[" short_slice "]"
1148 # extended_slicing: primary "[" slice_list "]"
1149 # slice_list: slice_item ("," slice_item)* [","]
1151 # backwards compat slice for '[i:j]'
1152 if len(nodelist
) == 2:
1154 if (sub
[1][0] == token
.COLON
or \
1155 (len(sub
) > 2 and sub
[2][0] == token
.COLON
)) and \
1156 sub
[-1][0] != symbol
.sliceop
:
1157 return self
.com_slice(primary
, sub
, assigning
)
1160 for i
in range(1, len(nodelist
), 2):
1161 subscripts
.append(self
.com_subscript(nodelist
[i
]))
1163 return Subscript(primary
, assigning
, subscripts
)
1165 def com_subscript(self
, node
):
1166 # slice_item: expression | proper_slice | ellipsis
1169 if t
== token
.DOT
and node
[2][0] == token
.DOT
:
1171 if t
== token
.COLON
or len(node
) > 2:
1172 return self
.com_sliceobj(node
)
1173 return self
.com_node(ch
)
1175 def com_sliceobj(self
, node
):
1176 # proper_slice: short_slice | long_slice
1177 # short_slice: [lower_bound] ":" [upper_bound]
1178 # long_slice: short_slice ":" [stride]
1179 # lower_bound: expression
1180 # upper_bound: expression
1181 # stride: expression
1183 # Note: a stride may be further slicing...
1187 if node
[1][0] == token
.COLON
:
1188 items
.append(Const(None))
1191 items
.append(self
.com_node(node
[1]))
1195 if i
< len(node
) and node
[i
][0] == symbol
.test
:
1196 items
.append(self
.com_node(node
[i
]))
1199 items
.append(Const(None))
1201 # a short_slice has been built. look for long_slice now by looking
1203 for j
in range(i
, len(node
)):
1206 items
.append(Const(None))
1208 items
.append(self
.com_node(ch
[2]))
1210 return Sliceobj(items
)
1212 def com_slice(self
, primary
, node
, assigning
):
1213 # short_slice: [lower_bound] ":" [upper_bound]
1214 lower
= upper
= None
1216 if node
[1][0] == token
.COLON
:
1217 upper
= self
.com_node(node
[2])
1219 lower
= self
.com_node(node
[1])
1220 elif len(node
) == 4:
1221 lower
= self
.com_node(node
[1])
1222 upper
= self
.com_node(node
[3])
1223 return Slice(primary
, assigning
, lower
, upper
)
1225 def get_docstring(self
, node
, n
=None):
1229 if n
== symbol
.suite
:
1231 return self
.get_docstring(node
[0])
1233 if sub
[0] == symbol
.stmt
:
1234 return self
.get_docstring(sub
)
1236 if n
== symbol
.file_input
:
1238 if sub
[0] == symbol
.stmt
:
1239 return self
.get_docstring(sub
)
1241 if n
== symbol
.atom
:
1242 if node
[0][0] == token
.STRING
:
1248 if n
== symbol
.stmt
or n
== symbol
.simple_stmt \
1249 or n
== symbol
.small_stmt
:
1250 return self
.get_docstring(node
[0])
1251 if n
in _doc_nodes
and len(node
) == 1:
1252 return self
.get_docstring(node
[0])
1259 symbol
.testlist_safe
,
1274 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
1275 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
1278 token
.GREATER
: '>',
1279 token
.EQEQUAL
: '==',
1281 token
.LESSEQUAL
: '<=',
1282 token
.GREATEREQUAL
: '>=',
1283 token
.NOTEQUAL
: '!=',
1286 _legal_node_types
= [
1293 symbol
.compound_stmt
,
1299 symbol
.continue_stmt
,
1312 symbol
.testlist_safe
,
1329 if hasattr(symbol
, 'yield_stmt'):
1330 _legal_node_types
.append(symbol
.yield_stmt
)
1348 for k
, v
in symbol
.sym_name
.items():
1350 for k
, v
in token
.tok_name
.items():
1353 def debug_tree(tree
):
1356 if type(elt
) == types
.IntType
:
1357 l
.append(_names
.get(elt
, elt
))
1358 elif type(elt
) == types
.StringType
:
1361 l
.append(debug_tree(elt
))