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
46 return Transformer().parsesuite(buf
)
51 if hasattr(item
, "asList"):
52 l
.append(item
.asList())
54 if type(item
) is type( (None, None) ):
55 l
.append(tuple(asList(item
)))
56 elif type(item
) is type( [] ):
57 l
.append(asList(item
))
64 if nodes
.has_key(kind
):
66 return apply(nodes
[kind
], args
[1:])
68 print nodes
[kind
], len(args
), args
71 raise error
, "Can't find appropriate Node type: %s" % str(args
)
72 #return apply(ast.Node, args)
75 """Utility object for transforming Python parse trees.
77 Exposes the following methods:
78 tree = transform(ast_tree)
79 tree = parsesuite(text)
80 tree = parseexpr(text)
81 tree = parsefile(fileob | filename)
86 for value
, name
in symbol
.sym_name
.items():
87 if hasattr(self
, name
):
88 self
._dispatch
[value
] = getattr(self
, name
)
89 self
._dispatch
[token
.NEWLINE
] = self
.com_NEWLINE
90 self
._atom
_dispatch
= {token
.LPAR
: self
.atom_lpar
,
91 token
.LSQB
: self
.atom_lsqb
,
92 token
.LBRACE
: self
.atom_lbrace
,
93 token
.BACKQUOTE
: self
.atom_backquote
,
94 token
.NUMBER
: self
.atom_number
,
95 token
.STRING
: self
.atom_string
,
96 token
.NAME
: self
.atom_name
,
99 def transform(self
, tree
):
100 """Transform an AST into a modified parse tree."""
101 if type(tree
) != type(()) and type(tree
) != type([]):
102 tree
= parser
.ast2tuple(tree
,1)
103 return self
.compile_node(tree
)
105 def parsesuite(self
, text
):
106 """Return a modified parse tree for the given suite text."""
107 # Hack for handling non-native line endings on non-DOS like OSs.
108 text
= string
.replace(text
, '\x0d', '')
109 return self
.transform(parser
.suite(text
))
111 def parseexpr(self
, text
):
112 """Return a modified parse tree for the given expression text."""
113 return self
.transform(parser
.expr(text
))
115 def parsefile(self
, file):
116 """Return a modified parse tree for the contents of the given file."""
117 if type(file) == type(''):
119 return self
.parsesuite(file.read())
121 # --------------------------------------------------------------
126 def compile_node(self
, node
):
127 ### emit a line-number node?
129 if n
== symbol
.single_input
:
130 return self
.single_input(node
[1:])
131 if n
== symbol
.file_input
:
132 return self
.file_input(node
[1:])
133 if n
== symbol
.eval_input
:
134 return self
.eval_input(node
[1:])
135 if n
== symbol
.lambdef
:
136 return self
.lambdef(node
[1:])
137 if n
== symbol
.funcdef
:
138 return self
.funcdef(node
[1:])
139 if n
== symbol
.classdef
:
140 return self
.classdef(node
[1:])
142 raise error
, ('unexpected node type', n
)
144 def single_input(self
, node
):
145 ### do we want to do anything about being "interactive" ?
147 # NEWLINE | simple_stmt | compound_stmt NEWLINE
149 if n
!= token
.NEWLINE
:
150 return self
.com_stmt(node
[0])
154 def file_input(self
, nodelist
):
155 doc
= self
.get_docstring(nodelist
, symbol
.file_input
)
157 for node
in nodelist
:
158 if node
[0] != token
.ENDMARKER
and node
[0] != token
.NEWLINE
:
159 self
.com_append_stmt(stmts
, node
)
160 return Module(doc
, Stmt(stmts
))
162 def eval_input(self
, nodelist
):
163 # from the built-in function input()
164 ### is this sufficient?
165 return self
.com_node(nodelist
[0])
167 def funcdef(self
, nodelist
):
168 # funcdef: 'def' NAME parameters ':' suite
169 # parameters: '(' [varargslist] ')'
171 lineno
= nodelist
[1][2]
172 name
= nodelist
[1][1]
173 args
= nodelist
[2][2]
175 if args
[0] == symbol
.varargslist
:
176 names
, defaults
, flags
= self
.com_arglist(args
[1:])
178 names
= defaults
= ()
180 doc
= self
.get_docstring(nodelist
[4])
183 code
= self
.com_node(nodelist
[4])
186 assert isinstance(code
, Stmt
)
187 assert isinstance(code
.nodes
[0], Discard
)
189 n
= Function(name
, names
, defaults
, flags
, doc
, code
)
193 def lambdef(self
, nodelist
):
194 # lambdef: 'lambda' [varargslist] ':' test
195 if nodelist
[2][0] == symbol
.varargslist
:
196 names
, defaults
, flags
= self
.com_arglist(nodelist
[2][1:])
198 names
= defaults
= ()
202 code
= self
.com_node(nodelist
[-1])
204 n
= Lambda(names
, defaults
, flags
, code
)
205 n
.lineno
= nodelist
[1][2]
208 def classdef(self
, nodelist
):
209 # classdef: 'class' NAME ['(' testlist ')'] ':' suite
211 name
= nodelist
[1][1]
212 doc
= self
.get_docstring(nodelist
[-1])
213 if nodelist
[2][0] == token
.COLON
:
216 bases
= self
.com_bases(nodelist
[3])
219 code
= self
.com_node(nodelist
[-1])
221 n
= Class(name
, bases
, doc
, code
)
222 n
.lineno
= nodelist
[1][2]
225 def stmt(self
, nodelist
):
226 return self
.com_stmt(nodelist
[0])
232 def simple_stmt(self
, nodelist
):
233 # small_stmt (';' small_stmt)* [';'] NEWLINE
235 for i
in range(0, len(nodelist
), 2):
236 self
.com_append_stmt(stmts
, nodelist
[i
])
239 def parameters(self
, nodelist
):
242 def varargslist(self
, nodelist
):
245 def fpdef(self
, nodelist
):
248 def fplist(self
, nodelist
):
251 def dotted_name(self
, nodelist
):
254 def comp_op(self
, nodelist
):
257 def trailer(self
, nodelist
):
260 def sliceop(self
, nodelist
):
263 def argument(self
, nodelist
):
266 # --------------------------------------------------------------
268 # STATEMENT NODES (invoked by com_node())
271 def expr_stmt(self
, nodelist
):
272 # augassign testlist | testlist ('=' testlist)*
273 exprNode
= self
.com_node(nodelist
[-1])
274 if len(nodelist
) == 1:
275 return Discard(exprNode
)
276 if nodelist
[1][0] == token
.EQUAL
:
278 for i
in range(0, len(nodelist
) - 2, 2):
279 nodes
.append(self
.com_assign(nodelist
[i
], OP_ASSIGN
))
280 n
= Assign(nodes
, exprNode
)
281 n
.lineno
= nodelist
[1][2]
283 lval
= self
.com_augassign(nodelist
[0])
284 op
= self
.com_augassign_op(nodelist
[1])
285 n
= AugAssign(lval
, op
[1], exprNode
)
289 def print_stmt(self
, nodelist
):
290 # print ([ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ])
292 if len(nodelist
) == 1:
295 elif nodelist
[1][0] == token
.RIGHTSHIFT
:
296 assert len(nodelist
) == 3 \
297 or nodelist
[3][0] == token
.COMMA
298 dest
= self
.com_node(nodelist
[2])
303 for i
in range(start
, len(nodelist
), 2):
304 items
.append(self
.com_node(nodelist
[i
]))
305 if nodelist
[-1][0] == token
.COMMA
:
306 n
= Print(items
, dest
)
307 n
.lineno
= nodelist
[0][2]
309 n
= Printnl(items
, dest
)
310 n
.lineno
= nodelist
[0][2]
313 def del_stmt(self
, nodelist
):
314 return self
.com_assign(nodelist
[1], OP_DELETE
)
316 def pass_stmt(self
, nodelist
):
318 n
.lineno
= nodelist
[0][2]
321 def break_stmt(self
, nodelist
):
323 n
.lineno
= nodelist
[0][2]
326 def continue_stmt(self
, nodelist
):
328 n
.lineno
= nodelist
[0][2]
331 def return_stmt(self
, nodelist
):
333 if len(nodelist
) < 2:
334 n
= Return(Const(None))
335 n
.lineno
= nodelist
[0][2]
337 n
= Return(self
.com_node(nodelist
[1]))
338 n
.lineno
= nodelist
[0][2]
341 def raise_stmt(self
, nodelist
):
342 # raise: [test [',' test [',' test]]]
343 if len(nodelist
) > 5:
344 expr3
= self
.com_node(nodelist
[5])
347 if len(nodelist
) > 3:
348 expr2
= self
.com_node(nodelist
[3])
351 if len(nodelist
) > 1:
352 expr1
= self
.com_node(nodelist
[1])
355 n
= Raise(expr1
, expr2
, expr3
)
356 n
.lineno
= nodelist
[0][2]
359 def import_stmt(self
, nodelist
):
360 # import_stmt: 'import' dotted_as_name (',' dotted_as_name)* |
361 # from: 'from' dotted_name 'import'
362 # ('*' | import_as_name (',' import_as_name)*)
363 if nodelist
[0][1] == 'from':
365 if nodelist
[3][0] == token
.NAME
:
366 for i
in range(3, len(nodelist
), 2):
367 names
.append((nodelist
[i
][1], None))
369 for i
in range(3, len(nodelist
), 2):
370 names
.append(self
.com_import_as_name(nodelist
[i
][1]))
371 n
= From(self
.com_dotted_name(nodelist
[1]), names
)
372 n
.lineno
= nodelist
[0][2]
375 if nodelist
[1][0] == symbol
.dotted_name
:
376 names
= [(self
.com_dotted_name(nodelist
[1][1:]), None)]
379 for i
in range(1, len(nodelist
), 2):
380 names
.append(self
.com_dotted_as_name(nodelist
[i
]))
382 n
.lineno
= nodelist
[0][2]
385 def global_stmt(self
, nodelist
):
386 # global: NAME (',' NAME)*
388 for i
in range(1, len(nodelist
), 2):
389 names
.append(nodelist
[i
][1])
391 n
.lineno
= nodelist
[0][2]
394 def exec_stmt(self
, nodelist
):
395 # exec_stmt: 'exec' expr ['in' expr [',' expr]]
396 expr1
= self
.com_node(nodelist
[1])
397 if len(nodelist
) >= 4:
398 expr2
= self
.com_node(nodelist
[3])
399 if len(nodelist
) >= 6:
400 expr3
= self
.com_node(nodelist
[5])
406 n
= Exec(expr1
, expr2
, expr3
)
407 n
.lineno
= nodelist
[0][2]
410 def assert_stmt(self
, nodelist
):
411 # 'assert': test, [',' test]
412 expr1
= self
.com_node(nodelist
[1])
413 if (len(nodelist
) == 4):
414 expr2
= self
.com_node(nodelist
[3])
417 n
= Assert(expr1
, expr2
)
418 n
.lineno
= nodelist
[0][2]
421 def if_stmt(self
, nodelist
):
422 # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
424 for i
in range(0, len(nodelist
) - 3, 4):
425 testNode
= self
.com_node(nodelist
[i
+ 1])
426 suiteNode
= self
.com_node(nodelist
[i
+ 3])
427 tests
.append((testNode
, suiteNode
))
429 if len(nodelist
) % 4 == 3:
430 elseNode
= self
.com_node(nodelist
[-1])
431 ## elseNode.lineno = nodelist[-1][1][2]
434 n
= If(tests
, elseNode
)
435 n
.lineno
= nodelist
[0][2]
438 def while_stmt(self
, nodelist
):
439 # 'while' test ':' suite ['else' ':' suite]
441 testNode
= self
.com_node(nodelist
[1])
442 bodyNode
= self
.com_node(nodelist
[3])
444 if len(nodelist
) > 4:
445 elseNode
= self
.com_node(nodelist
[6])
449 n
= While(testNode
, bodyNode
, elseNode
)
450 n
.lineno
= nodelist
[0][2]
453 def for_stmt(self
, nodelist
):
454 # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
456 assignNode
= self
.com_assign(nodelist
[1], OP_ASSIGN
)
457 listNode
= self
.com_node(nodelist
[3])
458 bodyNode
= self
.com_node(nodelist
[5])
460 if len(nodelist
) > 8:
461 elseNode
= self
.com_node(nodelist
[8])
465 n
= For(assignNode
, listNode
, bodyNode
, elseNode
)
466 n
.lineno
= nodelist
[0][2]
469 def try_stmt(self
, nodelist
):
470 # 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
471 # | 'try' ':' suite 'finally' ':' suite
472 if nodelist
[3][0] != symbol
.except_clause
:
473 return self
.com_try_finally(nodelist
)
475 return self
.com_try_except(nodelist
)
477 def suite(self
, nodelist
):
478 # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
479 if len(nodelist
) == 1:
480 return self
.com_stmt(nodelist
[0])
483 for node
in nodelist
:
484 if node
[0] == symbol
.stmt
:
485 self
.com_append_stmt(stmts
, node
)
488 # --------------------------------------------------------------
490 # EXPRESSION NODES (invoked by com_node())
493 def testlist(self
, nodelist
):
494 # testlist: expr (',' expr)* [',']
495 # exprlist: expr (',' expr)* [',']
496 return self
.com_binary(Tuple
, nodelist
)
500 def test(self
, nodelist
):
501 # and_test ('or' and_test)* | lambdef
502 if len(nodelist
) == 1 and nodelist
[0][0] == symbol
.lambdef
:
503 return self
.lambdef(nodelist
[0])
504 return self
.com_binary(Or
, nodelist
)
506 def and_test(self
, nodelist
):
507 # not_test ('and' not_test)*
508 return self
.com_binary(And
, nodelist
)
510 def not_test(self
, nodelist
):
511 # 'not' not_test | comparison
512 result
= self
.com_node(nodelist
[-1])
513 if len(nodelist
) == 2:
515 n
.lineno
= nodelist
[0][2]
519 def comparison(self
, nodelist
):
520 # comparison: expr (comp_op expr)*
521 node
= self
.com_node(nodelist
[0])
522 if len(nodelist
) == 1:
526 for i
in range(2, len(nodelist
), 2):
529 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
530 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
532 if n
[0] == token
.NAME
:
540 type = _cmp_types
[n
[0]]
543 results
.append((type, self
.com_node(nodelist
[i
])))
545 # we need a special "compare" node so that we can distinguish
546 # 3 < x < 5 from (3 < x) < 5
547 # the two have very different semantics and results (note that the
548 # latter form is always true)
550 n
= Compare(node
, results
)
554 def expr(self
, nodelist
):
555 # xor_expr ('|' xor_expr)*
556 return self
.com_binary(Bitor
, nodelist
)
558 def xor_expr(self
, nodelist
):
559 # xor_expr ('^' xor_expr)*
560 return self
.com_binary(Bitxor
, nodelist
)
562 def and_expr(self
, nodelist
):
563 # xor_expr ('&' xor_expr)*
564 return self
.com_binary(Bitand
, nodelist
)
566 def shift_expr(self
, nodelist
):
567 # shift_expr ('<<'|'>>' shift_expr)*
568 node
= self
.com_node(nodelist
[0])
569 for i
in range(2, len(nodelist
), 2):
570 right
= self
.com_node(nodelist
[i
])
571 if nodelist
[i
-1][0] == token
.LEFTSHIFT
:
572 node
= LeftShift([node
, right
])
573 node
.lineno
= nodelist
[1][2]
575 node
= RightShift([node
, right
])
576 node
.lineno
= nodelist
[1][2]
579 def arith_expr(self
, nodelist
):
580 node
= self
.com_node(nodelist
[0])
581 for i
in range(2, len(nodelist
), 2):
582 right
= self
.com_node(nodelist
[i
])
583 if nodelist
[i
-1][0] == token
.PLUS
:
584 node
= Add([node
, right
])
585 node
.lineno
= nodelist
[1][2]
587 node
= Sub([node
, right
])
588 node
.lineno
= nodelist
[1][2]
591 def term(self
, nodelist
):
592 node
= self
.com_node(nodelist
[0])
593 for i
in range(2, len(nodelist
), 2):
594 right
= self
.com_node(nodelist
[i
])
597 node
= Mul([node
, right
])
598 elif t
== token
.SLASH
:
599 node
= Div([node
, right
])
601 node
= Mod([node
, right
])
602 node
.lineno
= nodelist
[1][2]
605 def factor(self
, nodelist
):
608 node
= self
.com_node(nodelist
[-1])
610 node
= UnaryAdd(node
)
612 elif t
== token
.MINUS
:
613 node
= UnarySub(node
)
615 elif t
== token
.TILDE
:
620 def power(self
, nodelist
):
621 # power: atom trailer* ('**' factor)*
622 node
= self
.com_node(nodelist
[0])
623 for i
in range(1, len(nodelist
)):
625 if elt
[0] == token
.DOUBLESTAR
:
626 n
= Power([node
, self
.com_node(nodelist
[i
+1])])
630 node
= self
.com_apply_trailer(node
, elt
)
634 def atom(self
, nodelist
):
635 return self
._atom
_dispatch
[nodelist
[0][0]](nodelist
)
637 def atom_lpar(self
, nodelist
):
638 if nodelist
[1][0] == token
.RPAR
:
640 n
.lineno
= nodelist
[0][2]
642 return self
.com_node(nodelist
[1])
644 def atom_lsqb(self
, nodelist
):
645 if nodelist
[1][0] == token
.RSQB
:
647 n
.lineno
= nodelist
[0][2]
649 return self
.com_list_constructor(nodelist
[1])
651 def atom_lbrace(self
, nodelist
):
652 if nodelist
[1][0] == token
.RBRACE
:
654 return self
.com_dictmaker(nodelist
[1])
656 def atom_backquote(self
, nodelist
):
657 n
= Backquote(self
.com_node(nodelist
[1]))
658 n
.lineno
= nodelist
[0][2]
661 def atom_number(self
, nodelist
):
662 ### need to verify this matches compile.c
663 k
= eval(nodelist
[0][1])
665 n
.lineno
= nodelist
[0][2]
668 def atom_string(self
, nodelist
):
669 ### need to verify this matches compile.c
671 for node
in nodelist
:
672 k
= k
+ eval(node
[1])
674 n
.lineno
= nodelist
[0][2]
677 def atom_name(self
, nodelist
):
678 ### any processing to do?
679 n
= Name(nodelist
[0][1])
680 n
.lineno
= nodelist
[0][2]
683 # --------------------------------------------------------------
685 # INTERNAL PARSING UTILITIES
688 def com_node(self
, node
):
689 # Note: compile.c has handling in com_node for del_stmt, pass_stmt,
690 # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
692 # We'll just dispatch them.
693 return self
._dispatch
[node
[0]](node
[1:])
695 def com_NEWLINE(self
):
696 # A ';' at the end of a line can make a NEWLINE token appear
697 # here, Render it harmless. (genc discards ('discard',
698 # ('const', xxxx)) Nodes)
699 return Discard(Const(None))
701 def com_arglist(self
, nodelist
):
703 # (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME]
704 # | fpdef ['=' test] (',' fpdef ['=' test])* [',']
705 # | ('**'|'*' '*') NAME)
706 # fpdef: NAME | '(' fplist ')'
707 # fplist: fpdef (',' fpdef)* [',']
713 while i
< len(nodelist
):
715 if node
[0] == token
.STAR
or node
[0] == token
.DOUBLESTAR
:
716 if node
[0] == token
.STAR
:
718 if node
[0] == token
.NAME
:
719 names
.append(node
[1])
720 flags
= flags | CO_VARARGS
723 if i
< len(nodelist
):
724 # should be DOUBLESTAR or STAR STAR
725 if nodelist
[i
][0] == token
.DOUBLESTAR
:
729 names
.append(node
[1])
730 flags
= flags | CO_VARKEYWORDS
734 # fpdef: NAME | '(' fplist ')'
735 names
.append(self
.com_fpdef(node
))
738 if i
>= len(nodelist
):
741 if nodelist
[i
][0] == token
.EQUAL
:
742 defaults
.append(self
.com_node(nodelist
[i
+ 1]))
745 # Treat "(a=1, b)" as "(a=1, b=None)"
746 defaults
.append(Const(None))
750 return names
, defaults
, flags
752 def com_fpdef(self
, node
):
753 # fpdef: NAME | '(' fplist ')'
754 if node
[1][0] == token
.LPAR
:
755 return self
.com_fplist(node
[2])
758 def com_fplist(self
, node
):
759 # fplist: fpdef (',' fpdef)* [',']
761 return self
.com_fpdef(node
[1])
763 for i
in range(1, len(node
), 2):
764 list.append(self
.com_fpdef(node
[i
]))
767 def com_dotted_name(self
, node
):
768 # String together the dotted names and return the string
771 if type(n
) == type(()) and n
[0] == 1:
772 name
= name
+ n
[1] + '.'
775 def com_dotted_as_name(self
, node
):
776 dot
= self
.com_dotted_name(node
[1])
779 if node
[0] == symbol
.dotted_name
:
782 assert node
[2][1] == 'as'
783 assert node
[3][0] == token
.NAME
784 return dot
, node
[3][1]
786 def com_import_as_name(self
, node
):
789 if node
[0] == token
.NAME
:
791 assert len(node
) == 4
792 assert node
[2][1] == 'as'
793 assert node
[3][0] == token
.NAME
794 return node
[1][1], node
[3][1]
796 def com_bases(self
, node
):
798 for i
in range(1, len(node
), 2):
799 bases
.append(self
.com_node(node
[i
]))
802 def com_try_finally(self
, nodelist
):
803 # try_fin_stmt: "try" ":" suite "finally" ":" suite
804 n
= TryFinally(self
.com_node(nodelist
[2]),
805 self
.com_node(nodelist
[5]))
806 n
.lineno
= nodelist
[0][2]
809 def com_try_except(self
, nodelist
):
810 # try_except: 'try' ':' suite (except_clause ':' suite)* ['else' suite]
811 #tryexcept: [TryNode, [except_clauses], elseNode)]
812 stmt
= self
.com_node(nodelist
[2])
815 for i
in range(3, len(nodelist
), 3):
817 if node
[0] == symbol
.except_clause
:
818 # except_clause: 'except' [expr [',' expr]] */
820 expr1
= self
.com_node(node
[2])
822 expr2
= self
.com_assign(node
[4], OP_ASSIGN
)
827 clauses
.append((expr1
, expr2
, self
.com_node(nodelist
[i
+2])))
829 if node
[0] == token
.NAME
:
830 elseNode
= self
.com_node(nodelist
[i
+2])
831 n
= TryExcept(self
.com_node(nodelist
[2]), clauses
, elseNode
)
832 n
.lineno
= nodelist
[0][2]
835 def com_augassign_op(self
, node
):
836 assert node
[0] == symbol
.augassign
839 def com_augassign(self
, node
):
840 """Return node suitable for lvalue of augmented assignment
842 Names, slices, and attributes are the only allowable nodes.
844 l
= self
.com_node(node
)
845 if l
.__class
__ in (Name
, Slice
, Subscript
, Getattr
):
847 raise SyntaxError, "can't assign to %s" % l
.__class
__.__name
__
849 def com_assign(self
, node
, assigning
):
850 # return a node suitable for use as an "lvalue"
851 # loop to avoid trivial recursion
854 if t
== symbol
.exprlist
or t
== symbol
.testlist
:
856 return self
.com_assign_tuple(node
, assigning
)
858 elif t
in _assign_types
:
860 raise SyntaxError, "can't assign to operator"
862 elif t
== symbol
.power
:
863 if node
[1][0] != symbol
.atom
:
864 raise SyntaxError, "can't assign to operator"
866 primary
= self
.com_node(node
[1])
867 for i
in range(2, len(node
)-1):
869 if ch
[0] == token
.DOUBLESTAR
:
870 raise SyntaxError, "can't assign to operator"
871 primary
= self
.com_apply_trailer(primary
, ch
)
872 return self
.com_assign_trailer(primary
, node
[-1],
875 elif t
== symbol
.atom
:
879 if node
[0] == token
.RPAR
:
880 raise SyntaxError, "can't assign to ()"
881 elif t
== token
.LSQB
:
883 if node
[0] == token
.RSQB
:
884 raise SyntaxError, "can't assign to []"
885 return self
.com_assign_list(node
, assigning
)
886 elif t
== token
.NAME
:
887 return self
.com_assign_name(node
[1], assigning
)
889 raise SyntaxError, "can't assign to literal"
891 raise SyntaxError, "bad assignment"
893 def com_assign_tuple(self
, node
, assigning
):
895 for i
in range(1, len(node
), 2):
896 assigns
.append(self
.com_assign(node
[i
], assigning
))
897 return AssTuple(assigns
)
899 def com_assign_list(self
, node
, assigning
):
901 for i
in range(1, len(node
), 2):
902 assigns
.append(self
.com_assign(node
[i
], assigning
))
903 return AssList(assigns
)
905 def com_assign_name(self
, node
, assigning
):
906 n
= AssName(node
[1], assigning
)
910 def com_assign_trailer(self
, primary
, node
, assigning
):
913 return self
.com_assign_attr(primary
, node
[2], assigning
)
915 return self
.com_subscriptlist(primary
, node
[2], assigning
)
917 raise SyntaxError, "can't assign to function call"
918 raise SyntaxError, "unknown trailer type: %s" % t
920 def com_assign_attr(self
, primary
, node
, assigning
):
921 return AssAttr(primary
, node
[1], assigning
)
923 def com_binary(self
, constructor
, nodelist
):
924 "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
927 return self
.com_node(nodelist
[0])
929 for i
in range(0, l
, 2):
930 items
.append(self
.com_node(nodelist
[i
]))
931 return constructor(items
)
933 def com_stmt(self
, node
):
934 result
= self
.com_node(node
)
935 assert result
is not None
936 if isinstance(result
, Stmt
):
938 return Stmt([result
])
940 def com_append_stmt(self
, stmts
, node
):
941 result
= self
.com_node(node
)
942 assert result
is not None
943 if isinstance(result
, Stmt
):
944 stmts
.extend(result
.nodes
)
948 if hasattr(symbol
, 'list_for'):
949 def com_list_constructor(self
, nodelist
):
950 # listmaker: test ( list_for | (',' test)* [','] )
952 for i
in range(1, len(nodelist
)):
953 if nodelist
[i
][0] == symbol
.list_for
:
954 assert len(nodelist
[i
:]) == 1
955 return self
.com_list_comprehension(values
[0],
957 elif nodelist
[i
][0] == token
.COMMA
:
959 values
.append(self
.com_node(nodelist
[i
]))
962 def com_list_comprehension(self
, expr
, node
):
963 # list_iter: list_for | list_if
964 # list_for: 'for' exprlist 'in' testlist [list_iter]
965 # list_if: 'if' test [list_iter]
971 assignNode
= self
.com_assign(node
[2], OP_ASSIGN
)
972 listNode
= self
.com_node(node
[4])
973 newfor
= ListCompFor(assignNode
, listNode
, [])
974 newfor
.lineno
= node
[1][2]
979 node
= self
.com_list_iter(node
[5])
981 test
= self
.com_node(node
[2])
982 newif
= ListCompIf(test
)
983 newif
.lineno
= node
[1][2]
984 newfor
.ifs
.append(newif
)
988 node
= self
.com_list_iter(node
[3])
991 ("unexpected list comprehension element: %s %d"
993 n
= ListComp(expr
, fors
)
997 def com_list_iter(self
, node
):
998 assert node
[0] == symbol
.list_iter
1001 def com_list_constructor(self
, nodelist
):
1003 for i
in range(1, len(nodelist
), 2):
1004 values
.append(self
.com_node(nodelist
[i
]))
1007 def com_dictmaker(self
, nodelist
):
1008 # dictmaker: test ':' test (',' test ':' value)* [',']
1010 for i
in range(1, len(nodelist
), 4):
1011 items
.append((self
.com_node(nodelist
[i
]),
1012 self
.com_node(nodelist
[i
+2])))
1015 def com_apply_trailer(self
, primaryNode
, nodelist
):
1018 return self
.com_call_function(primaryNode
, nodelist
[2])
1020 return self
.com_select_member(primaryNode
, nodelist
[2])
1022 return self
.com_subscriptlist(primaryNode
, nodelist
[2], OP_APPLY
)
1024 raise SyntaxError, 'unknown node type: %s' % t
1026 def com_select_member(self
, primaryNode
, nodelist
):
1027 if nodelist
[0] != token
.NAME
:
1028 raise SyntaxError, "member must be a name"
1029 n
= Getattr(primaryNode
, nodelist
[1])
1030 n
.lineno
= nodelist
[2]
1033 def com_call_function(self
, primaryNode
, nodelist
):
1034 if nodelist
[0] == token
.RPAR
:
1035 return CallFunc(primaryNode
, [])
1038 len_nodelist
= len(nodelist
)
1039 for i
in range(1, len_nodelist
, 2):
1041 if node
[0] == token
.STAR
or node
[0] == token
.DOUBLESTAR
:
1043 kw
, result
= self
.com_argument(node
, kw
)
1046 # No broken by star arg, so skip the last one we processed.
1048 if i
< len_nodelist
and nodelist
[i
][0] == token
.COMMA
:
1049 # need to accept an application that looks like "f(a, b,)"
1051 star_node
= dstar_node
= None
1052 while i
< len_nodelist
:
1056 if tok
[0]==token
.STAR
:
1057 if star_node
is not None:
1058 raise SyntaxError, 'already have the varargs indentifier'
1059 star_node
= self
.com_node(ch
)
1060 elif tok
[0]==token
.DOUBLESTAR
:
1061 if dstar_node
is not None:
1062 raise SyntaxError, 'already have the kwargs indentifier'
1063 dstar_node
= self
.com_node(ch
)
1065 raise SyntaxError, 'unknown node type: %s' % tok
1067 return CallFunc(primaryNode
, args
, star_node
, dstar_node
)
1069 def com_argument(self
, nodelist
, kw
):
1070 if len(nodelist
) == 2:
1072 raise SyntaxError, "non-keyword arg after keyword arg"
1073 return 0, self
.com_node(nodelist
[1])
1074 result
= self
.com_node(nodelist
[3])
1076 while len(n
) == 2 and n
[0] != token
.NAME
:
1078 if n
[0] != token
.NAME
:
1079 raise SyntaxError, "keyword can't be an expression (%s)"%n
[0]
1080 node
= Keyword(n
[1], result
)
1084 def com_subscriptlist(self
, primary
, nodelist
, assigning
):
1085 # slicing: simple_slicing | extended_slicing
1086 # simple_slicing: primary "[" short_slice "]"
1087 # extended_slicing: primary "[" slice_list "]"
1088 # slice_list: slice_item ("," slice_item)* [","]
1090 # backwards compat slice for '[i:j]'
1091 if len(nodelist
) == 2:
1093 if (sub
[1][0] == token
.COLON
or \
1094 (len(sub
) > 2 and sub
[2][0] == token
.COLON
)) and \
1095 sub
[-1][0] != symbol
.sliceop
:
1096 return self
.com_slice(primary
, sub
, assigning
)
1099 for i
in range(1, len(nodelist
), 2):
1100 subscripts
.append(self
.com_subscript(nodelist
[i
]))
1102 return Subscript(primary
, assigning
, subscripts
)
1104 def com_subscript(self
, node
):
1105 # slice_item: expression | proper_slice | ellipsis
1108 if t
== token
.DOT
and node
[2][0] == token
.DOT
:
1110 if t
== token
.COLON
or len(node
) > 2:
1111 return self
.com_sliceobj(node
)
1112 return self
.com_node(ch
)
1114 def com_sliceobj(self
, node
):
1115 # proper_slice: short_slice | long_slice
1116 # short_slice: [lower_bound] ":" [upper_bound]
1117 # long_slice: short_slice ":" [stride]
1118 # lower_bound: expression
1119 # upper_bound: expression
1120 # stride: expression
1122 # Note: a stride may be further slicing...
1126 if node
[1][0] == token
.COLON
:
1127 items
.append(Const(None))
1130 items
.append(self
.com_node(node
[1]))
1134 if i
< len(node
) and node
[i
][0] == symbol
.test
:
1135 items
.append(self
.com_node(node
[i
]))
1138 items
.append(Const(None))
1140 # a short_slice has been built. look for long_slice now by looking
1142 for j
in range(i
, len(node
)):
1145 items
.append(Const(None))
1147 items
.append(self
.com_node(ch
[2]))
1149 return Sliceobj(items
)
1151 def com_slice(self
, primary
, node
, assigning
):
1152 # short_slice: [lower_bound] ":" [upper_bound]
1153 lower
= upper
= None
1155 if node
[1][0] == token
.COLON
:
1156 upper
= self
.com_node(node
[2])
1158 lower
= self
.com_node(node
[1])
1159 elif len(node
) == 4:
1160 lower
= self
.com_node(node
[1])
1161 upper
= self
.com_node(node
[3])
1162 return Slice(primary
, assigning
, lower
, upper
)
1164 def get_docstring(self
, node
, n
=None):
1168 if n
== symbol
.suite
:
1170 return self
.get_docstring(node
[0])
1172 if sub
[0] == symbol
.stmt
:
1173 return self
.get_docstring(sub
)
1175 if n
== symbol
.file_input
:
1177 if sub
[0] == symbol
.stmt
:
1178 return self
.get_docstring(sub
)
1180 if n
== symbol
.atom
:
1181 if node
[0][0] == token
.STRING
:
1187 if n
== symbol
.stmt
or n
== symbol
.simple_stmt \
1188 or n
== symbol
.small_stmt
:
1189 return self
.get_docstring(node
[0])
1190 if n
in _doc_nodes
and len(node
) == 1:
1191 return self
.get_docstring(node
[0])
1212 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
1213 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
1216 token
.GREATER
: '>',
1217 token
.EQEQUAL
: '==',
1219 token
.LESSEQUAL
: '<=',
1220 token
.GREATEREQUAL
: '>=',
1221 token
.NOTEQUAL
: '!=',
1224 _legal_node_types
= [
1231 symbol
.compound_stmt
,
1237 symbol
.continue_stmt
,
1282 for k
, v
in symbol
.sym_name
.items():
1284 for k
, v
in token
.tok_name
.items():
1287 def debug_tree(tree
):
1290 if type(elt
) == types
.IntType
:
1291 l
.append(_names
.get(elt
, elt
))
1292 elif type(elt
) == types
.StringType
:
1295 l
.append(debug_tree(elt
))