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_gexp(self
, nodelist
):
585 if len(nodelist
) == 2 and nodelist
[1][0] == symbol
.gen_for
:
586 test
= self
.com_node(nodelist
[0])
587 return self
.com_generator_expression(test
, nodelist
[1])
588 return self
.testlist(nodelist
)
590 def test(self
, nodelist
):
591 # or_test ['if' or_test 'else' test] | lambdef
592 if len(nodelist
) == 1 and nodelist
[0][0] == symbol
.lambdef
:
593 return self
.lambdef(nodelist
[0])
594 then
= self
.com_node(nodelist
[0])
595 if len(nodelist
) > 1:
596 assert len(nodelist
) == 5
597 assert nodelist
[1][1] == 'if'
598 assert nodelist
[3][1] == 'else'
599 test
= self
.com_node(nodelist
[2])
600 else_
= self
.com_node(nodelist
[4])
601 return IfExp(test
, then
, else_
, lineno
=nodelist
[1][2])
604 def or_test(self
, nodelist
):
605 # and_test ('or' and_test)* | lambdef
606 if len(nodelist
) == 1 and nodelist
[0][0] == symbol
.lambdef
:
607 return self
.lambdef(nodelist
[0])
608 return self
.com_binary(Or
, nodelist
)
611 def and_test(self
, nodelist
):
612 # not_test ('and' not_test)*
613 return self
.com_binary(And
, nodelist
)
615 def not_test(self
, nodelist
):
616 # 'not' not_test | comparison
617 result
= self
.com_node(nodelist
[-1])
618 if len(nodelist
) == 2:
619 return Not(result
, lineno
=nodelist
[0][2])
622 def comparison(self
, nodelist
):
623 # comparison: expr (comp_op expr)*
624 node
= self
.com_node(nodelist
[0])
625 if len(nodelist
) == 1:
629 for i
in range(2, len(nodelist
), 2):
632 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
633 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
635 if n
[0] == token
.NAME
:
643 type = _cmp_types
[n
[0]]
646 results
.append((type, self
.com_node(nodelist
[i
])))
648 # we need a special "compare" node so that we can distinguish
649 # 3 < x < 5 from (3 < x) < 5
650 # the two have very different semantics and results (note that the
651 # latter form is always true)
653 return Compare(node
, results
, lineno
=lineno
)
655 def expr(self
, nodelist
):
656 # xor_expr ('|' xor_expr)*
657 return self
.com_binary(Bitor
, nodelist
)
659 def xor_expr(self
, nodelist
):
660 # xor_expr ('^' xor_expr)*
661 return self
.com_binary(Bitxor
, nodelist
)
663 def and_expr(self
, nodelist
):
664 # xor_expr ('&' xor_expr)*
665 return self
.com_binary(Bitand
, nodelist
)
667 def shift_expr(self
, nodelist
):
668 # shift_expr ('<<'|'>>' shift_expr)*
669 node
= self
.com_node(nodelist
[0])
670 for i
in range(2, len(nodelist
), 2):
671 right
= self
.com_node(nodelist
[i
])
672 if nodelist
[i
-1][0] == token
.LEFTSHIFT
:
673 node
= LeftShift([node
, right
], lineno
=nodelist
[1][2])
674 elif nodelist
[i
-1][0] == token
.RIGHTSHIFT
:
675 node
= RightShift([node
, right
], lineno
=nodelist
[1][2])
677 raise ValueError, "unexpected token: %s" % nodelist
[i
-1][0]
680 def arith_expr(self
, nodelist
):
681 node
= self
.com_node(nodelist
[0])
682 for i
in range(2, len(nodelist
), 2):
683 right
= self
.com_node(nodelist
[i
])
684 if nodelist
[i
-1][0] == token
.PLUS
:
685 node
= Add([node
, right
], lineno
=nodelist
[1][2])
686 elif nodelist
[i
-1][0] == token
.MINUS
:
687 node
= Sub([node
, right
], lineno
=nodelist
[1][2])
689 raise ValueError, "unexpected token: %s" % nodelist
[i
-1][0]
692 def term(self
, nodelist
):
693 node
= self
.com_node(nodelist
[0])
694 for i
in range(2, len(nodelist
), 2):
695 right
= self
.com_node(nodelist
[i
])
698 node
= Mul([node
, right
])
699 elif t
== token
.SLASH
:
700 node
= Div([node
, right
])
701 elif t
== token
.PERCENT
:
702 node
= Mod([node
, right
])
703 elif t
== token
.DOUBLESLASH
:
704 node
= FloorDiv([node
, right
])
706 raise ValueError, "unexpected token: %s" % t
707 node
.lineno
= nodelist
[1][2]
710 def factor(self
, nodelist
):
713 node
= self
.lookup_node(nodelist
[-1])(nodelist
[-1][1:])
714 # need to handle (unary op)constant here...
716 return UnaryAdd(node
, lineno
=elt
[2])
717 elif t
== token
.MINUS
:
718 return UnarySub(node
, lineno
=elt
[2])
719 elif t
== token
.TILDE
:
720 node
= Invert(node
, lineno
=elt
[2])
723 def power(self
, nodelist
):
724 # power: atom trailer* ('**' factor)*
725 node
= self
.com_node(nodelist
[0])
726 for i
in range(1, len(nodelist
)):
728 if elt
[0] == token
.DOUBLESTAR
:
729 return Power([node
, self
.com_node(nodelist
[i
+1])],
732 node
= self
.com_apply_trailer(node
, elt
)
736 def atom(self
, nodelist
):
737 return self
._atom
_dispatch
[nodelist
[0][0]](nodelist
)
739 def atom_lpar(self
, nodelist
):
740 if nodelist
[1][0] == token
.RPAR
:
741 return Tuple((), lineno
=nodelist
[0][2])
742 return self
.com_node(nodelist
[1])
744 def atom_lsqb(self
, nodelist
):
745 if nodelist
[1][0] == token
.RSQB
:
746 return List((), lineno
=nodelist
[0][2])
747 return self
.com_list_constructor(nodelist
[1])
749 def atom_lbrace(self
, nodelist
):
750 if nodelist
[1][0] == token
.RBRACE
:
751 return Dict((), lineno
=nodelist
[0][2])
752 return self
.com_dictmaker(nodelist
[1])
754 def atom_backquote(self
, nodelist
):
755 return Backquote(self
.com_node(nodelist
[1]))
757 def atom_number(self
, nodelist
):
758 ### need to verify this matches compile.c
759 k
= eval(nodelist
[0][1])
760 return Const(k
, lineno
=nodelist
[0][2])
762 def decode_literal(self
, lit
):
764 # this is particularly fragile & a bit of a
765 # hack... changes in compile.c:parsestr and
766 # tokenizer.c must be reflected here.
767 if self
.encoding
not in ['utf-8', 'iso-8859-1']:
768 lit
= unicode(lit
, 'utf-8').encode(self
.encoding
)
769 return eval("# coding: %s\n%s" % (self
.encoding
, lit
))
773 def atom_string(self
, nodelist
):
775 for node
in nodelist
:
776 k
+= self
.decode_literal(node
[1])
777 return Const(k
, lineno
=nodelist
[0][2])
779 def atom_name(self
, nodelist
):
780 return Name(nodelist
[0][1], lineno
=nodelist
[0][2])
782 # --------------------------------------------------------------
784 # INTERNAL PARSING UTILITIES
787 # The use of com_node() introduces a lot of extra stack frames,
788 # enough to cause a stack overflow compiling test.test_parser with
789 # the standard interpreter recursionlimit. The com_node() is a
790 # convenience function that hides the dispatch details, but comes
791 # at a very high cost. It is more efficient to dispatch directly
792 # in the callers. In these cases, use lookup_node() and call the
793 # dispatched node directly.
795 def lookup_node(self
, node
):
796 return self
._dispatch
[node
[0]]
798 def com_node(self
, node
):
799 # Note: compile.c has handling in com_node for del_stmt, pass_stmt,
800 # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
802 # We'll just dispatch them.
803 return self
._dispatch
[node
[0]](node
[1:])
805 def com_NEWLINE(self
, *args
):
806 # A ';' at the end of a line can make a NEWLINE token appear
807 # here, Render it harmless. (genc discards ('discard',
808 # ('const', xxxx)) Nodes)
809 return Discard(Const(None))
811 def com_arglist(self
, nodelist
):
813 # (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME)
814 # | fpdef ['=' test] (',' fpdef ['=' test])* [',']
815 # fpdef: NAME | '(' fplist ')'
816 # fplist: fpdef (',' fpdef)* [',']
822 while i
< len(nodelist
):
824 if node
[0] == token
.STAR
or node
[0] == token
.DOUBLESTAR
:
825 if node
[0] == token
.STAR
:
827 if node
[0] == token
.NAME
:
828 names
.append(node
[1])
829 flags
= flags | CO_VARARGS
832 if i
< len(nodelist
):
833 # should be DOUBLESTAR
835 if t
== token
.DOUBLESTAR
:
838 raise ValueError, "unexpected token: %s" % t
839 names
.append(node
[1])
840 flags
= flags | CO_VARKEYWORDS
844 # fpdef: NAME | '(' fplist ')'
845 names
.append(self
.com_fpdef(node
))
848 if i
< len(nodelist
) and nodelist
[i
][0] == token
.EQUAL
:
849 defaults
.append(self
.com_node(nodelist
[i
+ 1]))
852 # we have already seen an argument with default, but here
854 raise SyntaxError, "non-default argument follows default argument"
859 return names
, defaults
, flags
861 def com_fpdef(self
, node
):
862 # fpdef: NAME | '(' fplist ')'
863 if node
[1][0] == token
.LPAR
:
864 return self
.com_fplist(node
[2])
867 def com_fplist(self
, node
):
868 # fplist: fpdef (',' fpdef)* [',']
870 return self
.com_fpdef(node
[1])
872 for i
in range(1, len(node
), 2):
873 list.append(self
.com_fpdef(node
[i
]))
876 def com_dotted_name(self
, node
):
877 # String together the dotted names and return the string
880 if type(n
) == type(()) and n
[0] == 1:
881 name
= name
+ n
[1] + '.'
884 def com_dotted_as_name(self
, node
):
885 assert node
[0] == symbol
.dotted_as_name
887 dot
= self
.com_dotted_name(node
[0][1:])
890 assert node
[1][1] == 'as'
891 assert node
[2][0] == token
.NAME
892 return dot
, node
[2][1]
894 def com_dotted_as_names(self
, node
):
895 assert node
[0] == symbol
.dotted_as_names
897 names
= [self
.com_dotted_as_name(node
[0])]
898 for i
in range(2, len(node
), 2):
899 names
.append(self
.com_dotted_as_name(node
[i
]))
902 def com_import_as_name(self
, node
):
903 assert node
[0] == symbol
.import_as_name
905 assert node
[0][0] == token
.NAME
907 return node
[0][1], None
908 assert node
[1][1] == 'as', node
909 assert node
[2][0] == token
.NAME
910 return node
[0][1], node
[2][1]
912 def com_import_as_names(self
, node
):
913 assert node
[0] == symbol
.import_as_names
915 names
= [self
.com_import_as_name(node
[0])]
916 for i
in range(2, len(node
), 2):
917 names
.append(self
.com_import_as_name(node
[i
]))
920 def com_bases(self
, node
):
922 for i
in range(1, len(node
), 2):
923 bases
.append(self
.com_node(node
[i
]))
926 def com_try_except_finally(self
, nodelist
):
928 # ((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite]
929 # | 'finally' ':' suite))
931 if nodelist
[3][0] == token
.NAME
:
932 # first clause is a finally clause: only try-finally
933 return TryFinally(self
.com_node(nodelist
[2]),
934 self
.com_node(nodelist
[5]),
935 lineno
=nodelist
[0][2])
937 #tryexcept: [TryNode, [except_clauses], elseNode)]
941 for i
in range(3, len(nodelist
), 3):
943 if node
[0] == symbol
.except_clause
:
944 # except_clause: 'except' [expr [(',' | 'as') expr]] */
946 expr1
= self
.com_node(node
[2])
948 expr2
= self
.com_assign(node
[4], OP_ASSIGN
)
953 clauses
.append((expr1
, expr2
, self
.com_node(nodelist
[i
+2])))
955 if node
[0] == token
.NAME
:
956 if node
[1] == 'else':
957 elseNode
= self
.com_node(nodelist
[i
+2])
958 elif node
[1] == 'finally':
959 finallyNode
= self
.com_node(nodelist
[i
+2])
960 try_except
= TryExcept(self
.com_node(nodelist
[2]), clauses
, elseNode
,
961 lineno
=nodelist
[0][2])
963 return TryFinally(try_except
, finallyNode
, lineno
=nodelist
[0][2])
967 def com_with(self
, nodelist
):
968 # with_stmt: 'with' with_item (',' with_item)* ':' suite
969 body
= self
.com_node(nodelist
[-1])
970 for i
in range(len(nodelist
) - 3, 0, -2):
971 ret
= self
.com_with_item(nodelist
[i
], body
, nodelist
[0][2])
976 def com_with_item(self
, nodelist
, body
, lineno
):
977 # with_item: test ['as' expr]
978 if len(nodelist
) == 4:
979 var
= self
.com_assign(nodelist
[3], OP_ASSIGN
)
982 expr
= self
.com_node(nodelist
[1])
983 return With(expr
, var
, body
, lineno
=lineno
)
985 def com_augassign_op(self
, node
):
986 assert node
[0] == symbol
.augassign
989 def com_augassign(self
, node
):
990 """Return node suitable for lvalue of augmented assignment
992 Names, slices, and attributes are the only allowable nodes.
994 l
= self
.com_node(node
)
995 if l
.__class
__ in (Name
, Slice
, Subscript
, Getattr
):
997 raise SyntaxError, "can't assign to %s" % l
.__class
__.__name
__
999 def com_assign(self
, node
, assigning
):
1000 # return a node suitable for use as an "lvalue"
1001 # loop to avoid trivial recursion
1004 if t
in (symbol
.exprlist
, symbol
.testlist
, symbol
.testlist_safe
, symbol
.testlist_gexp
):
1006 return self
.com_assign_tuple(node
, assigning
)
1008 elif t
in _assign_types
:
1010 raise SyntaxError, "can't assign to operator"
1012 elif t
== symbol
.power
:
1013 if node
[1][0] != symbol
.atom
:
1014 raise SyntaxError, "can't assign to operator"
1016 primary
= self
.com_node(node
[1])
1017 for i
in range(2, len(node
)-1):
1019 if ch
[0] == token
.DOUBLESTAR
:
1020 raise SyntaxError, "can't assign to operator"
1021 primary
= self
.com_apply_trailer(primary
, ch
)
1022 return self
.com_assign_trailer(primary
, node
[-1],
1025 elif t
== symbol
.atom
:
1029 if node
[0] == token
.RPAR
:
1030 raise SyntaxError, "can't assign to ()"
1031 elif t
== token
.LSQB
:
1033 if node
[0] == token
.RSQB
:
1034 raise SyntaxError, "can't assign to []"
1035 return self
.com_assign_list(node
, assigning
)
1036 elif t
== token
.NAME
:
1037 return self
.com_assign_name(node
[1], assigning
)
1039 raise SyntaxError, "can't assign to literal"
1041 raise SyntaxError, "bad assignment (%s)" % t
1043 def com_assign_tuple(self
, node
, assigning
):
1045 for i
in range(1, len(node
), 2):
1046 assigns
.append(self
.com_assign(node
[i
], assigning
))
1047 return AssTuple(assigns
, lineno
=extractLineNo(node
))
1049 def com_assign_list(self
, node
, assigning
):
1051 for i
in range(1, len(node
), 2):
1052 if i
+ 1 < len(node
):
1053 if node
[i
+ 1][0] == symbol
.list_for
:
1054 raise SyntaxError, "can't assign to list comprehension"
1055 assert node
[i
+ 1][0] == token
.COMMA
, node
[i
+ 1]
1056 assigns
.append(self
.com_assign(node
[i
], assigning
))
1057 return AssList(assigns
, lineno
=extractLineNo(node
))
1059 def com_assign_name(self
, node
, assigning
):
1060 return AssName(node
[1], assigning
, lineno
=node
[2])
1062 def com_assign_trailer(self
, primary
, node
, assigning
):
1065 return self
.com_assign_attr(primary
, node
[2], assigning
)
1067 return self
.com_subscriptlist(primary
, node
[2], assigning
)
1069 raise SyntaxError, "can't assign to function call"
1070 raise SyntaxError, "unknown trailer type: %s" % t
1072 def com_assign_attr(self
, primary
, node
, assigning
):
1073 return AssAttr(primary
, node
[1], assigning
, lineno
=node
[-1])
1075 def com_binary(self
, constructor
, nodelist
):
1076 "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
1080 return self
.lookup_node(n
)(n
[1:])
1082 for i
in range(0, l
, 2):
1084 items
.append(self
.lookup_node(n
)(n
[1:]))
1085 return constructor(items
, lineno
=extractLineNo(nodelist
))
1087 def com_stmt(self
, node
):
1088 result
= self
.lookup_node(node
)(node
[1:])
1089 assert result
is not None
1090 if isinstance(result
, Stmt
):
1092 return Stmt([result
])
1094 def com_append_stmt(self
, stmts
, node
):
1095 result
= self
.lookup_node(node
)(node
[1:])
1096 assert result
is not None
1097 if isinstance(result
, Stmt
):
1098 stmts
.extend(result
.nodes
)
1100 stmts
.append(result
)
1102 if hasattr(symbol
, 'list_for'):
1103 def com_list_constructor(self
, nodelist
):
1104 # listmaker: test ( list_for | (',' test)* [','] )
1106 for i
in range(1, len(nodelist
)):
1107 if nodelist
[i
][0] == symbol
.list_for
:
1108 assert len(nodelist
[i
:]) == 1
1109 return self
.com_list_comprehension(values
[0],
1111 elif nodelist
[i
][0] == token
.COMMA
:
1113 values
.append(self
.com_node(nodelist
[i
]))
1114 return List(values
, lineno
=values
[0].lineno
)
1116 def com_list_comprehension(self
, expr
, node
):
1117 # list_iter: list_for | list_if
1118 # list_for: 'for' exprlist 'in' testlist [list_iter]
1119 # list_if: 'if' test [list_iter]
1121 # XXX should raise SyntaxError for assignment
1128 assignNode
= self
.com_assign(node
[2], OP_ASSIGN
)
1129 listNode
= self
.com_node(node
[4])
1130 newfor
= ListCompFor(assignNode
, listNode
, [])
1131 newfor
.lineno
= node
[1][2]
1136 node
= self
.com_list_iter(node
[5])
1138 test
= self
.com_node(node
[2])
1139 newif
= ListCompIf(test
, lineno
=node
[1][2])
1140 newfor
.ifs
.append(newif
)
1144 node
= self
.com_list_iter(node
[3])
1146 raise SyntaxError, \
1147 ("unexpected list comprehension element: %s %d"
1149 return ListComp(expr
, fors
, lineno
=lineno
)
1151 def com_list_iter(self
, node
):
1152 assert node
[0] == symbol
.list_iter
1155 def com_list_constructor(self
, nodelist
):
1157 for i
in range(1, len(nodelist
), 2):
1158 values
.append(self
.com_node(nodelist
[i
]))
1159 return List(values
, lineno
=values
[0].lineno
)
1161 if hasattr(symbol
, 'gen_for'):
1162 def com_generator_expression(self
, expr
, node
):
1163 # gen_iter: gen_for | gen_if
1164 # gen_for: 'for' exprlist 'in' test [gen_iter]
1165 # gen_if: 'if' test [gen_iter]
1172 assignNode
= self
.com_assign(node
[2], OP_ASSIGN
)
1173 genNode
= self
.com_node(node
[4])
1174 newfor
= GenExprFor(assignNode
, genNode
, [],
1177 if (len(node
)) == 5:
1180 node
= self
.com_gen_iter(node
[5])
1182 test
= self
.com_node(node
[2])
1183 newif
= GenExprIf(test
, lineno
=node
[1][2])
1184 newfor
.ifs
.append(newif
)
1188 node
= self
.com_gen_iter(node
[3])
1190 raise SyntaxError, \
1191 ("unexpected generator expression element: %s %d"
1193 fors
[0].is_outmost
= True
1194 return GenExpr(GenExprInner(expr
, fors
), lineno
=lineno
)
1196 def com_gen_iter(self
, node
):
1197 assert node
[0] == symbol
.gen_iter
1200 def com_dictmaker(self
, nodelist
):
1201 # dictmaker: test ':' test (',' test ':' value)* [',']
1203 for i
in range(1, len(nodelist
), 4):
1204 items
.append((self
.com_node(nodelist
[i
]),
1205 self
.com_node(nodelist
[i
+2])))
1206 return Dict(items
, lineno
=items
[0][0].lineno
)
1208 def com_apply_trailer(self
, primaryNode
, nodelist
):
1211 return self
.com_call_function(primaryNode
, nodelist
[2])
1213 return self
.com_select_member(primaryNode
, nodelist
[2])
1215 return self
.com_subscriptlist(primaryNode
, nodelist
[2], OP_APPLY
)
1217 raise SyntaxError, 'unknown node type: %s' % t
1219 def com_select_member(self
, primaryNode
, nodelist
):
1220 if nodelist
[0] != token
.NAME
:
1221 raise SyntaxError, "member must be a name"
1222 return Getattr(primaryNode
, nodelist
[1], lineno
=nodelist
[2])
1224 def com_call_function(self
, primaryNode
, nodelist
):
1225 if nodelist
[0] == token
.RPAR
:
1226 return CallFunc(primaryNode
, [], lineno
=extractLineNo(nodelist
))
1229 star_node
= dstar_node
= None
1230 len_nodelist
= len(nodelist
)
1232 while i
< len_nodelist
:
1235 if node
[0]==token
.STAR
:
1236 if star_node
is not None:
1237 raise SyntaxError, 'already have the varargs indentifier'
1238 star_node
= self
.com_node(nodelist
[i
+1])
1241 elif node
[0]==token
.DOUBLESTAR
:
1242 if dstar_node
is not None:
1243 raise SyntaxError, 'already have the kwargs indentifier'
1244 dstar_node
= self
.com_node(nodelist
[i
+1])
1248 # positional or named parameters
1249 kw
, result
= self
.com_argument(node
, kw
, star_node
)
1251 if len_nodelist
!= 2 and isinstance(result
, GenExpr
) \
1252 and len(node
) == 3 and node
[2][0] == symbol
.gen_for
:
1253 # allow f(x for x in y), but reject f(x for x in y, 1)
1254 # should use f((x for x in y), 1) instead of f(x for x in y, 1)
1255 raise SyntaxError, 'generator expression needs parenthesis'
1260 return CallFunc(primaryNode
, args
, star_node
, dstar_node
,
1261 lineno
=extractLineNo(nodelist
))
1263 def com_argument(self
, nodelist
, kw
, star_node
):
1264 if len(nodelist
) == 3 and nodelist
[2][0] == symbol
.gen_for
:
1265 test
= self
.com_node(nodelist
[1])
1266 return 0, self
.com_generator_expression(test
, nodelist
[2])
1267 if len(nodelist
) == 2:
1269 raise SyntaxError, "non-keyword arg after keyword arg"
1271 raise SyntaxError, "only named arguments may follow *expression"
1272 return 0, self
.com_node(nodelist
[1])
1273 result
= self
.com_node(nodelist
[3])
1275 while len(n
) == 2 and n
[0] != token
.NAME
:
1277 if n
[0] != token
.NAME
:
1278 raise SyntaxError, "keyword can't be an expression (%s)"%n
[0]
1279 node
= Keyword(n
[1], result
, lineno
=n
[2])
1282 def com_subscriptlist(self
, primary
, nodelist
, assigning
):
1283 # slicing: simple_slicing | extended_slicing
1284 # simple_slicing: primary "[" short_slice "]"
1285 # extended_slicing: primary "[" slice_list "]"
1286 # slice_list: slice_item ("," slice_item)* [","]
1288 # backwards compat slice for '[i:j]'
1289 if len(nodelist
) == 2:
1291 if (sub
[1][0] == token
.COLON
or \
1292 (len(sub
) > 2 and sub
[2][0] == token
.COLON
)) and \
1293 sub
[-1][0] != symbol
.sliceop
:
1294 return self
.com_slice(primary
, sub
, assigning
)
1297 for i
in range(1, len(nodelist
), 2):
1298 subscripts
.append(self
.com_subscript(nodelist
[i
]))
1299 return Subscript(primary
, assigning
, subscripts
,
1300 lineno
=extractLineNo(nodelist
))
1302 def com_subscript(self
, node
):
1303 # slice_item: expression | proper_slice | ellipsis
1306 if t
== token
.DOT
and node
[2][0] == token
.DOT
:
1308 if t
== token
.COLON
or len(node
) > 2:
1309 return self
.com_sliceobj(node
)
1310 return self
.com_node(ch
)
1312 def com_sliceobj(self
, node
):
1313 # proper_slice: short_slice | long_slice
1314 # short_slice: [lower_bound] ":" [upper_bound]
1315 # long_slice: short_slice ":" [stride]
1316 # lower_bound: expression
1317 # upper_bound: expression
1318 # stride: expression
1320 # Note: a stride may be further slicing...
1324 if node
[1][0] == token
.COLON
:
1325 items
.append(Const(None))
1328 items
.append(self
.com_node(node
[1]))
1332 if i
< len(node
) and node
[i
][0] == symbol
.test
:
1333 items
.append(self
.com_node(node
[i
]))
1336 items
.append(Const(None))
1338 # a short_slice has been built. look for long_slice now by looking
1340 for j
in range(i
, len(node
)):
1343 items
.append(Const(None))
1345 items
.append(self
.com_node(ch
[2]))
1346 return Sliceobj(items
, lineno
=extractLineNo(node
))
1348 def com_slice(self
, primary
, node
, assigning
):
1349 # short_slice: [lower_bound] ":" [upper_bound]
1350 lower
= upper
= None
1352 if node
[1][0] == token
.COLON
:
1353 upper
= self
.com_node(node
[2])
1355 lower
= self
.com_node(node
[1])
1356 elif len(node
) == 4:
1357 lower
= self
.com_node(node
[1])
1358 upper
= self
.com_node(node
[3])
1359 return Slice(primary
, assigning
, lower
, upper
,
1360 lineno
=extractLineNo(node
))
1362 def get_docstring(self
, node
, n
=None):
1366 if n
== symbol
.suite
:
1368 return self
.get_docstring(node
[0])
1370 if sub
[0] == symbol
.stmt
:
1371 return self
.get_docstring(sub
)
1373 if n
== symbol
.file_input
:
1375 if sub
[0] == symbol
.stmt
:
1376 return self
.get_docstring(sub
)
1378 if n
== symbol
.atom
:
1379 if node
[0][0] == token
.STRING
:
1385 if n
== symbol
.stmt
or n
== symbol
.simple_stmt \
1386 or n
== symbol
.small_stmt
:
1387 return self
.get_docstring(node
[0])
1388 if n
in _doc_nodes
and len(node
) == 1:
1389 return self
.get_docstring(node
[0])
1396 symbol
.testlist_safe
,
1412 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
1413 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
1416 token
.GREATER
: '>',
1417 token
.EQEQUAL
: '==',
1419 token
.LESSEQUAL
: '<=',
1420 token
.GREATEREQUAL
: '>=',
1421 token
.NOTEQUAL
: '!=',
1424 _legal_node_types
= [
1431 symbol
.compound_stmt
,
1437 symbol
.continue_stmt
,
1451 symbol
.testlist_safe
,
1468 if hasattr(symbol
, 'yield_stmt'):
1469 _legal_node_types
.append(symbol
.yield_stmt
)
1470 if hasattr(symbol
, 'yield_expr'):
1471 _legal_node_types
.append(symbol
.yield_expr
)
1489 for k
, v
in symbol
.sym_name
.items():
1491 for k
, v
in token
.tok_name
.items():
1494 def debug_tree(tree
):
1497 if isinstance(elt
, int):
1498 l
.append(_names
.get(elt
, elt
))
1499 elif isinstance(elt
, str):
1502 l
.append(debug_tree(elt
))