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 # Some fixes to try to have correct line number on almost all nodes
19 # (except Module, Discard and Stmt) added by Sylvain Thenault
21 # Portions of this file are:
22 # Copyright (C) 1997-1998 Greg Stein. All Rights Reserved.
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.
28 from compiler
.ast
import *
33 class WalkerError(StandardError):
36 from compiler
.consts
import CO_VARARGS
, CO_VARKEYWORDS
37 from compiler
.consts
import OP_ASSIGN
, OP_DELETE
, OP_APPLY
41 # XXX The parser API tolerates files without a trailing newline,
42 # but not strings without a trailing newline. Always add an extra
43 # newline to the file contents, since we're going through the string
49 def parse(buf
, mode
="exec"):
50 if mode
== "exec" or mode
== "single":
51 return Transformer().parsesuite(buf
)
53 return Transformer().parseexpr(buf
)
55 raise ValueError("compile() arg 3 must be"
56 " 'exec' or 'eval' or 'single'")
61 if hasattr(item
, "asList"):
62 l
.append(item
.asList())
64 if type(item
) is type( (None, None) ):
65 l
.append(tuple(asList(item
)))
66 elif type(item
) is type( [] ):
67 l
.append(asList(item
))
72 def extractLineNo(ast
):
73 if not isinstance(ast
[1], tuple):
77 if isinstance(child
, tuple):
78 lineno
= extractLineNo(child
)
79 if lineno
is not None:
86 return nodes
[kind
](*args
[1:])
88 print nodes
[kind
], len(args
), args
91 raise WalkerError
, "Can't find appropriate Node type: %s" % str(args
)
92 #return apply(ast.Node, args)
95 """Utility object for transforming Python parse trees.
97 Exposes the following methods:
98 tree = transform(ast_tree)
99 tree = parsesuite(text)
100 tree = parseexpr(text)
101 tree = parsefile(fileob | filename)
106 for value
, name
in symbol
.sym_name
.items():
107 if hasattr(self
, name
):
108 self
._dispatch
[value
] = getattr(self
, name
)
109 self
._dispatch
[token
.NEWLINE
] = self
.com_NEWLINE
110 self
._atom
_dispatch
= {token
.LPAR
: self
.atom_lpar
,
111 token
.LSQB
: self
.atom_lsqb
,
112 token
.LBRACE
: self
.atom_lbrace
,
113 token
.BACKQUOTE
: self
.atom_backquote
,
114 token
.NUMBER
: self
.atom_number
,
115 token
.STRING
: self
.atom_string
,
116 token
.NAME
: self
.atom_name
,
120 def transform(self
, tree
):
121 """Transform an AST into a modified parse tree."""
122 if not (isinstance(tree
, tuple) or isinstance(tree
, list)):
123 tree
= parser
.st2tuple(tree
, line_info
=1)
124 return self
.compile_node(tree
)
126 def parsesuite(self
, text
):
127 """Return a modified parse tree for the given suite text."""
128 return self
.transform(parser
.suite(text
))
130 def parseexpr(self
, text
):
131 """Return a modified parse tree for the given expression text."""
132 return self
.transform(parser
.expr(text
))
134 def parsefile(self
, file):
135 """Return a modified parse tree for the contents of the given file."""
136 if type(file) == type(''):
138 return self
.parsesuite(file.read())
140 # --------------------------------------------------------------
145 def compile_node(self
, node
):
146 ### emit a line-number node?
149 if n
== symbol
.encoding_decl
:
150 self
.encoding
= node
[2]
154 if n
== symbol
.single_input
:
155 return self
.single_input(node
[1:])
156 if n
== symbol
.file_input
:
157 return self
.file_input(node
[1:])
158 if n
== symbol
.eval_input
:
159 return self
.eval_input(node
[1:])
160 if n
== symbol
.lambdef
:
161 return self
.lambdef(node
[1:])
162 if n
== symbol
.funcdef
:
163 return self
.funcdef(node
[1:])
164 if n
== symbol
.classdef
:
165 return self
.classdef(node
[1:])
167 raise WalkerError
, ('unexpected node type', n
)
169 def single_input(self
, node
):
170 ### do we want to do anything about being "interactive" ?
172 # NEWLINE | simple_stmt | compound_stmt NEWLINE
174 if n
!= token
.NEWLINE
:
175 return self
.com_stmt(node
[0])
179 def file_input(self
, nodelist
):
180 doc
= self
.get_docstring(nodelist
, symbol
.file_input
)
186 for node
in nodelist
[i
:]:
187 if node
[0] != token
.ENDMARKER
and node
[0] != token
.NEWLINE
:
188 self
.com_append_stmt(stmts
, node
)
189 return Module(doc
, Stmt(stmts
))
191 def eval_input(self
, nodelist
):
192 # from the built-in function input()
193 ### is this sufficient?
194 return Expression(self
.com_node(nodelist
[0]))
196 def decorator_name(self
, nodelist
):
197 listlen
= len(nodelist
)
198 assert listlen
>= 1 and listlen
% 2 == 1
200 item
= self
.atom_name(nodelist
)
203 assert nodelist
[i
][0] == token
.DOT
204 assert nodelist
[i
+ 1][0] == token
.NAME
205 item
= Getattr(item
, nodelist
[i
+ 1][1])
210 def decorator(self
, nodelist
):
211 # '@' dotted_name [ '(' [arglist] ')' ]
212 assert len(nodelist
) in (3, 5, 6)
213 assert nodelist
[0][0] == token
.AT
214 assert nodelist
[-1][0] == token
.NEWLINE
216 assert nodelist
[1][0] == symbol
.dotted_name
217 funcname
= self
.decorator_name(nodelist
[1][1:])
219 if len(nodelist
) > 3:
220 assert nodelist
[2][0] == token
.LPAR
221 expr
= self
.com_call_function(funcname
, nodelist
[3])
227 def decorators(self
, nodelist
):
228 # decorators: decorator ([NEWLINE] decorator)* NEWLINE
230 for dec_nodelist
in nodelist
:
231 assert dec_nodelist
[0] == symbol
.decorator
232 items
.append(self
.decorator(dec_nodelist
[1:]))
233 return Decorators(items
)
235 def decorated(self
, nodelist
):
236 assert nodelist
[0][0] == symbol
.decorators
237 if nodelist
[1][0] == symbol
.funcdef
:
238 n
= [nodelist
[0]] + list(nodelist
[1][1:])
239 return self
.funcdef(n
)
240 elif nodelist
[1][0] == symbol
.classdef
:
241 decorators
= self
.decorators(nodelist
[0][1:])
242 cls
= self
.classdef(nodelist
[1][1:])
243 cls
.decorators
= decorators
247 def funcdef(self
, nodelist
):
249 # funcdef: [decorators] 'def' NAME parameters ':' suite
250 # parameters: '(' [varargslist] ')'
252 if len(nodelist
) == 6:
253 assert nodelist
[0][0] == symbol
.decorators
254 decorators
= self
.decorators(nodelist
[0][1:])
256 assert len(nodelist
) == 5
259 lineno
= nodelist
[-4][2]
260 name
= nodelist
[-4][1]
261 args
= nodelist
[-3][2]
263 if args
[0] == symbol
.varargslist
:
264 names
, defaults
, flags
= self
.com_arglist(args
[1:])
266 names
= defaults
= ()
268 doc
= self
.get_docstring(nodelist
[-1])
271 code
= self
.com_node(nodelist
[-1])
274 assert isinstance(code
, Stmt
)
275 assert isinstance(code
.nodes
[0], Discard
)
277 return Function(decorators
, name
, names
, defaults
, flags
, doc
, code
,
280 def lambdef(self
, nodelist
):
281 # lambdef: 'lambda' [varargslist] ':' test
282 if nodelist
[2][0] == symbol
.varargslist
:
283 names
, defaults
, flags
= self
.com_arglist(nodelist
[2][1:])
285 names
= defaults
= ()
289 code
= self
.com_node(nodelist
[-1])
291 return Lambda(names
, defaults
, flags
, code
, lineno
=nodelist
[1][2])
292 old_lambdef
= lambdef
294 def classdef(self
, nodelist
):
295 # classdef: 'class' NAME ['(' [testlist] ')'] ':' suite
297 name
= nodelist
[1][1]
298 doc
= self
.get_docstring(nodelist
[-1])
299 if nodelist
[2][0] == token
.COLON
:
301 elif nodelist
[3][0] == token
.RPAR
:
304 bases
= self
.com_bases(nodelist
[3])
307 code
= self
.com_node(nodelist
[-1])
310 assert isinstance(code
, Stmt
)
311 assert isinstance(code
.nodes
[0], Discard
)
314 return Class(name
, bases
, doc
, code
, lineno
=nodelist
[1][2])
316 def stmt(self
, nodelist
):
317 return self
.com_stmt(nodelist
[0])
323 def simple_stmt(self
, nodelist
):
324 # small_stmt (';' small_stmt)* [';'] NEWLINE
326 for i
in range(0, len(nodelist
), 2):
327 self
.com_append_stmt(stmts
, nodelist
[i
])
330 def parameters(self
, nodelist
):
333 def varargslist(self
, nodelist
):
336 def fpdef(self
, nodelist
):
339 def fplist(self
, nodelist
):
342 def dotted_name(self
, nodelist
):
345 def comp_op(self
, nodelist
):
348 def trailer(self
, nodelist
):
351 def sliceop(self
, nodelist
):
354 def argument(self
, nodelist
):
357 # --------------------------------------------------------------
359 # STATEMENT NODES (invoked by com_node())
362 def expr_stmt(self
, nodelist
):
363 # augassign testlist | testlist ('=' testlist)*
365 exprNode
= self
.lookup_node(en
)(en
[1:])
366 if len(nodelist
) == 1:
367 return Discard(exprNode
, lineno
=exprNode
.lineno
)
368 if nodelist
[1][0] == token
.EQUAL
:
370 for i
in range(0, len(nodelist
) - 2, 2):
371 nodesl
.append(self
.com_assign(nodelist
[i
], OP_ASSIGN
))
372 return Assign(nodesl
, exprNode
, lineno
=nodelist
[1][2])
374 lval
= self
.com_augassign(nodelist
[0])
375 op
= self
.com_augassign_op(nodelist
[1])
376 return AugAssign(lval
, op
[1], exprNode
, lineno
=op
[2])
377 raise WalkerError
, "can't get here"
379 def print_stmt(self
, nodelist
):
380 # print ([ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ])
382 if len(nodelist
) == 1:
385 elif nodelist
[1][0] == token
.RIGHTSHIFT
:
386 assert len(nodelist
) == 3 \
387 or nodelist
[3][0] == token
.COMMA
388 dest
= self
.com_node(nodelist
[2])
393 for i
in range(start
, len(nodelist
), 2):
394 items
.append(self
.com_node(nodelist
[i
]))
395 if nodelist
[-1][0] == token
.COMMA
:
396 return Print(items
, dest
, lineno
=nodelist
[0][2])
397 return Printnl(items
, dest
, lineno
=nodelist
[0][2])
399 def del_stmt(self
, nodelist
):
400 return self
.com_assign(nodelist
[1], OP_DELETE
)
402 def pass_stmt(self
, nodelist
):
403 return Pass(lineno
=nodelist
[0][2])
405 def break_stmt(self
, nodelist
):
406 return Break(lineno
=nodelist
[0][2])
408 def continue_stmt(self
, nodelist
):
409 return Continue(lineno
=nodelist
[0][2])
411 def return_stmt(self
, nodelist
):
413 if len(nodelist
) < 2:
414 return Return(Const(None), lineno
=nodelist
[0][2])
415 return Return(self
.com_node(nodelist
[1]), lineno
=nodelist
[0][2])
417 def yield_stmt(self
, nodelist
):
418 expr
= self
.com_node(nodelist
[0])
419 return Discard(expr
, lineno
=expr
.lineno
)
421 def yield_expr(self
, nodelist
):
422 if len(nodelist
) > 1:
423 value
= self
.com_node(nodelist
[1])
426 return Yield(value
, lineno
=nodelist
[0][2])
428 def raise_stmt(self
, nodelist
):
429 # raise: [test [',' test [',' test]]]
430 if len(nodelist
) > 5:
431 expr3
= self
.com_node(nodelist
[5])
434 if len(nodelist
) > 3:
435 expr2
= self
.com_node(nodelist
[3])
438 if len(nodelist
) > 1:
439 expr1
= self
.com_node(nodelist
[1])
442 return Raise(expr1
, expr2
, expr3
, lineno
=nodelist
[0][2])
444 def import_stmt(self
, nodelist
):
445 # import_stmt: import_name | import_from
446 assert len(nodelist
) == 1
447 return self
.com_node(nodelist
[0])
449 def import_name(self
, nodelist
):
450 # import_name: 'import' dotted_as_names
451 return Import(self
.com_dotted_as_names(nodelist
[1]),
452 lineno
=nodelist
[0][2])
454 def import_from(self
, nodelist
):
455 # import_from: 'from' ('.'* dotted_name | '.') 'import' ('*' |
456 # '(' import_as_names ')' | import_as_names)
457 assert nodelist
[0][1] == 'from'
459 while nodelist
[idx
][1] == '.':
462 if nodelist
[idx
][0] == symbol
.dotted_name
:
463 fromname
= self
.com_dotted_name(nodelist
[idx
])
467 assert nodelist
[idx
][1] == 'import'
468 if nodelist
[idx
+ 1][0] == token
.STAR
:
469 return From(fromname
, [('*', None)], level
,
470 lineno
=nodelist
[0][2])
472 node
= nodelist
[idx
+ 1 + (nodelist
[idx
+ 1][0] == token
.LPAR
)]
473 return From(fromname
, self
.com_import_as_names(node
), level
,
474 lineno
=nodelist
[0][2])
476 def global_stmt(self
, nodelist
):
477 # global: NAME (',' NAME)*
479 for i
in range(1, len(nodelist
), 2):
480 names
.append(nodelist
[i
][1])
481 return Global(names
, lineno
=nodelist
[0][2])
483 def exec_stmt(self
, nodelist
):
484 # exec_stmt: 'exec' expr ['in' expr [',' expr]]
485 expr1
= self
.com_node(nodelist
[1])
486 if len(nodelist
) >= 4:
487 expr2
= self
.com_node(nodelist
[3])
488 if len(nodelist
) >= 6:
489 expr3
= self
.com_node(nodelist
[5])
495 return Exec(expr1
, expr2
, expr3
, lineno
=nodelist
[0][2])
497 def assert_stmt(self
, nodelist
):
498 # 'assert': test, [',' test]
499 expr1
= self
.com_node(nodelist
[1])
500 if (len(nodelist
) == 4):
501 expr2
= self
.com_node(nodelist
[3])
504 return Assert(expr1
, expr2
, lineno
=nodelist
[0][2])
506 def if_stmt(self
, nodelist
):
507 # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
509 for i
in range(0, len(nodelist
) - 3, 4):
510 testNode
= self
.com_node(nodelist
[i
+ 1])
511 suiteNode
= self
.com_node(nodelist
[i
+ 3])
512 tests
.append((testNode
, suiteNode
))
514 if len(nodelist
) % 4 == 3:
515 elseNode
= self
.com_node(nodelist
[-1])
516 ## elseNode.lineno = nodelist[-1][1][2]
519 return If(tests
, elseNode
, lineno
=nodelist
[0][2])
521 def while_stmt(self
, nodelist
):
522 # 'while' test ':' suite ['else' ':' suite]
524 testNode
= self
.com_node(nodelist
[1])
525 bodyNode
= self
.com_node(nodelist
[3])
527 if len(nodelist
) > 4:
528 elseNode
= self
.com_node(nodelist
[6])
532 return While(testNode
, bodyNode
, elseNode
, lineno
=nodelist
[0][2])
534 def for_stmt(self
, nodelist
):
535 # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
537 assignNode
= self
.com_assign(nodelist
[1], OP_ASSIGN
)
538 listNode
= self
.com_node(nodelist
[3])
539 bodyNode
= self
.com_node(nodelist
[5])
541 if len(nodelist
) > 8:
542 elseNode
= self
.com_node(nodelist
[8])
546 return For(assignNode
, listNode
, bodyNode
, elseNode
,
547 lineno
=nodelist
[0][2])
549 def try_stmt(self
, nodelist
):
550 return self
.com_try_except_finally(nodelist
)
552 def with_stmt(self
, nodelist
):
553 return self
.com_with(nodelist
)
555 def with_var(self
, nodelist
):
556 return self
.com_with_var(nodelist
)
558 def suite(self
, nodelist
):
559 # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
560 if len(nodelist
) == 1:
561 return self
.com_stmt(nodelist
[0])
564 for node
in nodelist
:
565 if node
[0] == symbol
.stmt
:
566 self
.com_append_stmt(stmts
, node
)
569 # --------------------------------------------------------------
571 # EXPRESSION NODES (invoked by com_node())
574 def testlist(self
, nodelist
):
575 # testlist: expr (',' expr)* [',']
576 # testlist_safe: test [(',' test)+ [',']]
577 # exprlist: expr (',' expr)* [',']
578 return self
.com_binary(Tuple
, nodelist
)
580 testlist_safe
= testlist
# XXX
584 def testlist_comp(self
, nodelist
):
585 # test ( comp_for | (',' test)* [','] )
586 assert nodelist
[0][0] == symbol
.test
587 if len(nodelist
) == 2 and nodelist
[1][0] == symbol
.comp_for
:
588 test
= self
.com_node(nodelist
[0])
589 return self
.com_generator_expression(test
, nodelist
[1])
590 return self
.testlist(nodelist
)
592 def test(self
, nodelist
):
593 # or_test ['if' or_test 'else' test] | lambdef
594 if len(nodelist
) == 1 and nodelist
[0][0] == symbol
.lambdef
:
595 return self
.lambdef(nodelist
[0])
596 then
= self
.com_node(nodelist
[0])
597 if len(nodelist
) > 1:
598 assert len(nodelist
) == 5
599 assert nodelist
[1][1] == 'if'
600 assert nodelist
[3][1] == 'else'
601 test
= self
.com_node(nodelist
[2])
602 else_
= self
.com_node(nodelist
[4])
603 return IfExp(test
, then
, else_
, lineno
=nodelist
[1][2])
606 def or_test(self
, nodelist
):
607 # and_test ('or' and_test)* | lambdef
608 if len(nodelist
) == 1 and nodelist
[0][0] == symbol
.lambdef
:
609 return self
.lambdef(nodelist
[0])
610 return self
.com_binary(Or
, nodelist
)
613 def and_test(self
, nodelist
):
614 # not_test ('and' not_test)*
615 return self
.com_binary(And
, nodelist
)
617 def not_test(self
, nodelist
):
618 # 'not' not_test | comparison
619 result
= self
.com_node(nodelist
[-1])
620 if len(nodelist
) == 2:
621 return Not(result
, lineno
=nodelist
[0][2])
624 def comparison(self
, nodelist
):
625 # comparison: expr (comp_op expr)*
626 node
= self
.com_node(nodelist
[0])
627 if len(nodelist
) == 1:
631 for i
in range(2, len(nodelist
), 2):
634 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
635 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
637 if n
[0] == token
.NAME
:
645 type = _cmp_types
[n
[0]]
648 results
.append((type, self
.com_node(nodelist
[i
])))
650 # we need a special "compare" node so that we can distinguish
651 # 3 < x < 5 from (3 < x) < 5
652 # the two have very different semantics and results (note that the
653 # latter form is always true)
655 return Compare(node
, results
, lineno
=lineno
)
657 def expr(self
, nodelist
):
658 # xor_expr ('|' xor_expr)*
659 return self
.com_binary(Bitor
, nodelist
)
661 def xor_expr(self
, nodelist
):
662 # xor_expr ('^' xor_expr)*
663 return self
.com_binary(Bitxor
, nodelist
)
665 def and_expr(self
, nodelist
):
666 # xor_expr ('&' xor_expr)*
667 return self
.com_binary(Bitand
, nodelist
)
669 def shift_expr(self
, nodelist
):
670 # shift_expr ('<<'|'>>' shift_expr)*
671 node
= self
.com_node(nodelist
[0])
672 for i
in range(2, len(nodelist
), 2):
673 right
= self
.com_node(nodelist
[i
])
674 if nodelist
[i
-1][0] == token
.LEFTSHIFT
:
675 node
= LeftShift([node
, right
], lineno
=nodelist
[1][2])
676 elif nodelist
[i
-1][0] == token
.RIGHTSHIFT
:
677 node
= RightShift([node
, right
], lineno
=nodelist
[1][2])
679 raise ValueError, "unexpected token: %s" % nodelist
[i
-1][0]
682 def arith_expr(self
, nodelist
):
683 node
= self
.com_node(nodelist
[0])
684 for i
in range(2, len(nodelist
), 2):
685 right
= self
.com_node(nodelist
[i
])
686 if nodelist
[i
-1][0] == token
.PLUS
:
687 node
= Add([node
, right
], lineno
=nodelist
[1][2])
688 elif nodelist
[i
-1][0] == token
.MINUS
:
689 node
= Sub([node
, right
], lineno
=nodelist
[1][2])
691 raise ValueError, "unexpected token: %s" % nodelist
[i
-1][0]
694 def term(self
, nodelist
):
695 node
= self
.com_node(nodelist
[0])
696 for i
in range(2, len(nodelist
), 2):
697 right
= self
.com_node(nodelist
[i
])
700 node
= Mul([node
, right
])
701 elif t
== token
.SLASH
:
702 node
= Div([node
, right
])
703 elif t
== token
.PERCENT
:
704 node
= Mod([node
, right
])
705 elif t
== token
.DOUBLESLASH
:
706 node
= FloorDiv([node
, right
])
708 raise ValueError, "unexpected token: %s" % t
709 node
.lineno
= nodelist
[1][2]
712 def factor(self
, nodelist
):
715 node
= self
.lookup_node(nodelist
[-1])(nodelist
[-1][1:])
716 # need to handle (unary op)constant here...
718 return UnaryAdd(node
, lineno
=elt
[2])
719 elif t
== token
.MINUS
:
720 return UnarySub(node
, lineno
=elt
[2])
721 elif t
== token
.TILDE
:
722 node
= Invert(node
, lineno
=elt
[2])
725 def power(self
, nodelist
):
726 # power: atom trailer* ('**' factor)*
727 node
= self
.com_node(nodelist
[0])
728 for i
in range(1, len(nodelist
)):
730 if elt
[0] == token
.DOUBLESTAR
:
731 return Power([node
, self
.com_node(nodelist
[i
+1])],
734 node
= self
.com_apply_trailer(node
, elt
)
738 def atom(self
, nodelist
):
739 return self
._atom
_dispatch
[nodelist
[0][0]](nodelist
)
741 def atom_lpar(self
, nodelist
):
742 if nodelist
[1][0] == token
.RPAR
:
743 return Tuple((), lineno
=nodelist
[0][2])
744 return self
.com_node(nodelist
[1])
746 def atom_lsqb(self
, nodelist
):
747 if nodelist
[1][0] == token
.RSQB
:
748 return List((), lineno
=nodelist
[0][2])
749 return self
.com_list_constructor(nodelist
[1])
751 def atom_lbrace(self
, nodelist
):
752 if nodelist
[1][0] == token
.RBRACE
:
753 return Dict((), lineno
=nodelist
[0][2])
754 return self
.com_dictorsetmaker(nodelist
[1])
756 def atom_backquote(self
, nodelist
):
757 return Backquote(self
.com_node(nodelist
[1]))
759 def atom_number(self
, nodelist
):
760 ### need to verify this matches compile.c
761 k
= eval(nodelist
[0][1])
762 return Const(k
, lineno
=nodelist
[0][2])
764 def decode_literal(self
, lit
):
766 # this is particularly fragile & a bit of a
767 # hack... changes in compile.c:parsestr and
768 # tokenizer.c must be reflected here.
769 if self
.encoding
not in ['utf-8', 'iso-8859-1']:
770 lit
= unicode(lit
, 'utf-8').encode(self
.encoding
)
771 return eval("# coding: %s\n%s" % (self
.encoding
, lit
))
775 def atom_string(self
, nodelist
):
777 for node
in nodelist
:
778 k
+= self
.decode_literal(node
[1])
779 return Const(k
, lineno
=nodelist
[0][2])
781 def atom_name(self
, nodelist
):
782 return Name(nodelist
[0][1], lineno
=nodelist
[0][2])
784 # --------------------------------------------------------------
786 # INTERNAL PARSING UTILITIES
789 # The use of com_node() introduces a lot of extra stack frames,
790 # enough to cause a stack overflow compiling test.test_parser with
791 # the standard interpreter recursionlimit. The com_node() is a
792 # convenience function that hides the dispatch details, but comes
793 # at a very high cost. It is more efficient to dispatch directly
794 # in the callers. In these cases, use lookup_node() and call the
795 # dispatched node directly.
797 def lookup_node(self
, node
):
798 return self
._dispatch
[node
[0]]
800 def com_node(self
, node
):
801 # Note: compile.c has handling in com_node for del_stmt, pass_stmt,
802 # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
804 # We'll just dispatch them.
805 return self
._dispatch
[node
[0]](node
[1:])
807 def com_NEWLINE(self
, *args
):
808 # A ';' at the end of a line can make a NEWLINE token appear
809 # here, Render it harmless. (genc discards ('discard',
810 # ('const', xxxx)) Nodes)
811 return Discard(Const(None))
813 def com_arglist(self
, nodelist
):
815 # (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME)
816 # | fpdef ['=' test] (',' fpdef ['=' test])* [',']
817 # fpdef: NAME | '(' fplist ')'
818 # fplist: fpdef (',' fpdef)* [',']
824 while i
< len(nodelist
):
826 if node
[0] == token
.STAR
or node
[0] == token
.DOUBLESTAR
:
827 if node
[0] == token
.STAR
:
829 if node
[0] == token
.NAME
:
830 names
.append(node
[1])
831 flags
= flags | CO_VARARGS
834 if i
< len(nodelist
):
835 # should be DOUBLESTAR
837 if t
== token
.DOUBLESTAR
:
840 raise ValueError, "unexpected token: %s" % t
841 names
.append(node
[1])
842 flags
= flags | CO_VARKEYWORDS
846 # fpdef: NAME | '(' fplist ')'
847 names
.append(self
.com_fpdef(node
))
850 if i
< len(nodelist
) and nodelist
[i
][0] == token
.EQUAL
:
851 defaults
.append(self
.com_node(nodelist
[i
+ 1]))
854 # we have already seen an argument with default, but here
856 raise SyntaxError, "non-default argument follows default argument"
861 return names
, defaults
, flags
863 def com_fpdef(self
, node
):
864 # fpdef: NAME | '(' fplist ')'
865 if node
[1][0] == token
.LPAR
:
866 return self
.com_fplist(node
[2])
869 def com_fplist(self
, node
):
870 # fplist: fpdef (',' fpdef)* [',']
872 return self
.com_fpdef(node
[1])
874 for i
in range(1, len(node
), 2):
875 list.append(self
.com_fpdef(node
[i
]))
878 def com_dotted_name(self
, node
):
879 # String together the dotted names and return the string
882 if type(n
) == type(()) and n
[0] == 1:
883 name
= name
+ n
[1] + '.'
886 def com_dotted_as_name(self
, node
):
887 assert node
[0] == symbol
.dotted_as_name
889 dot
= self
.com_dotted_name(node
[0][1:])
892 assert node
[1][1] == 'as'
893 assert node
[2][0] == token
.NAME
894 return dot
, node
[2][1]
896 def com_dotted_as_names(self
, node
):
897 assert node
[0] == symbol
.dotted_as_names
899 names
= [self
.com_dotted_as_name(node
[0])]
900 for i
in range(2, len(node
), 2):
901 names
.append(self
.com_dotted_as_name(node
[i
]))
904 def com_import_as_name(self
, node
):
905 assert node
[0] == symbol
.import_as_name
907 assert node
[0][0] == token
.NAME
909 return node
[0][1], None
910 assert node
[1][1] == 'as', node
911 assert node
[2][0] == token
.NAME
912 return node
[0][1], node
[2][1]
914 def com_import_as_names(self
, node
):
915 assert node
[0] == symbol
.import_as_names
917 names
= [self
.com_import_as_name(node
[0])]
918 for i
in range(2, len(node
), 2):
919 names
.append(self
.com_import_as_name(node
[i
]))
922 def com_bases(self
, node
):
924 for i
in range(1, len(node
), 2):
925 bases
.append(self
.com_node(node
[i
]))
928 def com_try_except_finally(self
, nodelist
):
930 # ((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite]
931 # | 'finally' ':' suite))
933 if nodelist
[3][0] == token
.NAME
:
934 # first clause is a finally clause: only try-finally
935 return TryFinally(self
.com_node(nodelist
[2]),
936 self
.com_node(nodelist
[5]),
937 lineno
=nodelist
[0][2])
939 #tryexcept: [TryNode, [except_clauses], elseNode)]
943 for i
in range(3, len(nodelist
), 3):
945 if node
[0] == symbol
.except_clause
:
946 # except_clause: 'except' [expr [(',' | 'as') expr]] */
948 expr1
= self
.com_node(node
[2])
950 expr2
= self
.com_assign(node
[4], OP_ASSIGN
)
955 clauses
.append((expr1
, expr2
, self
.com_node(nodelist
[i
+2])))
957 if node
[0] == token
.NAME
:
958 if node
[1] == 'else':
959 elseNode
= self
.com_node(nodelist
[i
+2])
960 elif node
[1] == 'finally':
961 finallyNode
= self
.com_node(nodelist
[i
+2])
962 try_except
= TryExcept(self
.com_node(nodelist
[2]), clauses
, elseNode
,
963 lineno
=nodelist
[0][2])
965 return TryFinally(try_except
, finallyNode
, lineno
=nodelist
[0][2])
969 def com_with(self
, nodelist
):
970 # with_stmt: 'with' with_item (',' with_item)* ':' suite
971 body
= self
.com_node(nodelist
[-1])
972 for i
in range(len(nodelist
) - 3, 0, -2):
973 ret
= self
.com_with_item(nodelist
[i
], body
, nodelist
[0][2])
978 def com_with_item(self
, nodelist
, body
, lineno
):
979 # with_item: test ['as' expr]
980 if len(nodelist
) == 4:
981 var
= self
.com_assign(nodelist
[3], OP_ASSIGN
)
984 expr
= self
.com_node(nodelist
[1])
985 return With(expr
, var
, body
, lineno
=lineno
)
987 def com_augassign_op(self
, node
):
988 assert node
[0] == symbol
.augassign
991 def com_augassign(self
, node
):
992 """Return node suitable for lvalue of augmented assignment
994 Names, slices, and attributes are the only allowable nodes.
996 l
= self
.com_node(node
)
997 if l
.__class
__ in (Name
, Slice
, Subscript
, Getattr
):
999 raise SyntaxError, "can't assign to %s" % l
.__class
__.__name
__
1001 def com_assign(self
, node
, assigning
):
1002 # return a node suitable for use as an "lvalue"
1003 # loop to avoid trivial recursion
1006 if t
in (symbol
.exprlist
, symbol
.testlist
, symbol
.testlist_safe
, symbol
.testlist_comp
):
1008 return self
.com_assign_tuple(node
, assigning
)
1010 elif t
in _assign_types
:
1012 raise SyntaxError, "can't assign to operator"
1014 elif t
== symbol
.power
:
1015 if node
[1][0] != symbol
.atom
:
1016 raise SyntaxError, "can't assign to operator"
1018 primary
= self
.com_node(node
[1])
1019 for i
in range(2, len(node
)-1):
1021 if ch
[0] == token
.DOUBLESTAR
:
1022 raise SyntaxError, "can't assign to operator"
1023 primary
= self
.com_apply_trailer(primary
, ch
)
1024 return self
.com_assign_trailer(primary
, node
[-1],
1027 elif t
== symbol
.atom
:
1031 if node
[0] == token
.RPAR
:
1032 raise SyntaxError, "can't assign to ()"
1033 elif t
== token
.LSQB
:
1035 if node
[0] == token
.RSQB
:
1036 raise SyntaxError, "can't assign to []"
1037 return self
.com_assign_list(node
, assigning
)
1038 elif t
== token
.NAME
:
1039 return self
.com_assign_name(node
[1], assigning
)
1041 raise SyntaxError, "can't assign to literal"
1043 raise SyntaxError, "bad assignment (%s)" % t
1045 def com_assign_tuple(self
, node
, assigning
):
1047 for i
in range(1, len(node
), 2):
1048 assigns
.append(self
.com_assign(node
[i
], assigning
))
1049 return AssTuple(assigns
, lineno
=extractLineNo(node
))
1051 def com_assign_list(self
, node
, assigning
):
1053 for i
in range(1, len(node
), 2):
1054 if i
+ 1 < len(node
):
1055 if node
[i
+ 1][0] == symbol
.list_for
:
1056 raise SyntaxError, "can't assign to list comprehension"
1057 assert node
[i
+ 1][0] == token
.COMMA
, node
[i
+ 1]
1058 assigns
.append(self
.com_assign(node
[i
], assigning
))
1059 return AssList(assigns
, lineno
=extractLineNo(node
))
1061 def com_assign_name(self
, node
, assigning
):
1062 return AssName(node
[1], assigning
, lineno
=node
[2])
1064 def com_assign_trailer(self
, primary
, node
, assigning
):
1067 return self
.com_assign_attr(primary
, node
[2], assigning
)
1069 return self
.com_subscriptlist(primary
, node
[2], assigning
)
1071 raise SyntaxError, "can't assign to function call"
1072 raise SyntaxError, "unknown trailer type: %s" % t
1074 def com_assign_attr(self
, primary
, node
, assigning
):
1075 return AssAttr(primary
, node
[1], assigning
, lineno
=node
[-1])
1077 def com_binary(self
, constructor
, nodelist
):
1078 "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
1082 return self
.lookup_node(n
)(n
[1:])
1084 for i
in range(0, l
, 2):
1086 items
.append(self
.lookup_node(n
)(n
[1:]))
1087 return constructor(items
, lineno
=extractLineNo(nodelist
))
1089 def com_stmt(self
, node
):
1090 result
= self
.lookup_node(node
)(node
[1:])
1091 assert result
is not None
1092 if isinstance(result
, Stmt
):
1094 return Stmt([result
])
1096 def com_append_stmt(self
, stmts
, node
):
1097 result
= self
.lookup_node(node
)(node
[1:])
1098 assert result
is not None
1099 if isinstance(result
, Stmt
):
1100 stmts
.extend(result
.nodes
)
1102 stmts
.append(result
)
1104 def com_list_constructor(self
, nodelist
):
1105 # listmaker: test ( list_for | (',' test)* [','] )
1107 for i
in range(1, len(nodelist
)):
1108 if nodelist
[i
][0] == symbol
.list_for
:
1109 assert len(nodelist
[i
:]) == 1
1110 return self
.com_list_comprehension(values
[0],
1112 elif nodelist
[i
][0] == token
.COMMA
:
1114 values
.append(self
.com_node(nodelist
[i
]))
1115 return List(values
, lineno
=values
[0].lineno
)
1117 def com_list_comprehension(self
, expr
, node
):
1118 return self
.com_comprehension(expr
, None, node
, 'list')
1120 def com_comprehension(self
, expr1
, expr2
, node
, type):
1121 # list_iter: list_for | list_if
1122 # list_for: 'for' exprlist 'in' testlist [list_iter]
1123 # list_if: 'if' test [list_iter]
1125 # XXX should raise SyntaxError for assignment
1126 # XXX(avassalotti) Set and dict comprehensions should have generator
1127 # semantics. In other words, they shouldn't leak
1128 # variables outside of the comprehension's scope.
1135 assignNode
= self
.com_assign(node
[2], OP_ASSIGN
)
1136 compNode
= self
.com_node(node
[4])
1137 newfor
= ListCompFor(assignNode
, compNode
, [])
1138 newfor
.lineno
= node
[1][2]
1142 elif type == 'list':
1143 node
= self
.com_list_iter(node
[5])
1145 node
= self
.com_comp_iter(node
[5])
1147 test
= self
.com_node(node
[2])
1148 newif
= ListCompIf(test
, lineno
=node
[1][2])
1149 newfor
.ifs
.append(newif
)
1152 elif type == 'list':
1153 node
= self
.com_list_iter(node
[3])
1155 node
= self
.com_comp_iter(node
[3])
1157 raise SyntaxError, \
1158 ("unexpected comprehension element: %s %d"
1161 return ListComp(expr1
, fors
, lineno
=lineno
)
1163 return SetComp(expr1
, fors
, lineno
=lineno
)
1164 elif type == 'dict':
1165 return DictComp(expr1
, expr2
, fors
, lineno
=lineno
)
1167 raise ValueError("unexpected comprehension type: " + repr(type))
1169 def com_list_iter(self
, node
):
1170 assert node
[0] == symbol
.list_iter
1173 def com_comp_iter(self
, node
):
1174 assert node
[0] == symbol
.comp_iter
1177 def com_generator_expression(self
, expr
, node
):
1178 # comp_iter: comp_for | comp_if
1179 # comp_for: 'for' exprlist 'in' test [comp_iter]
1180 # comp_if: 'if' test [comp_iter]
1187 assignNode
= self
.com_assign(node
[2], OP_ASSIGN
)
1188 genNode
= self
.com_node(node
[4])
1189 newfor
= GenExprFor(assignNode
, genNode
, [],
1192 if (len(node
)) == 5:
1195 node
= self
.com_comp_iter(node
[5])
1197 test
= self
.com_node(node
[2])
1198 newif
= GenExprIf(test
, lineno
=node
[1][2])
1199 newfor
.ifs
.append(newif
)
1203 node
= self
.com_comp_iter(node
[3])
1205 raise SyntaxError, \
1206 ("unexpected generator expression element: %s %d"
1208 fors
[0].is_outmost
= True
1209 return GenExpr(GenExprInner(expr
, fors
), lineno
=lineno
)
1211 def com_dictorsetmaker(self
, nodelist
):
1212 # dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) |
1213 # (test (comp_for | (',' test)* [','])) )
1214 assert nodelist
[0] == symbol
.dictorsetmaker
1215 nodelist
= nodelist
[1:]
1216 if len(nodelist
) == 1 or nodelist
[1][0] == token
.COMMA
:
1219 for i
in range(0, len(nodelist
), 2):
1220 items
.append(self
.com_node(nodelist
[i
]))
1221 return Set(items
, lineno
=items
[0].lineno
)
1222 elif nodelist
[1][0] == symbol
.comp_for
:
1224 expr
= self
.com_node(nodelist
[0])
1225 return self
.com_comprehension(expr
, None, nodelist
[1], 'set')
1226 elif len(nodelist
) > 3 and nodelist
[3][0] == symbol
.comp_for
:
1227 # dict comprehension
1228 assert nodelist
[1][0] == token
.COLON
1229 key
= self
.com_node(nodelist
[0])
1230 value
= self
.com_node(nodelist
[2])
1231 return self
.com_comprehension(key
, value
, nodelist
[3], 'dict')
1235 for i
in range(0, len(nodelist
), 4):
1236 items
.append((self
.com_node(nodelist
[i
]),
1237 self
.com_node(nodelist
[i
+2])))
1238 return Dict(items
, lineno
=items
[0][0].lineno
)
1240 def com_apply_trailer(self
, primaryNode
, nodelist
):
1243 return self
.com_call_function(primaryNode
, nodelist
[2])
1245 return self
.com_select_member(primaryNode
, nodelist
[2])
1247 return self
.com_subscriptlist(primaryNode
, nodelist
[2], OP_APPLY
)
1249 raise SyntaxError, 'unknown node type: %s' % t
1251 def com_select_member(self
, primaryNode
, nodelist
):
1252 if nodelist
[0] != token
.NAME
:
1253 raise SyntaxError, "member must be a name"
1254 return Getattr(primaryNode
, nodelist
[1], lineno
=nodelist
[2])
1256 def com_call_function(self
, primaryNode
, nodelist
):
1257 if nodelist
[0] == token
.RPAR
:
1258 return CallFunc(primaryNode
, [], lineno
=extractLineNo(nodelist
))
1261 star_node
= dstar_node
= None
1262 len_nodelist
= len(nodelist
)
1264 while i
< len_nodelist
:
1267 if node
[0]==token
.STAR
:
1268 if star_node
is not None:
1269 raise SyntaxError, 'already have the varargs indentifier'
1270 star_node
= self
.com_node(nodelist
[i
+1])
1273 elif node
[0]==token
.DOUBLESTAR
:
1274 if dstar_node
is not None:
1275 raise SyntaxError, 'already have the kwargs indentifier'
1276 dstar_node
= self
.com_node(nodelist
[i
+1])
1280 # positional or named parameters
1281 kw
, result
= self
.com_argument(node
, kw
, star_node
)
1283 if len_nodelist
!= 2 and isinstance(result
, GenExpr
) \
1284 and len(node
) == 3 and node
[2][0] == symbol
.comp_for
:
1285 # allow f(x for x in y), but reject f(x for x in y, 1)
1286 # should use f((x for x in y), 1) instead of f(x for x in y, 1)
1287 raise SyntaxError, 'generator expression needs parenthesis'
1292 return CallFunc(primaryNode
, args
, star_node
, dstar_node
,
1293 lineno
=extractLineNo(nodelist
))
1295 def com_argument(self
, nodelist
, kw
, star_node
):
1296 if len(nodelist
) == 3 and nodelist
[2][0] == symbol
.comp_for
:
1297 test
= self
.com_node(nodelist
[1])
1298 return 0, self
.com_generator_expression(test
, nodelist
[2])
1299 if len(nodelist
) == 2:
1301 raise SyntaxError, "non-keyword arg after keyword arg"
1303 raise SyntaxError, "only named arguments may follow *expression"
1304 return 0, self
.com_node(nodelist
[1])
1305 result
= self
.com_node(nodelist
[3])
1307 while len(n
) == 2 and n
[0] != token
.NAME
:
1309 if n
[0] != token
.NAME
:
1310 raise SyntaxError, "keyword can't be an expression (%s)"%n
[0]
1311 node
= Keyword(n
[1], result
, lineno
=n
[2])
1314 def com_subscriptlist(self
, primary
, nodelist
, assigning
):
1315 # slicing: simple_slicing | extended_slicing
1316 # simple_slicing: primary "[" short_slice "]"
1317 # extended_slicing: primary "[" slice_list "]"
1318 # slice_list: slice_item ("," slice_item)* [","]
1320 # backwards compat slice for '[i:j]'
1321 if len(nodelist
) == 2:
1323 if (sub
[1][0] == token
.COLON
or \
1324 (len(sub
) > 2 and sub
[2][0] == token
.COLON
)) and \
1325 sub
[-1][0] != symbol
.sliceop
:
1326 return self
.com_slice(primary
, sub
, assigning
)
1329 for i
in range(1, len(nodelist
), 2):
1330 subscripts
.append(self
.com_subscript(nodelist
[i
]))
1331 return Subscript(primary
, assigning
, subscripts
,
1332 lineno
=extractLineNo(nodelist
))
1334 def com_subscript(self
, node
):
1335 # slice_item: expression | proper_slice | ellipsis
1338 if t
== token
.DOT
and node
[2][0] == token
.DOT
:
1340 if t
== token
.COLON
or len(node
) > 2:
1341 return self
.com_sliceobj(node
)
1342 return self
.com_node(ch
)
1344 def com_sliceobj(self
, node
):
1345 # proper_slice: short_slice | long_slice
1346 # short_slice: [lower_bound] ":" [upper_bound]
1347 # long_slice: short_slice ":" [stride]
1348 # lower_bound: expression
1349 # upper_bound: expression
1350 # stride: expression
1352 # Note: a stride may be further slicing...
1356 if node
[1][0] == token
.COLON
:
1357 items
.append(Const(None))
1360 items
.append(self
.com_node(node
[1]))
1364 if i
< len(node
) and node
[i
][0] == symbol
.test
:
1365 items
.append(self
.com_node(node
[i
]))
1368 items
.append(Const(None))
1370 # a short_slice has been built. look for long_slice now by looking
1372 for j
in range(i
, len(node
)):
1375 items
.append(Const(None))
1377 items
.append(self
.com_node(ch
[2]))
1378 return Sliceobj(items
, lineno
=extractLineNo(node
))
1380 def com_slice(self
, primary
, node
, assigning
):
1381 # short_slice: [lower_bound] ":" [upper_bound]
1382 lower
= upper
= None
1384 if node
[1][0] == token
.COLON
:
1385 upper
= self
.com_node(node
[2])
1387 lower
= self
.com_node(node
[1])
1388 elif len(node
) == 4:
1389 lower
= self
.com_node(node
[1])
1390 upper
= self
.com_node(node
[3])
1391 return Slice(primary
, assigning
, lower
, upper
,
1392 lineno
=extractLineNo(node
))
1394 def get_docstring(self
, node
, n
=None):
1398 if n
== symbol
.suite
:
1400 return self
.get_docstring(node
[0])
1402 if sub
[0] == symbol
.stmt
:
1403 return self
.get_docstring(sub
)
1405 if n
== symbol
.file_input
:
1407 if sub
[0] == symbol
.stmt
:
1408 return self
.get_docstring(sub
)
1410 if n
== symbol
.atom
:
1411 if node
[0][0] == token
.STRING
:
1417 if n
== symbol
.stmt
or n
== symbol
.simple_stmt \
1418 or n
== symbol
.small_stmt
:
1419 return self
.get_docstring(node
[0])
1420 if n
in _doc_nodes
and len(node
) == 1:
1421 return self
.get_docstring(node
[0])
1428 symbol
.testlist_safe
,
1444 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
1445 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
1448 token
.GREATER
: '>',
1449 token
.EQEQUAL
: '==',
1451 token
.LESSEQUAL
: '<=',
1452 token
.GREATEREQUAL
: '>=',
1453 token
.NOTEQUAL
: '!=',
1456 _legal_node_types
= [
1463 symbol
.compound_stmt
,
1469 symbol
.continue_stmt
,
1483 symbol
.testlist_safe
,
1500 if hasattr(symbol
, 'yield_stmt'):
1501 _legal_node_types
.append(symbol
.yield_stmt
)
1502 if hasattr(symbol
, 'yield_expr'):
1503 _legal_node_types
.append(symbol
.yield_expr
)
1521 for k
, v
in symbol
.sym_name
.items():
1523 for k
, v
in token
.tok_name
.items():
1526 def debug_tree(tree
):
1529 if isinstance(elt
, int):
1530 l
.append(_names
.get(elt
, elt
))
1531 elif isinstance(elt
, str):
1534 l
.append(debug_tree(elt
))