OILS / opy / compiler2 / transformer.py View on Github | oilshell.org

1518 lines, 1117 significant
1"""Parse tree transformation module.
2
3Transforms Python source code into an abstract syntax tree (AST)
4defined in the ast module.
5
6The simplest ways to invoke this module are via parse and parseFile.
7parse(buf) -> AST
8parseFile(path) -> AST
9"""
10
11# Original version written by Greg Stein (gstein@lyra.org)
12# and Bill Tutt (rassilon@lima.mudlib.org)
13# February 1997.
14#
15# Modifications and improvements for Python 2.0 by Jeremy Hylton and
16# Mark Hammond
17#
18# Some fixes to try to have correct line number on almost all nodes
19# (except Module, Discard and Stmt) added by Sylvain Thenault
20#
21# Portions of this file are:
22# Copyright (C) 1997-1998 Greg Stein. All Rights Reserved.
23#
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.
27
28from .ast import *
29from .consts import CO_VARARGS, CO_VARKEYWORDS
30from .consts import OP_ASSIGN, OP_DELETE, OP_APPLY
31
32from ..pytree import type_repr
33from pgen2 import token
34
35
36symbol = None
37
38def Init(sym):
39 """Replacement for the stdlib symbol module.
40
41 Args:
42 sym: module
43
44 The stdlib module is generated from pgen.c's output data. pgen2 derives it
45 from the grammar directly.
46
47 """
48 global symbol
49 symbol = sym
50 _InitGlobals()
51
52
53# Various constants
54_doc_nodes = []
55_legal_node_types = []
56_assign_types = []
57# NOTE: This is somewhat duplicated in pytree.py as type_repr.
58_names = {}
59
60def _InitGlobals():
61 _doc_nodes.extend([
62 symbol.expr_stmt,
63 symbol.testlist,
64 symbol.testlist_safe,
65 symbol.test,
66 symbol.or_test,
67 symbol.and_test,
68 symbol.not_test,
69 symbol.comparison,
70 symbol.expr,
71 symbol.xor_expr,
72 symbol.and_expr,
73 symbol.shift_expr,
74 symbol.arith_expr,
75 symbol.term,
76 symbol.factor,
77 symbol.power,
78 ])
79
80 _legal_node_types.extend([
81 symbol.funcdef,
82 symbol.classdef,
83 symbol.stmt,
84 symbol.small_stmt,
85 symbol.flow_stmt,
86 symbol.simple_stmt,
87 symbol.compound_stmt,
88 symbol.expr_stmt,
89 symbol.print_stmt,
90 symbol.del_stmt,
91 symbol.pass_stmt,
92 symbol.break_stmt,
93 symbol.continue_stmt,
94 symbol.return_stmt,
95 symbol.raise_stmt,
96 symbol.import_stmt,
97 symbol.global_stmt,
98 symbol.exec_stmt,
99 symbol.assert_stmt,
100 symbol.if_stmt,
101 symbol.while_stmt,
102 symbol.for_stmt,
103 symbol.try_stmt,
104 symbol.with_stmt,
105 symbol.suite,
106 symbol.testlist,
107 symbol.testlist_safe,
108 symbol.test,
109 symbol.and_test,
110 symbol.not_test,
111 symbol.comparison,
112 symbol.exprlist,
113 symbol.expr,
114 symbol.xor_expr,
115 symbol.and_expr,
116 symbol.shift_expr,
117 symbol.arith_expr,
118 symbol.term,
119 symbol.factor,
120 symbol.power,
121 symbol.atom,
122 ])
123
124 if hasattr(symbol, 'yield_stmt'):
125 _legal_node_types.append(symbol.yield_stmt)
126 if hasattr(symbol, 'yield_expr'):
127 _legal_node_types.append(symbol.yield_expr)
128
129 _assign_types.extend([
130 symbol.test,
131 symbol.or_test,
132 symbol.and_test,
133 symbol.not_test,
134 symbol.comparison,
135 symbol.expr,
136 symbol.xor_expr,
137 symbol.and_expr,
138 symbol.shift_expr,
139 symbol.arith_expr,
140 symbol.term,
141 symbol.factor,
142 ])
143
144 # Do this first because NT_OFFSET (non-terminal offset) conflicts with
145 # file_input.
146 for k, v in token.tok_name.items():
147 _names[k] = v
148 for k, v in symbol.number2symbol.items():
149 _names[k] = v
150
151
152# comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
153# | 'in' | 'not' 'in' | 'is' | 'is' 'not'
154_cmp_types = {
155 token.LESS : '<',
156 token.GREATER : '>',
157 token.EQEQUAL : '==',
158 token.EQUAL : '==',
159 token.LESSEQUAL : '<=',
160 token.GREATEREQUAL : '>=',
161 token.NOTEQUAL : '!=',
162 }
163
164
165class WalkerError(StandardError):
166 pass
167
168
169def asList(nodes):
170 l = []
171 for item in nodes:
172 if hasattr(item, "asList"):
173 l.append(item.asList())
174 else:
175 if type(item) is type( (None, None) ):
176 l.append(tuple(asList(item)))
177 elif type(item) is type( [] ):
178 l.append(asList(item))
179 else:
180 l.append(item)
181 return l
182
183def extractLineNo(ast):
184 if not isinstance(ast[1], tuple):
185 # get a terminal node
186 return ast[2]
187 for child in ast[1:]:
188 if isinstance(child, tuple):
189 lineno = extractLineNo(child)
190 if lineno is not None:
191 return lineno
192
193def Node(*args):
194 kind = args[0]
195 if kind in nodes:
196 try:
197 return nodes[kind](*args[1:])
198 except TypeError:
199 print(nodes[kind], len(args), args)
200 raise
201 else:
202 raise WalkerError, "Can't find appropriate Node type: %s" % str(args)
203 #return apply(ast.Node, args)
204
205class Transformer(object):
206 """Transform a parse tree into an AST."""
207
208 def __init__(self):
209 self._dispatch = {}
210 for value, name in symbol.number2symbol.items():
211 if hasattr(self, name):
212 self._dispatch[value] = getattr(self, name)
213 self._dispatch[token.NEWLINE] = self.com_NEWLINE
214 self._atom_dispatch = {token.LPAR: self.atom_lpar,
215 token.LSQB: self.atom_lsqb,
216 token.LBRACE: self.atom_lbrace,
217 token.BACKQUOTE: self.atom_backquote,
218 token.NUMBER: self.atom_number,
219 token.STRING: self.atom_string,
220 token.NAME: self.atom_name,
221 }
222 self.encoding = None
223
224 def transform(self, node):
225 ### emit a line-number node?
226 n = node[0]
227
228 if n == symbol.encoding_decl:
229 self.encoding = node[2]
230 node = node[1]
231 n = node[0]
232
233 if n == symbol.single_input:
234 return self.single_input(node[1:])
235 if n == symbol.file_input:
236 return self.file_input(node[1:])
237 if n == symbol.eval_input:
238 return self.eval_input(node[1:])
239 if n == symbol.lambdef:
240 return self.lambdef(node[1:])
241 if n == symbol.funcdef:
242 return self.funcdef(node[1:])
243 if n == symbol.classdef:
244 return self.classdef(node[1:])
245
246 raise WalkerError('unexpected node type %r' % type_repr(n))
247
248 # --------------------------------------------------------------
249 #
250 # PRIVATE METHODS
251 #
252
253 def single_input(self, node):
254 ### do we want to do anything about being "interactive" ?
255
256 # NEWLINE | simple_stmt | compound_stmt NEWLINE
257 n = node[0][0]
258 if n != token.NEWLINE:
259 return self.com_stmt(node[0])
260
261 return Pass()
262
263 def file_input(self, nodelist):
264 doc = self.get_docstring(nodelist, symbol.file_input)
265 if doc is not None:
266 i = 1
267 else:
268 i = 0
269 stmts = []
270 for node in nodelist[i:]:
271 if node[0] != token.ENDMARKER and node[0] != token.NEWLINE:
272 self.com_append_stmt(stmts, node)
273 return Module(doc, Stmt(stmts))
274
275 def eval_input(self, nodelist):
276 # from the built-in function input()
277 ### is this sufficient?
278 return Expression(self.com_node(nodelist[0]))
279
280 def decorator_name(self, nodelist):
281 listlen = len(nodelist)
282 assert listlen >= 1 and listlen % 2 == 1
283
284 item = self.atom_name(nodelist)
285 i = 1
286 while i < listlen:
287 assert nodelist[i][0] == token.DOT
288 assert nodelist[i + 1][0] == token.NAME
289 item = Getattr(item, nodelist[i + 1][1])
290 i += 2
291
292 return item
293
294 def decorator(self, nodelist):
295 # '@' dotted_name [ '(' [arglist] ')' ]
296 assert len(nodelist) in (3, 5, 6)
297 assert nodelist[0][0] == token.AT
298 assert nodelist[-1][0] == token.NEWLINE
299
300 assert nodelist[1][0] == symbol.dotted_name
301 funcname = self.decorator_name(nodelist[1][1:])
302
303 if len(nodelist) > 3:
304 assert nodelist[2][0] == token.LPAR
305 expr = self.com_call_function(funcname, nodelist[3])
306 else:
307 expr = funcname
308
309 return expr
310
311 def decorators(self, nodelist):
312 # decorators: decorator ([NEWLINE] decorator)* NEWLINE
313 items = []
314 for dec_nodelist in nodelist:
315 assert dec_nodelist[0] == symbol.decorator
316 items.append(self.decorator(dec_nodelist[1:]))
317 return Decorators(items)
318
319 def decorated(self, nodelist):
320 assert nodelist[0][0] == symbol.decorators
321 if nodelist[1][0] == symbol.funcdef:
322 n = [nodelist[0]] + list(nodelist[1][1:])
323 return self.funcdef(n)
324 elif nodelist[1][0] == symbol.classdef:
325 decorators = self.decorators(nodelist[0][1:])
326 cls = self.classdef(nodelist[1][1:])
327 cls.decorators = decorators
328 return cls
329 raise WalkerError()
330
331 def funcdef(self, nodelist):
332 # -6 -5 -4 -3 -2 -1
333 # funcdef: [decorators] 'def' NAME parameters ':' suite
334 # parameters: '(' [varargslist] ')'
335
336 if len(nodelist) == 6:
337 assert nodelist[0][0] == symbol.decorators
338 decorators = self.decorators(nodelist[0][1:])
339 else:
340 assert len(nodelist) == 5
341 decorators = None
342
343 lineno = nodelist[-4][2]
344 name = nodelist[-4][1]
345 args = nodelist[-3][2]
346
347 if args[0] == symbol.varargslist:
348 names, defaults, flags = self.com_arglist(args[1:])
349 else:
350 names = defaults = ()
351 flags = 0
352 doc = self.get_docstring(nodelist[-1])
353
354 # code for function
355 code = self.com_node(nodelist[-1])
356
357 if doc is not None:
358 assert isinstance(code, Stmt)
359 assert isinstance(code.nodes[0], Discard)
360 del code.nodes[0]
361 return Function(decorators, name, names, defaults, flags, doc, code,
362 lineno=lineno)
363
364 def lambdef(self, nodelist):
365 # lambdef: 'lambda' [varargslist] ':' test
366 if nodelist[2][0] == symbol.varargslist:
367 names, defaults, flags = self.com_arglist(nodelist[2][1:])
368 else:
369 names = defaults = ()
370 flags = 0
371
372 # code for lambda
373 code = self.com_node(nodelist[-1])
374
375 return Lambda(names, defaults, flags, code, lineno=nodelist[1][2])
376 old_lambdef = lambdef
377
378 def classdef(self, nodelist):
379 # classdef: 'class' NAME ['(' [testlist] ')'] ':' suite
380
381 name = nodelist[1][1]
382 doc = self.get_docstring(nodelist[-1])
383 if nodelist[2][0] == token.COLON:
384 bases = []
385 elif nodelist[3][0] == token.RPAR:
386 bases = []
387 else:
388 bases = self.com_bases(nodelist[3])
389
390 # code for class
391 code = self.com_node(nodelist[-1])
392
393 if doc is not None:
394 assert isinstance(code, Stmt)
395 assert isinstance(code.nodes[0], Discard)
396 del code.nodes[0]
397
398 return Class(name, bases, doc, code, lineno=nodelist[1][2])
399
400 def stmt(self, nodelist):
401 return self.com_stmt(nodelist[0])
402
403 small_stmt = stmt
404 flow_stmt = stmt
405 compound_stmt = stmt
406
407 def simple_stmt(self, nodelist):
408 # small_stmt (';' small_stmt)* [';'] NEWLINE
409 stmts = []
410 for i in range(0, len(nodelist), 2):
411 self.com_append_stmt(stmts, nodelist[i])
412 return Stmt(stmts)
413
414 def parameters(self, nodelist):
415 raise WalkerError
416
417 def varargslist(self, nodelist):
418 raise WalkerError
419
420 def fpdef(self, nodelist):
421 raise WalkerError
422
423 def fplist(self, nodelist):
424 raise WalkerError
425
426 def dotted_name(self, nodelist):
427 raise WalkerError
428
429 def comp_op(self, nodelist):
430 raise WalkerError
431
432 def trailer(self, nodelist):
433 raise WalkerError
434
435 def sliceop(self, nodelist):
436 raise WalkerError
437
438 def argument(self, nodelist):
439 raise WalkerError
440
441 # --------------------------------------------------------------
442 #
443 # STATEMENT NODES (invoked by com_node())
444 #
445
446 def expr_stmt(self, nodelist):
447 # augassign testlist | testlist ('=' testlist)*
448 en = nodelist[-1]
449 exprNode = self.lookup_node(en)(en[1:])
450 if len(nodelist) == 1:
451 return Discard(exprNode, lineno=exprNode.lineno)
452 if nodelist[1][0] == token.EQUAL:
453 nodesl = []
454 for i in range(0, len(nodelist) - 2, 2):
455 nodesl.append(self.com_assign(nodelist[i], OP_ASSIGN))
456 return Assign(nodesl, exprNode, lineno=nodelist[1][2])
457 else:
458 lval = self.com_augassign(nodelist[0])
459 op = self.com_augassign_op(nodelist[1])
460 return AugAssign(lval, op[1], exprNode, lineno=op[2])
461 raise WalkerError, "can't get here"
462
463 def print_stmt(self, nodelist):
464 # print ([ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ])
465 items = []
466 if len(nodelist) == 1:
467 start = 1
468 dest = None
469 elif nodelist[1][0] == token.RIGHTSHIFT:
470 assert len(nodelist) == 3 \
471 or nodelist[3][0] == token.COMMA
472 dest = self.com_node(nodelist[2])
473 start = 4
474 else:
475 dest = None
476 start = 1
477 for i in range(start, len(nodelist), 2):
478 items.append(self.com_node(nodelist[i]))
479 if nodelist[-1][0] == token.COMMA:
480 return Print(items, dest, lineno=nodelist[0][2])
481 return Printnl(items, dest, lineno=nodelist[0][2])
482
483 def del_stmt(self, nodelist):
484 return self.com_assign(nodelist[1], OP_DELETE)
485
486 def pass_stmt(self, nodelist):
487 return Pass(lineno=nodelist[0][2])
488
489 def break_stmt(self, nodelist):
490 return Break(lineno=nodelist[0][2])
491
492 def continue_stmt(self, nodelist):
493 return Continue(lineno=nodelist[0][2])
494
495 def return_stmt(self, nodelist):
496 # return: [testlist]
497 if len(nodelist) < 2:
498 return Return(Const(None), lineno=nodelist[0][2])
499 return Return(self.com_node(nodelist[1]), lineno=nodelist[0][2])
500
501 def yield_stmt(self, nodelist):
502 expr = self.com_node(nodelist[0])
503 return Discard(expr, lineno=expr.lineno)
504
505 def yield_expr(self, nodelist):
506 if len(nodelist) > 1:
507 value = self.com_node(nodelist[1])
508 else:
509 value = Const(None)
510 return Yield(value, lineno=nodelist[0][2])
511
512 def raise_stmt(self, nodelist):
513 # raise: [test [',' test [',' test]]]
514 if len(nodelist) > 5:
515 expr3 = self.com_node(nodelist[5])
516 else:
517 expr3 = None
518 if len(nodelist) > 3:
519 expr2 = self.com_node(nodelist[3])
520 else:
521 expr2 = None
522 if len(nodelist) > 1:
523 expr1 = self.com_node(nodelist[1])
524 else:
525 expr1 = None
526 return Raise(expr1, expr2, expr3, lineno=nodelist[0][2])
527
528 def import_stmt(self, nodelist):
529 # import_stmt: import_name | import_from
530 assert len(nodelist) == 1
531 return self.com_node(nodelist[0])
532
533 def import_name(self, nodelist):
534 # import_name: 'import' dotted_as_names
535 return Import(self.com_dotted_as_names(nodelist[1]),
536 lineno=nodelist[0][2])
537
538 def import_from(self, nodelist):
539 # import_from: 'from' ('.'* dotted_name | '.') 'import' ('*' |
540 # '(' import_as_names ')' | import_as_names)
541 assert nodelist[0][1] == 'from'
542 idx = 1
543 while nodelist[idx][1] == '.':
544 idx += 1
545 level = idx - 1
546 if nodelist[idx][0] == symbol.dotted_name:
547 fromname = self.com_dotted_name(nodelist[idx])
548 idx += 1
549 else:
550 fromname = ""
551 assert nodelist[idx][1] == 'import'
552 if nodelist[idx + 1][0] == token.STAR:
553 return From(fromname, [('*', None)], level,
554 lineno=nodelist[0][2])
555 else:
556 node = nodelist[idx + 1 + (nodelist[idx + 1][0] == token.LPAR)]
557 return From(fromname, self.com_import_as_names(node), level,
558 lineno=nodelist[0][2])
559
560 def global_stmt(self, nodelist):
561 # global: NAME (',' NAME)*
562 names = []
563 for i in range(1, len(nodelist), 2):
564 names.append(nodelist[i][1])
565 return Global(names, lineno=nodelist[0][2])
566
567 def exec_stmt(self, nodelist):
568 # exec_stmt: 'exec' expr ['in' expr [',' expr]]
569 expr1 = self.com_node(nodelist[1])
570 if len(nodelist) >= 4:
571 expr2 = self.com_node(nodelist[3])
572 if len(nodelist) >= 6:
573 expr3 = self.com_node(nodelist[5])
574 else:
575 expr3 = None
576 else:
577 expr2 = expr3 = None
578
579 return Exec(expr1, expr2, expr3, lineno=nodelist[0][2])
580
581 def assert_stmt(self, nodelist):
582 # 'assert': test, [',' test]
583 expr1 = self.com_node(nodelist[1])
584 if (len(nodelist) == 4):
585 expr2 = self.com_node(nodelist[3])
586 else:
587 expr2 = None
588 return Assert(expr1, expr2, lineno=nodelist[0][2])
589
590 def if_stmt(self, nodelist):
591 # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
592 tests = []
593 for i in range(0, len(nodelist) - 3, 4):
594 testNode = self.com_node(nodelist[i + 1])
595 suiteNode = self.com_node(nodelist[i + 3])
596 tests.append((testNode, suiteNode))
597
598 if len(nodelist) % 4 == 3:
599 elseNode = self.com_node(nodelist[-1])
600## elseNode.lineno = nodelist[-1][1][2]
601 else:
602 elseNode = None
603 return If(tests, elseNode, lineno=nodelist[0][2])
604
605 def while_stmt(self, nodelist):
606 # 'while' test ':' suite ['else' ':' suite]
607
608 testNode = self.com_node(nodelist[1])
609 bodyNode = self.com_node(nodelist[3])
610
611 if len(nodelist) > 4:
612 elseNode = self.com_node(nodelist[6])
613 else:
614 elseNode = None
615
616 return While(testNode, bodyNode, elseNode, lineno=nodelist[0][2])
617
618 def for_stmt(self, nodelist):
619 # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
620
621 assignNode = self.com_assign(nodelist[1], OP_ASSIGN)
622 listNode = self.com_node(nodelist[3])
623 bodyNode = self.com_node(nodelist[5])
624
625 if len(nodelist) > 8:
626 elseNode = self.com_node(nodelist[8])
627 else:
628 elseNode = None
629
630 return For(assignNode, listNode, bodyNode, elseNode,
631 lineno=nodelist[0][2])
632
633 def try_stmt(self, nodelist):
634 return self.com_try_except_finally(nodelist)
635
636 def with_stmt(self, nodelist):
637 return self.com_with(nodelist)
638
639 def with_var(self, nodelist):
640 return self.com_with_var(nodelist)
641
642 def suite(self, nodelist):
643 # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
644 if len(nodelist) == 1:
645 return self.com_stmt(nodelist[0])
646
647 stmts = []
648 for node in nodelist:
649 if node[0] == symbol.stmt:
650 self.com_append_stmt(stmts, node)
651 return Stmt(stmts)
652
653 # --------------------------------------------------------------
654 #
655 # EXPRESSION NODES (invoked by com_node())
656 #
657
658 def testlist(self, nodelist):
659 # testlist: expr (',' expr)* [',']
660 # testlist_safe: test [(',' test)+ [',']]
661 # exprlist: expr (',' expr)* [',']
662 return self.com_binary(Tuple, nodelist)
663
664 testlist_safe = testlist # XXX
665 testlist1 = testlist
666 exprlist = testlist
667
668 def testlist_comp(self, nodelist):
669 # test ( comp_for | (',' test)* [','] )
670 assert nodelist[0][0] == symbol.test
671 if len(nodelist) == 2 and nodelist[1][0] == symbol.comp_for:
672 test = self.com_node(nodelist[0])
673 return self.com_generator_expression(test, nodelist[1])
674 return self.testlist(nodelist)
675
676 def test(self, nodelist):
677 # or_test ['if' or_test 'else' test] | lambdef
678 if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef:
679 return self.lambdef(nodelist[0])
680 then = self.com_node(nodelist[0])
681 if len(nodelist) > 1:
682 assert len(nodelist) == 5
683 assert nodelist[1][1] == 'if'
684 assert nodelist[3][1] == 'else'
685 test = self.com_node(nodelist[2])
686 else_ = self.com_node(nodelist[4])
687 return IfExp(test, then, else_, lineno=nodelist[1][2])
688 return then
689
690 def or_test(self, nodelist):
691 # and_test ('or' and_test)* | lambdef
692 if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef:
693 return self.lambdef(nodelist[0])
694 return self.com_binary(Or, nodelist)
695 old_test = or_test
696
697 def and_test(self, nodelist):
698 # not_test ('and' not_test)*
699 return self.com_binary(And, nodelist)
700
701 def not_test(self, nodelist):
702 # 'not' not_test | comparison
703 result = self.com_node(nodelist[-1])
704 if len(nodelist) == 2:
705 return Not(result, lineno=nodelist[0][2])
706 return result
707
708 def comparison(self, nodelist):
709 # comparison: expr (comp_op expr)*
710 node = self.com_node(nodelist[0])
711 if len(nodelist) == 1:
712 return node
713
714 results = []
715 for i in range(2, len(nodelist), 2):
716 nl = nodelist[i-1]
717
718 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
719 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
720 n = nl[1]
721 if n[0] == token.NAME:
722 type = n[1]
723 if len(nl) == 3:
724 if type == 'not':
725 type = 'not in'
726 else:
727 type = 'is not'
728 else:
729 type = _cmp_types[n[0]]
730
731 lineno = nl[1][2]
732 results.append((type, self.com_node(nodelist[i])))
733
734 # we need a special "compare" node so that we can distinguish
735 # 3 < x < 5 from (3 < x) < 5
736 # the two have very different semantics and results (note that the
737 # latter form is always true)
738
739 return Compare(node, results, lineno=lineno)
740
741 def expr(self, nodelist):
742 # xor_expr ('|' xor_expr)*
743 return self.com_binary(Bitor, nodelist)
744
745 def xor_expr(self, nodelist):
746 # xor_expr ('^' xor_expr)*
747 return self.com_binary(Bitxor, nodelist)
748
749 def and_expr(self, nodelist):
750 # xor_expr ('&' xor_expr)*
751 return self.com_binary(Bitand, nodelist)
752
753 def shift_expr(self, nodelist):
754 # shift_expr ('<<'|'>>' shift_expr)*
755 node = self.com_node(nodelist[0])
756 for i in range(2, len(nodelist), 2):
757 right = self.com_node(nodelist[i])
758 if nodelist[i-1][0] == token.LEFTSHIFT:
759 node = LeftShift([node, right], lineno=nodelist[1][2])
760 elif nodelist[i-1][0] == token.RIGHTSHIFT:
761 node = RightShift([node, right], lineno=nodelist[1][2])
762 else:
763 raise ValueError, "unexpected token: %s" % nodelist[i-1][0]
764 return node
765
766 def arith_expr(self, nodelist):
767 node = self.com_node(nodelist[0])
768 for i in range(2, len(nodelist), 2):
769 right = self.com_node(nodelist[i])
770 if nodelist[i-1][0] == token.PLUS:
771 node = Add([node, right], lineno=nodelist[1][2])
772 elif nodelist[i-1][0] == token.MINUS:
773 node = Sub([node, right], lineno=nodelist[1][2])
774 else:
775 raise ValueError, "unexpected token: %s" % nodelist[i-1][0]
776 return node
777
778 def term(self, nodelist):
779 node = self.com_node(nodelist[0])
780 for i in range(2, len(nodelist), 2):
781 right = self.com_node(nodelist[i])
782 t = nodelist[i-1][0]
783 if t == token.STAR:
784 node = Mul([node, right])
785 elif t == token.SLASH:
786 node = Div([node, right])
787 elif t == token.PERCENT:
788 node = Mod([node, right])
789 elif t == token.DOUBLESLASH:
790 node = FloorDiv([node, right])
791 else:
792 raise ValueError, "unexpected token: %s" % t
793 node.lineno = nodelist[1][2]
794 return node
795
796 def factor(self, nodelist):
797 elt = nodelist[0]
798 t = elt[0]
799 node = self.lookup_node(nodelist[-1])(nodelist[-1][1:])
800 # need to handle (unary op)constant here...
801 if t == token.PLUS:
802 return UnaryAdd(node, lineno=elt[2])
803 elif t == token.MINUS:
804 return UnarySub(node, lineno=elt[2])
805 elif t == token.TILDE:
806 node = Invert(node, lineno=elt[2])
807 return node
808
809 def power(self, nodelist):
810 # power: atom trailer* ['**' factor]
811 node = self.com_node(nodelist[0])
812 for i in range(1, len(nodelist)):
813 elt = nodelist[i]
814 if elt[0] == token.DOUBLESTAR:
815 return Power([node, self.com_node(nodelist[i+1])],
816 lineno=elt[2])
817
818 node = self.com_apply_trailer(node, elt)
819
820 return node
821
822 def atom(self, nodelist):
823 return self._atom_dispatch[nodelist[0][0]](nodelist)
824
825 def atom_lpar(self, nodelist):
826 if nodelist[1][0] == token.RPAR:
827 return Tuple((), lineno=nodelist[0][2])
828 return self.com_node(nodelist[1])
829
830 def atom_lsqb(self, nodelist):
831 if nodelist[1][0] == token.RSQB:
832 return List((), lineno=nodelist[0][2])
833 return self.com_list_constructor(nodelist[1])
834
835 def atom_lbrace(self, nodelist):
836 if nodelist[1][0] == token.RBRACE:
837 return Dict((), lineno=nodelist[0][2])
838 return self.com_dictorsetmaker(nodelist[1])
839
840 def atom_backquote(self, nodelist):
841 return Backquote(self.com_node(nodelist[1]))
842
843 def atom_number(self, nodelist):
844 ### need to verify this matches compile.c
845 k = eval(nodelist[0][1])
846 return Const(k, lineno=nodelist[0][2])
847
848 def decode_literal(self, lit):
849 if self.encoding:
850 # this is particularly fragile & a bit of a
851 # hack... changes in compile.c:parsestr and
852 # tokenizer.c must be reflected here.
853 if self.encoding not in ['utf-8', 'iso-8859-1']:
854 lit = unicode(lit, 'utf-8').encode(self.encoding)
855 return eval("# coding: %s\n%s" % (self.encoding, lit))
856 else:
857 return eval(lit)
858
859 def atom_string(self, nodelist):
860 k = ''
861 for node in nodelist:
862 k += self.decode_literal(node[1])
863 return Const(k, lineno=nodelist[0][2])
864
865 def atom_name(self, nodelist):
866 return Name(nodelist[0][1], lineno=nodelist[0][2])
867
868 # --------------------------------------------------------------
869 #
870 # INTERNAL PARSING UTILITIES
871 #
872
873 # The use of com_node() introduces a lot of extra stack frames,
874 # enough to cause a stack overflow compiling test.test_parser with
875 # the standard interpreter recursionlimit. The com_node() is a
876 # convenience function that hides the dispatch details, but comes
877 # at a very high cost. It is more efficient to dispatch directly
878 # in the callers. In these cases, use lookup_node() and call the
879 # dispatched node directly.
880
881 def lookup_node(self, node):
882 return self._dispatch[node[0]]
883
884 def com_node(self, node):
885 # Note: compile.c has handling in com_node for del_stmt, pass_stmt,
886 # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
887 # and compound_stmt.
888 # We'll just dispatch them.
889 return self._dispatch[node[0]](node[1:])
890
891 def com_NEWLINE(self, *args):
892 # A ';' at the end of a line can make a NEWLINE token appear
893 # here, Render it harmless. (genc discards ('discard',
894 # ('const', xxxx)) Nodes)
895 return Discard(Const(None))
896
897 def com_arglist(self, nodelist):
898 # varargslist:
899 # (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME)
900 # | fpdef ['=' test] (',' fpdef ['=' test])* [',']
901 # fpdef: NAME | '(' fplist ')'
902 # fplist: fpdef (',' fpdef)* [',']
903 names = []
904 defaults = []
905 flags = 0
906
907 i = 0
908 while i < len(nodelist):
909 node = nodelist[i]
910 if node[0] == token.STAR or node[0] == token.DOUBLESTAR:
911 if node[0] == token.STAR:
912 node = nodelist[i+1]
913 if node[0] == token.NAME:
914 names.append(node[1])
915 flags = flags | CO_VARARGS
916 i = i + 3
917
918 if i < len(nodelist):
919 # should be DOUBLESTAR
920 t = nodelist[i][0]
921 if t == token.DOUBLESTAR:
922 node = nodelist[i+1]
923 else:
924 raise ValueError, "unexpected token: %s" % t
925 names.append(node[1])
926 flags = flags | CO_VARKEYWORDS
927
928 break
929
930 # fpdef: NAME | '(' fplist ')'
931 names.append(self.com_fpdef(node))
932
933 i = i + 1
934 if i < len(nodelist) and nodelist[i][0] == token.EQUAL:
935 defaults.append(self.com_node(nodelist[i + 1]))
936 i = i + 2
937 elif len(defaults):
938 # we have already seen an argument with default, but here
939 # came one without
940 raise SyntaxError, "non-default argument follows default argument"
941
942 # skip the comma
943 i = i + 1
944
945 return names, defaults, flags
946
947 def com_fpdef(self, node):
948 # fpdef: NAME | '(' fplist ')'
949 if node[1][0] == token.LPAR:
950 return self.com_fplist(node[2])
951 return node[1][1]
952
953 def com_fplist(self, node):
954 # fplist: fpdef (',' fpdef)* [',']
955 if len(node) == 2:
956 return self.com_fpdef(node[1])
957 list = []
958 for i in range(1, len(node), 2):
959 list.append(self.com_fpdef(node[i]))
960 return tuple(list)
961
962 def com_dotted_name(self, node):
963 # String together the dotted names and return the string
964 name = ""
965 for n in node:
966 if type(n) == type(()) and n[0] == 1:
967 name = name + n[1] + '.'
968 return name[:-1]
969
970 def com_dotted_as_name(self, node):
971 assert node[0] == symbol.dotted_as_name
972 node = node[1:]
973 dot = self.com_dotted_name(node[0][1:])
974 if len(node) == 1:
975 return dot, None
976 assert node[1][1] == 'as'
977 assert node[2][0] == token.NAME
978 return dot, node[2][1]
979
980 def com_dotted_as_names(self, node):
981 assert node[0] == symbol.dotted_as_names
982 node = node[1:]
983 names = [self.com_dotted_as_name(node[0])]
984 for i in range(2, len(node), 2):
985 names.append(self.com_dotted_as_name(node[i]))
986 return names
987
988 def com_import_as_name(self, node):
989 assert node[0] == symbol.import_as_name
990 node = node[1:]
991 assert node[0][0] == token.NAME
992 if len(node) == 1:
993 return node[0][1], None
994 assert node[1][1] == 'as', node
995 assert node[2][0] == token.NAME
996 return node[0][1], node[2][1]
997
998 def com_import_as_names(self, node):
999 assert node[0] == symbol.import_as_names
1000 node = node[1:]
1001 names = [self.com_import_as_name(node[0])]
1002 for i in range(2, len(node), 2):
1003 names.append(self.com_import_as_name(node[i]))
1004 return names
1005
1006 def com_bases(self, node):
1007 bases = []
1008 for i in range(1, len(node), 2):
1009 bases.append(self.com_node(node[i]))
1010 return bases
1011
1012 def com_try_except_finally(self, nodelist):
1013 # ('try' ':' suite
1014 # ((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite]
1015 # | 'finally' ':' suite))
1016
1017 if nodelist[3][0] == token.NAME:
1018 # first clause is a finally clause: only try-finally
1019 return TryFinally(self.com_node(nodelist[2]),
1020 self.com_node(nodelist[5]),
1021 lineno=nodelist[0][2])
1022
1023 #tryexcept: [TryNode, [except_clauses], elseNode)]
1024 clauses = []
1025 elseNode = None
1026 finallyNode = None
1027 for i in range(3, len(nodelist), 3):
1028 node = nodelist[i]
1029 if node[0] == symbol.except_clause:
1030 # except_clause: 'except' [expr [(',' | 'as') expr]] */
1031 if len(node) > 2:
1032 expr1 = self.com_node(node[2])
1033 if len(node) > 4:
1034 expr2 = self.com_assign(node[4], OP_ASSIGN)
1035 else:
1036 expr2 = None
1037 else:
1038 expr1 = expr2 = None
1039 clauses.append((expr1, expr2, self.com_node(nodelist[i+2])))
1040
1041 if node[0] == token.NAME:
1042 if node[1] == 'else':
1043 elseNode = self.com_node(nodelist[i+2])
1044 elif node[1] == 'finally':
1045 finallyNode = self.com_node(nodelist[i+2])
1046 try_except = TryExcept(self.com_node(nodelist[2]), clauses, elseNode,
1047 lineno=nodelist[0][2])
1048 if finallyNode:
1049 return TryFinally(try_except, finallyNode, lineno=nodelist[0][2])
1050 else:
1051 return try_except
1052
1053 def com_with(self, nodelist):
1054 # with_stmt: 'with' with_item (',' with_item)* ':' suite
1055 body = self.com_node(nodelist[-1])
1056 for i in range(len(nodelist) - 3, 0, -2):
1057 ret = self.com_with_item(nodelist[i], body, nodelist[0][2])
1058 if i == 1:
1059 return ret
1060 body = ret
1061
1062 def com_with_item(self, nodelist, body, lineno):
1063 # with_item: test ['as' expr]
1064 if len(nodelist) == 4:
1065 var = self.com_assign(nodelist[3], OP_ASSIGN)
1066 else:
1067 var = None
1068 expr = self.com_node(nodelist[1])
1069 return With(expr, var, body, lineno=lineno)
1070
1071 def com_augassign_op(self, node):
1072 assert node[0] == symbol.augassign
1073 return node[1]
1074
1075 def com_augassign(self, node):
1076 """Return node suitable for lvalue of augmented assignment
1077
1078 Names, slices, and attributes are the only allowable nodes.
1079 """
1080 l = self.com_node(node)
1081 if l.__class__ in (Name, Slice, Subscript, Getattr):
1082 return l
1083 raise SyntaxError, "can't assign to %s" % l.__class__.__name__
1084
1085 def com_assign(self, node, assigning):
1086 # return a node suitable for use as an "lvalue"
1087 # loop to avoid trivial recursion
1088 while 1:
1089 t = node[0]
1090 if t in (symbol.exprlist, symbol.testlist, symbol.testlist_safe, symbol.testlist_comp):
1091 if len(node) > 2:
1092 return self.com_assign_tuple(node, assigning)
1093 node = node[1]
1094 elif t in _assign_types:
1095 if len(node) > 2:
1096 raise SyntaxError, "can't assign to operator"
1097 node = node[1]
1098 elif t == symbol.power:
1099 if node[1][0] != symbol.atom:
1100 raise SyntaxError, "can't assign to operator"
1101 if len(node) > 2:
1102 primary = self.com_node(node[1])
1103 for i in range(2, len(node)-1):
1104 ch = node[i]
1105 if ch[0] == token.DOUBLESTAR:
1106 raise SyntaxError, "can't assign to operator"
1107 primary = self.com_apply_trailer(primary, ch)
1108 return self.com_assign_trailer(primary, node[-1],
1109 assigning)
1110 node = node[1]
1111 elif t == symbol.atom:
1112 t = node[1][0]
1113 if t == token.LPAR:
1114 node = node[2]
1115 if node[0] == token.RPAR:
1116 raise SyntaxError, "can't assign to ()"
1117 elif t == token.LSQB:
1118 node = node[2]
1119 if node[0] == token.RSQB:
1120 raise SyntaxError, "can't assign to []"
1121 return self.com_assign_list(node, assigning)
1122 elif t == token.NAME:
1123 return self.com_assign_name(node[1], assigning)
1124 else:
1125 raise SyntaxError, "can't assign to literal"
1126 else:
1127 raise SyntaxError, "bad assignment (%s)" % t
1128
1129 def com_assign_tuple(self, node, assigning):
1130 assigns = []
1131 for i in range(1, len(node), 2):
1132 assigns.append(self.com_assign(node[i], assigning))
1133 return AssTuple(assigns, lineno=extractLineNo(node))
1134
1135 def com_assign_list(self, node, assigning):
1136 assigns = []
1137 for i in range(1, len(node), 2):
1138 if i + 1 < len(node):
1139 if node[i + 1][0] == symbol.list_for:
1140 raise SyntaxError, "can't assign to list comprehension"
1141 assert node[i + 1][0] == token.COMMA, node[i + 1]
1142 assigns.append(self.com_assign(node[i], assigning))
1143 return AssList(assigns, lineno=extractLineNo(node))
1144
1145 def com_assign_name(self, node, assigning):
1146 return AssName(node[1], assigning, lineno=node[2])
1147
1148 def com_assign_trailer(self, primary, node, assigning):
1149 t = node[1][0]
1150 if t == token.DOT:
1151 return self.com_assign_attr(primary, node[2], assigning)
1152 if t == token.LSQB:
1153 return self.com_subscriptlist(primary, node[2], assigning)
1154 if t == token.LPAR:
1155 raise SyntaxError, "can't assign to function call"
1156 raise SyntaxError, "unknown trailer type: %s" % t
1157
1158 def com_assign_attr(self, primary, node, assigning):
1159 return AssAttr(primary, node[1], assigning, lineno=node[-1])
1160
1161 def com_binary(self, constructor, nodelist):
1162 "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
1163 l = len(nodelist)
1164 if l == 1:
1165 n = nodelist[0]
1166 return self.lookup_node(n)(n[1:])
1167 items = []
1168 for i in range(0, l, 2):
1169 n = nodelist[i]
1170 items.append(self.lookup_node(n)(n[1:]))
1171 return constructor(items, lineno=extractLineNo(nodelist))
1172
1173 def com_stmt(self, node):
1174 result = self.lookup_node(node)(node[1:])
1175 assert result is not None
1176 if isinstance(result, Stmt):
1177 return result
1178 return Stmt([result])
1179
1180 def com_append_stmt(self, stmts, node):
1181 result = self.lookup_node(node)(node[1:])
1182 assert result is not None
1183 if isinstance(result, Stmt):
1184 stmts.extend(result.nodes)
1185 else:
1186 stmts.append(result)
1187
1188 def com_list_constructor(self, nodelist):
1189 # listmaker: test ( list_for | (',' test)* [','] )
1190 values = []
1191 for i in range(1, len(nodelist)):
1192 if nodelist[i][0] == symbol.list_for:
1193 assert len(nodelist[i:]) == 1
1194 return self.com_list_comprehension(values[0],
1195 nodelist[i])
1196 elif nodelist[i][0] == token.COMMA:
1197 continue
1198 values.append(self.com_node(nodelist[i]))
1199 return List(values, lineno=values[0].lineno)
1200
1201 def com_list_comprehension(self, expr, node):
1202 return self.com_comprehension(expr, None, node, 'list')
1203
1204 def com_comprehension(self, expr1, expr2, node, type):
1205 # list_iter: list_for | list_if
1206 # list_for: 'for' exprlist 'in' testlist [list_iter]
1207 # list_if: 'if' test [list_iter]
1208
1209 # XXX should raise SyntaxError for assignment
1210 # XXX(avassalotti) Set and dict comprehensions should have generator
1211 # semantics. In other words, they shouldn't leak
1212 # variables outside of the comprehension's scope.
1213
1214 lineno = node[1][2]
1215 fors = []
1216 while node:
1217 t = node[1][1]
1218 if t == 'for':
1219 assignNode = self.com_assign(node[2], OP_ASSIGN)
1220 compNode = self.com_node(node[4])
1221 newfor = ListCompFor(assignNode, compNode, [])
1222 newfor.lineno = node[1][2]
1223 fors.append(newfor)
1224 if len(node) == 5:
1225 node = None
1226 elif type == 'list':
1227 node = self.com_list_iter(node[5])
1228 else:
1229 node = self.com_comp_iter(node[5])
1230 elif t == 'if':
1231 test = self.com_node(node[2])
1232 newif = ListCompIf(test, lineno=node[1][2])
1233 newfor.ifs.append(newif)
1234 if len(node) == 3:
1235 node = None
1236 elif type == 'list':
1237 node = self.com_list_iter(node[3])
1238 else:
1239 node = self.com_comp_iter(node[3])
1240 else:
1241 raise SyntaxError, \
1242 ("unexpected comprehension element: %s %d"
1243 % (node, lineno))
1244 if type == 'list':
1245 return ListComp(expr1, fors, lineno=lineno)
1246 elif type == 'set':
1247 return SetComp(expr1, fors, lineno=lineno)
1248 elif type == 'dict':
1249 return DictComp(expr1, expr2, fors, lineno=lineno)
1250 else:
1251 raise ValueError("unexpected comprehension type: " + repr(type))
1252
1253 def com_list_iter(self, node):
1254 assert node[0] == symbol.list_iter
1255 return node[1]
1256
1257 def com_comp_iter(self, node):
1258 assert node[0] == symbol.comp_iter
1259 return node[1]
1260
1261 def com_generator_expression(self, expr, node):
1262 # comp_iter: comp_for | comp_if
1263 # comp_for: 'for' exprlist 'in' test [comp_iter]
1264 # comp_if: 'if' test [comp_iter]
1265
1266 lineno = node[1][2]
1267 fors = []
1268 while node:
1269 t = node[1][1]
1270 if t == 'for':
1271 assignNode = self.com_assign(node[2], OP_ASSIGN)
1272 genNode = self.com_node(node[4])
1273 newfor = GenExprFor(assignNode, genNode, [],
1274 lineno=node[1][2])
1275 fors.append(newfor)
1276 if (len(node)) == 5:
1277 node = None
1278 else:
1279 node = self.com_comp_iter(node[5])
1280 elif t == 'if':
1281 test = self.com_node(node[2])
1282 newif = GenExprIf(test, lineno=node[1][2])
1283 newfor.ifs.append(newif)
1284 if len(node) == 3:
1285 node = None
1286 else:
1287 node = self.com_comp_iter(node[3])
1288 else:
1289 raise SyntaxError, \
1290 ("unexpected generator expression element: %s %d"
1291 % (node, lineno))
1292 fors[0].is_outmost = True
1293 return GenExpr(GenExprInner(expr, fors), lineno=lineno)
1294
1295 def com_dictorsetmaker(self, nodelist):
1296 # dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) |
1297 # (test (comp_for | (',' test)* [','])) )
1298 assert nodelist[0] == symbol.dictorsetmaker
1299 nodelist = nodelist[1:]
1300 if len(nodelist) == 1 or nodelist[1][0] == token.COMMA:
1301 # set literal
1302 items = []
1303 for i in range(0, len(nodelist), 2):
1304 items.append(self.com_node(nodelist[i]))
1305 return Set(items, lineno=items[0].lineno)
1306 elif nodelist[1][0] == symbol.comp_for:
1307 # set comprehension
1308 expr = self.com_node(nodelist[0])
1309 return self.com_comprehension(expr, None, nodelist[1], 'set')
1310 elif len(nodelist) > 3 and nodelist[3][0] == symbol.comp_for:
1311 # dict comprehension
1312 assert nodelist[1][0] == token.COLON
1313 key = self.com_node(nodelist[0])
1314 value = self.com_node(nodelist[2])
1315 return self.com_comprehension(key, value, nodelist[3], 'dict')
1316 else:
1317 # dict literal
1318 items = []
1319 for i in range(0, len(nodelist), 4):
1320 items.append((self.com_node(nodelist[i]),
1321 self.com_node(nodelist[i+2])))
1322 return Dict(items, lineno=items[0][0].lineno)
1323
1324 def com_apply_trailer(self, primaryNode, nodelist):
1325 t = nodelist[1][0]
1326 if t == token.LPAR:
1327 return self.com_call_function(primaryNode, nodelist[2])
1328 if t == token.DOT:
1329 return self.com_select_member(primaryNode, nodelist[2])
1330 if t == token.LSQB:
1331 return self.com_subscriptlist(primaryNode, nodelist[2], OP_APPLY)
1332
1333 raise SyntaxError, 'unknown node type: %s' % t
1334
1335 def com_select_member(self, primaryNode, nodelist):
1336 if nodelist[0] != token.NAME:
1337 raise SyntaxError, "member must be a name"
1338 return Getattr(primaryNode, nodelist[1], lineno=nodelist[2])
1339
1340 def com_call_function(self, primaryNode, nodelist):
1341 if nodelist[0] == token.RPAR:
1342 return CallFunc(primaryNode, [], lineno=extractLineNo(nodelist))
1343 args = []
1344 kw = 0
1345 star_node = dstar_node = None
1346 len_nodelist = len(nodelist)
1347 i = 1
1348 while i < len_nodelist:
1349 node = nodelist[i]
1350
1351 if node[0]==token.STAR:
1352 if star_node is not None:
1353 raise SyntaxError, 'already have the varargs identifier'
1354 star_node = self.com_node(nodelist[i+1])
1355 i = i + 3
1356 continue
1357 elif node[0]==token.DOUBLESTAR:
1358 if dstar_node is not None:
1359 raise SyntaxError, 'already have the kwargs identifier'
1360 dstar_node = self.com_node(nodelist[i+1])
1361 i = i + 3
1362 continue
1363
1364 # positional or named parameters
1365 kw, result = self.com_argument(node, kw, star_node)
1366
1367 if len_nodelist != 2 and isinstance(result, GenExpr) \
1368 and len(node) == 3 and node[2][0] == symbol.comp_for:
1369 # allow f(x for x in y), but reject f(x for x in y, 1)
1370 # should use f((x for x in y), 1) instead of f(x for x in y, 1)
1371 raise SyntaxError, 'generator expression needs parenthesis'
1372
1373 args.append(result)
1374 i = i + 2
1375
1376 return CallFunc(primaryNode, args, star_node, dstar_node,
1377 lineno=extractLineNo(nodelist))
1378
1379 def com_argument(self, nodelist, kw, star_node):
1380 if len(nodelist) == 3 and nodelist[2][0] == symbol.comp_for:
1381 test = self.com_node(nodelist[1])
1382 return 0, self.com_generator_expression(test, nodelist[2])
1383 if len(nodelist) == 2:
1384 if kw:
1385 raise SyntaxError, "non-keyword arg after keyword arg"
1386 if star_node:
1387 raise SyntaxError, "only named arguments may follow *expression"
1388 return 0, self.com_node(nodelist[1])
1389 result = self.com_node(nodelist[3])
1390 n = nodelist[1]
1391 while len(n) == 2 and n[0] != token.NAME:
1392 n = n[1]
1393 if n[0] != token.NAME:
1394 raise SyntaxError, "keyword can't be an expression (%s)"%n[0]
1395 node = Keyword(n[1], result, lineno=n[2])
1396 return 1, node
1397
1398 def com_subscriptlist(self, primary, nodelist, assigning):
1399 # slicing: simple_slicing | extended_slicing
1400 # simple_slicing: primary "[" short_slice "]"
1401 # extended_slicing: primary "[" slice_list "]"
1402 # slice_list: slice_item ("," slice_item)* [","]
1403
1404 # backwards compat slice for '[i:j]'
1405 if len(nodelist) == 2:
1406 sub = nodelist[1]
1407 if (sub[1][0] == token.COLON or \
1408 (len(sub) > 2 and sub[2][0] == token.COLON)) and \
1409 sub[-1][0] != symbol.sliceop:
1410 return self.com_slice(primary, sub, assigning)
1411
1412 subscripts = []
1413 for i in range(1, len(nodelist), 2):
1414 subscripts.append(self.com_subscript(nodelist[i]))
1415 return Subscript(primary, assigning, subscripts,
1416 lineno=extractLineNo(nodelist))
1417
1418 def com_subscript(self, node):
1419 # slice_item: expression | proper_slice | ellipsis
1420 ch = node[1]
1421 t = ch[0]
1422 if t == token.DOT and node[2][0] == token.DOT:
1423 return Ellipsis()
1424 if t == token.COLON or len(node) > 2:
1425 return self.com_sliceobj(node)
1426 return self.com_node(ch)
1427
1428 def com_sliceobj(self, node):
1429 # proper_slice: short_slice | long_slice
1430 # short_slice: [lower_bound] ":" [upper_bound]
1431 # long_slice: short_slice ":" [stride]
1432 # lower_bound: expression
1433 # upper_bound: expression
1434 # stride: expression
1435 #
1436 # Note: a stride may be further slicing...
1437
1438 items = []
1439
1440 if node[1][0] == token.COLON:
1441 items.append(Const(None))
1442 i = 2
1443 else:
1444 items.append(self.com_node(node[1]))
1445 # i == 2 is a COLON
1446 i = 3
1447
1448 if i < len(node) and node[i][0] == symbol.test:
1449 items.append(self.com_node(node[i]))
1450 i = i + 1
1451 else:
1452 items.append(Const(None))
1453
1454 # a short_slice has been built. look for long_slice now by looking
1455 # for strides...
1456 for j in range(i, len(node)):
1457 ch = node[j]
1458 if len(ch) == 2:
1459 items.append(Const(None))
1460 else:
1461 items.append(self.com_node(ch[2]))
1462 return Sliceobj(items, lineno=extractLineNo(node))
1463
1464 def com_slice(self, primary, node, assigning):
1465 # short_slice: [lower_bound] ":" [upper_bound]
1466 lower = upper = None
1467 if len(node) == 3:
1468 if node[1][0] == token.COLON:
1469 upper = self.com_node(node[2])
1470 else:
1471 lower = self.com_node(node[1])
1472 elif len(node) == 4:
1473 lower = self.com_node(node[1])
1474 upper = self.com_node(node[3])
1475 return Slice(primary, assigning, lower, upper,
1476 lineno=extractLineNo(node))
1477
1478 def get_docstring(self, node, n=None):
1479 if n is None:
1480 n = node[0]
1481 node = node[1:]
1482 if n == symbol.suite:
1483 if len(node) == 1:
1484 return self.get_docstring(node[0])
1485 for sub in node:
1486 if sub[0] == symbol.stmt:
1487 return self.get_docstring(sub)
1488 return None
1489 if n == symbol.file_input:
1490 for sub in node:
1491 if sub[0] == symbol.stmt:
1492 return self.get_docstring(sub)
1493 return None
1494 if n == symbol.atom:
1495 if node[0][0] == token.STRING:
1496 s = ''
1497 for t in node:
1498 s = s + eval(t[1])
1499 return s
1500 return None
1501 if n == symbol.stmt or n == symbol.simple_stmt \
1502 or n == symbol.small_stmt:
1503 return self.get_docstring(node[0])
1504 if n in _doc_nodes and len(node) == 1:
1505 return self.get_docstring(node[0])
1506 return None
1507
1508
1509def debug_tree(tree):
1510 l = []
1511 for elt in tree:
1512 if isinstance(elt, int):
1513 l.append(_names.get(elt, elt))
1514 elif isinstance(elt, str):
1515 l.append(elt)
1516 else:
1517 l.append(debug_tree(elt))
1518 return l