blob: 42d34dcbdc608998b21c0bc019b85f59dfe2690b [file] [log] [blame]
Jeremy Hyltonf968e852000-02-04 00:25:23 +00001# Copyright 1997-1998 Greg Stein and Bill Tutt
2#
3# transformer.py -- transforms Python parse trees
4#
5# Takes an input parse tree and transforms it into a higher-level parse
6# tree that is a bit more amenable to code generation. Essentially, it
7# simply introduces some additional semantics.
8#
9# Written by Greg Stein (gstein@lyra.org)
10# and Bill Tutt (rassilon@lima.mudlib.org)
11# February 1997.
12#
13# Support for Node subclasses written by
14# Jeremy Hylton (jeremy@cnri.reston.va.us)
15#
16# The output tree has the following nodes:
17#
18# Source Python line #'s appear at the end of each of all of these nodes
19# If a line # doesn't apply, there will be a None instead.
20#
21# module: doc, node
22# stmt: [ node1, ..., nodeN ]
23# function: name, argnames, defaults, flags, doc, codeNode
24# lambda: argnames, defaults, flags, codeNode
25# classdef: name, bases, doc, codeNode
26# pass:
27# break:
28# continue:
29# for: assignNode, listNode, bodyNode, elseNode
30# while: testNode, bodyNode, elseNode
31# if: [ (testNode, suiteNode), ... ], elseNode
32# exec: expr1Node, expr2Node, expr3Node
33# from: modname, [ name1, ..., nameN ]
34# import: [ name1, ..., nameN ]
35# raise: expr1Node, expr2Node, expr3Node
36# tryfinally: trySuiteNode, finSuiteNode
37# tryexcept: trySuiteNode, [ (exprNode, assgnNode, suiteNode), ... ], elseNode
38# return: valueNode
39# const: value
40# print: [ node1, ..., nodeN ]
41# printnl: [ node1, ..., nodeN ]
42# discard: exprNode
43# assign: [ node1, ..., nodeN ], exprNode
44# ass_tuple: [ node1, ..., nodeN ]
45# ass_list: [ node1, ..., nodeN ]
46# ass_name: name, flags
47# ass_attr: exprNode, attrname, flags
48# list: [ node1, ..., nodeN ]
49# dict: [ (key1, val1), ..., (keyN, valN) ]
50# not: exprNode
51# compare: exprNode, [ (op, node), ..., (op, node) ]
52# name: name
53# global: [ name1, ..., nameN ]
54# backquote: node
55# getattr: exprNode, attrname
56# call_func: node, [ arg1, ..., argN ]
57# keyword: name, exprNode
58# subscript: exprNode, flags, [ sub1, ..., subN ]
59# ellipsis:
60# sliceobj: [ node1, ..., nodeN ]
61# slice: exprNode, flags, lowerNode, upperNode
62# assert: expr1, expr2
63#
64# Compiled as "binary" ops:
65# tuple: [ node1, ..., nodeN ]
66# or: [ node1, ..., nodeN ]
67# and: [ node1, ..., nodeN ]
68# bitor: [ node1, ..., nodeN ]
69# bitxor: [ node1, ..., nodeN ]
70# bitand: [ node1, ..., nodeN ]
71#
72# Operations easily evaluateable on constants:
73# <<: exprNode, shiftNode
74# >>: exprNode, shiftNode
75# +: leftNode, rightNode
76# -: leftNode, rightNode
77# *: leftNode, rightNode
78# /: leftNode, rightNode
79# %: leftNode, rightNode
80# power: leftNode, rightNode
81# unary+: node
82# unary-: node
83# invert: node
84#
85
86"""Parse tree transformation module.
87
88Exposes the Transformer class with a number of methods for returning a
89"cleansed AST" instead of the parse tree that the parser exposes.
90"""
91
92import ast
93import parser
94import symbol
95import token
96import string
97
98import pprint
99
100error = 'walker.error'
101
Jeremy Hylton9605c112000-02-08 18:57:32 +0000102from consts import CO_VARARGS, CO_VARKEYWORDS
103from consts import OP_ASSIGN, OP_DELETE, OP_APPLY
Jeremy Hyltonf968e852000-02-04 00:25:23 +0000104
105def asList(nodes):
106 l = []
107 for item in nodes:
108 if hasattr(item, "asList"):
109 l.append(item.asList())
110 else:
111 if type(item) is type( (None, None) ):
112 l.append(tuple(asList(item)))
113 elif type(item) is type( [] ):
114 l.append(asList(item))
115 else:
116 l.append(item)
117 return l
118
119def Node(*args):
120 kind = args[0]
121 if ast.nodes.has_key(kind):
122 try:
123 return apply(ast.nodes[kind], args[1:])
124 except TypeError:
125 print ast.nodes[kind], len(args), args
126 raise
127 else:
128 raise error, "Can't find appropriate Node type."
129 #return apply(ast.Node, args)
130
131class Transformer:
132 """Utility object for transforming Python parse trees.
133
134 Exposes the following methods:
135 tree = transform(ast_tree)
136 tree = parsesuite(text)
137 tree = parseexpr(text)
138 tree = parsefile(fileob | filename)
139 """
140
141 def __init__(self):
142 self._dispatch = { }
143 for value, name in symbol.sym_name.items():
144 if hasattr(self, name):
145 self._dispatch[value] = getattr(self, name)
146
147 def transform(self, tree):
148 """Transform an AST into a modified parse tree."""
149 if type(tree) != type(()) and type(tree) != type([]):
150 tree = parser.ast2tuple(tree,1)
151 return self.compile_node(tree)
152
153 def parsesuite(self, text):
154 """Return a modified parse tree for the given suite text."""
155 # Hack for handling non-native line endings on non-DOS like OSs.
156 text = string.replace(text, '\x0d', '')
157 return self.transform(parser.suite(text))
158
159 def parseexpr(self, text):
160 """Return a modified parse tree for the given expression text."""
161 return self.transform(parser.expr(text))
162
163 def parsefile(self, file):
164 """Return a modified parse tree for the contents of the given file."""
165 if type(file) == type(''):
166 file = open(file)
167 return self.parsesuite(file.read())
168
169 # --------------------------------------------------------------
170 #
171 # PRIVATE METHODS
172 #
173
174 def compile_node(self, node):
175 ### emit a line-number node?
176 n = node[0]
177 if n == symbol.single_input:
178 return self.single_input(node[1:])
179 if n == symbol.file_input:
180 return self.file_input(node[1:])
181 if n == symbol.eval_input:
182 return self.eval_input(node[1:])
183 if n == symbol.lambdef:
184 return self.lambdef(node[1:])
185 if n == symbol.funcdef:
186 return self.funcdef(node[1:])
187 if n == symbol.classdef:
188 return self.classdef(node[1:])
189
190 raise error, ('unexpected node type', n)
191
192 def single_input(self, node):
193 ### do we want to do anything about being "interactive" ?
194
195 # NEWLINE | simple_stmt | compound_stmt NEWLINE
196 n = node[0][0]
197 if n != token.NEWLINE:
198 return self.com_stmt(node[0])
199
200 return Node('pass')
201
202 def file_input(self, nodelist):
203 doc = self.get_docstring(nodelist, symbol.file_input)
204 stmts = [ ]
205 for node in nodelist:
206 if node[0] != token.ENDMARKER and node[0] != token.NEWLINE:
207 self.com_append_stmt(stmts, node)
208 return Node('module', doc, Node('stmt', stmts))
209
210 def eval_input(self, nodelist):
211 # from the built-in function input()
212 ### is this sufficient?
213 return self.com_node(nodelist[0])
214
215 def funcdef(self, nodelist):
216 # funcdef: 'def' NAME parameters ':' suite
217 # parameters: '(' [varargslist] ')'
218
219 lineno = nodelist[1][2]
220 name = nodelist[1][1]
221 args = nodelist[2][2]
222
223 if args[0] == symbol.varargslist:
224 names, defaults, flags = self.com_arglist(args[1:])
225 else:
226 names = defaults = ()
227 flags = 0
228 doc = self.get_docstring(nodelist[4])
229
230 # code for function
231 code = self.com_node(nodelist[4])
232
233 n = Node('function', name, names, defaults, flags, doc, code)
234 n.lineno = lineno
235 return n
236
237 def lambdef(self, nodelist):
238 # lambdef: 'lambda' [varargslist] ':' test
239 if nodelist[2][0] == symbol.varargslist:
240 names, defaults, flags = self.com_arglist(nodelist[2][1:])
241 else:
242 names = defaults = ()
243 flags = 0
244
245 # code for lambda
246 code = self.com_node(nodelist[-1])
247
248 n = Node('lambda', names, defaults, flags, code)
249 n.lineno = nodelist[1][2]
250 return n
251
252 def classdef(self, nodelist):
253 # classdef: 'class' NAME ['(' testlist ')'] ':' suite
254
255 name = nodelist[1][1]
256 doc = self.get_docstring(nodelist[-1])
257 if nodelist[2][0] == token.COLON:
258 bases = []
259 else:
260 bases = self.com_bases(nodelist[3])
261
262 # code for class
263 code = self.com_node(nodelist[-1])
264
265 n = Node('classdef', name, bases, doc, code)
266 n.lineno = nodelist[1][2]
267 return n
268
269 def stmt(self, nodelist):
270 return self.com_stmt(nodelist[0])
271
272 small_stmt = stmt
273 flow_stmt = stmt
274 compound_stmt = stmt
275
276 def simple_stmt(self, nodelist):
277 # small_stmt (';' small_stmt)* [';'] NEWLINE
278 stmts = [ ]
279 for i in range(0, len(nodelist), 2):
280 self.com_append_stmt(stmts, nodelist[i])
281 return Node('stmt', stmts)
282
283 def parameters(self, nodelist):
284 raise error
285
286 def varargslist(self, nodelist):
287 raise error
288
289 def fpdef(self, nodelist):
290 raise error
291
292 def fplist(self, nodelist):
293 raise error
294
295 def dotted_name(self, nodelist):
296 raise error
297
298 def comp_op(self, nodelist):
299 raise error
300
301 def trailer(self, nodelist):
302 raise error
303
304 def sliceop(self, nodelist):
305 raise error
306
307 def argument(self, nodelist):
308 raise error
309
310 # --------------------------------------------------------------
311 #
312 # STATEMENT NODES (invoked by com_node())
313 #
314
315 def expr_stmt(self, nodelist):
316 # testlist ('=' testlist)*
317 exprNode = self.com_node(nodelist[-1])
318 if len(nodelist) == 1:
319 return Node('discard', exprNode)
320 nodes = [ ]
321 for i in range(0, len(nodelist) - 2, 2):
322 nodes.append(self.com_assign(nodelist[i], OP_ASSIGN))
323 n = Node('assign', nodes, exprNode)
324 n.lineno = nodelist[1][2]
325 return n
326
327 def print_stmt(self, nodelist):
328 # print: (test ',')* [test]
329 items = [ ]
330 for i in range(1, len(nodelist), 2):
331 items.append(self.com_node(nodelist[i]))
332 if nodelist[-1][0] == token.COMMA:
333 n = Node('print', items)
334 n.lineno = nodelist[0][2]
335 return n
336 n = Node('printnl', items)
337 n.lineno = nodelist[0][2]
338 return n
339
340 def del_stmt(self, nodelist):
341 return self.com_assign(nodelist[1], OP_DELETE)
342
343 def pass_stmt(self, nodelist):
344 # pass:
345 n = Node('pass')
346 n.lineno = nodelist[0][2]
347 return n
348
349 def break_stmt(self, nodelist):
350 # break:
351 n = Node('break')
352 n.lineno = nodelist[0][2]
353 return n
354
355 def continue_stmt(self, nodelist):
356 # continue
357 n = Node('continue')
358 n.lineno = nodelist[0][2]
359 return n
360
361 def return_stmt(self, nodelist):
362 # return: [testlist]
363 if len(nodelist) < 2:
364 n = Node('return', Node('const', None))
365 n.lineno = nodelist[0][2]
366 return n
367 n = Node('return', self.com_node(nodelist[1]))
368 n.lineno = nodelist[0][2]
369 return n
370
371 def raise_stmt(self, nodelist):
372 # raise: [test [',' test [',' test]]]
373 if len(nodelist) > 5:
374 expr3 = self.com_node(nodelist[5])
375 else:
376 expr3 = None
377 if len(nodelist) > 3:
378 expr2 = self.com_node(nodelist[3])
379 else:
380 expr2 = None
381 if len(nodelist) > 1:
382 expr1 = self.com_node(nodelist[1])
383 else:
384 expr1 = None
385 n = Node('raise', expr1, expr2, expr3)
386 n.lineno = nodelist[0][2]
387 return n
388
389 def import_stmt(self, nodelist):
390 # import: dotted_name (',' dotted_name)* |
391 # from: dotted_name 'import' ('*' | NAME (',' NAME)*)
392 names = [ ]
393 if nodelist[0][1][0] == 'f':
394 for i in range(3, len(nodelist), 2):
395 # note: nodelist[i] could be (token.STAR, '*') or (token.NAME, name)
396 names.append(nodelist[i][1])
397 n = Node('from', self.com_dotted_name(nodelist[1]), names)
398 n.lineno = nodelist[0][2]
399 return n
400
401 for i in range(1, len(nodelist), 2):
402 names.append(self.com_dotted_name(nodelist[i]))
403 n = Node('import', names)
404 n.lineno = nodelist[0][2]
405 return n
406
407 def global_stmt(self, nodelist):
408 # global: NAME (',' NAME)*
409 names = [ ]
410 for i in range(1, len(nodelist), 2):
411 names.append(nodelist[i][1])
412 n = Node('global', names)
413 n.lineno = nodelist[0][2]
414 return n
415
416 def exec_stmt(self, nodelist):
417 # exec_stmt: 'exec' expr ['in' expr [',' expr]]
418 expr1 = self.com_node(nodelist[1])
419 if len(nodelist) >= 4:
420 expr2 = self.com_node(nodelist[3])
421 if len(nodelist) >= 6:
422 expr3 = self.com_node(nodelist[5])
423 else:
424 expr3 = None
425 else:
426 expr2 = expr3 = None
427
428 n = Node('exec', expr1, expr2, expr3)
429 n.lineno = nodelist[0][2]
430 return n
431
432 def assert_stmt(self, nodelist):
433 # 'assert': test, [',' test]
434 expr1 = self.com_node(nodelist[1])
435 if (len(nodelist) == 4):
436 expr2 = self.com_node(nodelist[3])
437 else:
438 expr2 = Node('name', 'None')
439 n = Node('assert', expr1, expr2)
440 n.lineno = nodelist[0][2]
441 return n
442
443 def if_stmt(self, nodelist):
444 # if: test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
445 tests = [ ]
446 for i in range(0, len(nodelist) - 3, 4):
447 testNode = self.com_node(nodelist[i + 1])
448 suiteNode = self.com_node(nodelist[i + 3])
449 tests.append((testNode, suiteNode))
450
451 if len(nodelist) % 4 == 3:
452 elseNode = self.com_node(nodelist[-1])
453## elseNode.lineno = nodelist[-1][1][2]
454 else:
455 elseNode = None
456 n = Node('if', tests, elseNode)
457 n.lineno = nodelist[0][2]
458 return n
459
460 def while_stmt(self, nodelist):
461 # 'while' test ':' suite ['else' ':' suite]
462
463 testNode = self.com_node(nodelist[1])
464 bodyNode = self.com_node(nodelist[3])
465
466 if len(nodelist) > 4:
467 elseNode = self.com_node(nodelist[6])
468 else:
469 elseNode = None
470
471 n = Node('while', testNode, bodyNode, elseNode)
472 n.lineno = nodelist[0][2]
473 return n
474
475 def for_stmt(self, nodelist):
476 # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
477
478 assignNode = self.com_assign(nodelist[1], OP_ASSIGN)
479 listNode = self.com_node(nodelist[3])
480 bodyNode = self.com_node(nodelist[5])
481
482 if len(nodelist) > 8:
483 elseNode = self.com_node(nodelist[8])
484 else:
485 elseNode = None
486
487 n = Node('for', assignNode, listNode, bodyNode, elseNode)
488 n.lineno = nodelist[0][2]
489 return n
490
491 def try_stmt(self, nodelist):
492 # 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
493 # | 'try' ':' suite 'finally' ':' suite
494 if nodelist[3][0] != symbol.except_clause:
495 return self.com_try_finally(nodelist)
496
497 return self.com_try_except(nodelist)
498
499 def suite(self, nodelist):
500 # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
501 if len(nodelist) == 1:
502 return self.com_stmt(nodelist[0])
503
504 stmts = [ ]
505 for node in nodelist:
506 if node[0] == symbol.stmt:
507 self.com_append_stmt(stmts, node)
508 return Node('stmt', stmts)
509
510 # --------------------------------------------------------------
511 #
512 # EXPRESSION NODES (invoked by com_node())
513 #
514
515 def testlist(self, nodelist):
516 # testlist: expr (',' expr)* [',']
517 # exprlist: expr (',' expr)* [',']
518 return self.com_binary('tuple', nodelist)
519
520 exprlist = testlist
521
522 def test(self, nodelist):
523 # and_test ('or' and_test)* | lambdef
524 if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef:
525 return self.lambdef(nodelist[0])
526 return self.com_binary('or', nodelist)
527
528 def and_test(self, nodelist):
529 # not_test ('and' not_test)*
530 return self.com_binary('and', nodelist)
531
532 def not_test(self, nodelist):
533 # 'not' not_test | comparison
534 result = self.com_node(nodelist[-1])
535 if len(nodelist) == 2:
536 n = Node('not', result)
537 n.lineno = nodelist[0][2]
538 return n
539 return result
540
541 def comparison(self, nodelist):
542 # comparison: expr (comp_op expr)*
543 node = self.com_node(nodelist[0])
544 if len(nodelist) == 1:
545 return node
546
547 results = [ ]
548 for i in range(2, len(nodelist), 2):
549 nl = nodelist[i-1]
550
551 # comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
552 # | 'in' | 'not' 'in' | 'is' | 'is' 'not'
553 n = nl[1]
554 if n[0] == token.NAME:
555 type = n[1]
556 if len(nl) == 3:
557 if type == 'not':
558 type = 'notin'
559 else:
560 type = 'isnot'
561 else:
562 type = _cmp_types[n[0]]
563
564 lineno = nl[1][2]
565 results.append(type, self.com_node(nodelist[i]))
566
567 # we need a special "compare" node so that we can distinguish
568 # 3 < x < 5 from (3 < x) < 5
569 # the two have very different semantics and results (note that the
570 # latter form is always true)
571
572 n = Node('compare', node, results)
573 n.lineno = lineno
574 return n
575
576 def expr(self, nodelist):
577 # xor_expr ('|' xor_expr)*
578 return self.com_binary('bitor', nodelist)
579
580 def xor_expr(self, nodelist):
581 # xor_expr ('^' xor_expr)*
582 return self.com_binary('bitxor', nodelist)
583
584 def and_expr(self, nodelist):
585 # xor_expr ('&' xor_expr)*
586 return self.com_binary('bitand', nodelist)
587
588 def shift_expr(self, nodelist):
589 # shift_expr ('<<'|'>>' shift_expr)*
590 node = self.com_node(nodelist[0])
591 for i in range(2, len(nodelist), 2):
592 right = self.com_node(nodelist[i])
593 if nodelist[i-1][0] == token.LEFTSHIFT:
594 node = Node('<<', [node, right])
595 node.lineno = nodelist[1][2]
596 else:
597 node = Node('>>', [node, right])
598 node.lineno = nodelist[1][2]
599 return node
600
601 def arith_expr(self, nodelist):
602 node = self.com_node(nodelist[0])
603 for i in range(2, len(nodelist), 2):
604 right = self.com_node(nodelist[i])
605 if nodelist[i-1][0] == token.PLUS:
606 node = Node('+', [node, right])
607 node.lineno = nodelist[1][2]
608 else:
609 node = Node('-', [node, right])
610 node.lineno = nodelist[1][2]
611 return node
612
613 def term(self, nodelist):
614 node = self.com_node(nodelist[0])
615 for i in range(2, len(nodelist), 2):
616 right = self.com_node(nodelist[i])
617 if nodelist[i-1][0] == token.STAR:
618 node = Node('*', [node, right])
619 node.lineno = nodelist[1][2]
620 elif nodelist[i-1][0] == token.SLASH:
621 node = Node('/', [node, right])
622 node.lineno = nodelist[1][2]
623 else:
624 node = Node('%', [node, right])
625 node.lineno = nodelist[1][2]
626 return node
627
628 def factor(self, nodelist):
629 t = nodelist[0][0]
630 node = self.com_node(nodelist[-1])
631 if t == token.PLUS:
632 node = Node('unary+', node)
633 node.lineno = nodelist[0][2]
634 elif t == token.MINUS:
635 node = Node('unary-', node)
636 node.lineno = nodelist[0][2]
637 elif t == token.TILDE:
638 node = Node('invert', node)
639 node.lineno = nodelist[0][2]
640 return node
641
642 def power(self, nodelist):
643 # power: atom trailer* ('**' factor)*
644 node = self.com_node(nodelist[0])
645 for i in range(1, len(nodelist)):
646 if nodelist[i][0] == token.DOUBLESTAR:
647 n = Node('power', [node, self.com_node(nodelist[i+1])])
648 n.lineno = nodelist[i][2]
649 return n
650
651 node = self.com_apply_trailer(node, nodelist[i])
652
653 return node
654
655 def atom(self, nodelist):
656 t = nodelist[0][0]
657 if t == token.LPAR:
658 if nodelist[1][0] == token.RPAR:
659 n = Node('const', ())
660 n.lineno = nodelist[0][2]
661 return n
662 return self.com_node(nodelist[1])
663
664 if t == token.LSQB:
665 if nodelist[1][0] == token.RSQB:
666 n = Node('const', [ ])
667 n.lineno = nodelist[0][2]
668 return n
669 return self.com_list_constructor(nodelist[1])
670
671 if t == token.LBRACE:
672 if nodelist[1][0] == token.RBRACE:
673 return Node('const', { })
674 return self.com_dictmaker(nodelist[1])
675
676 if t == token.BACKQUOTE:
677 n = Node('backquote', self.com_node(nodelist[1]))
678 n.lineno = nodelist[0][2]
679 return n
680
681 if t == token.NUMBER:
682 ### need to verify this matches compile.c
683 k = eval(nodelist[0][1])
684 n = Node('const', k)
685 n.lineno = nodelist[0][2]
686 return n
687
688 if t == token.STRING:
689 ### need to verify this matches compile.c
690 k = ''
691 for node in nodelist:
692 k = k + eval(node[1])
693 n = Node('const', k)
694 n.lineno = nodelist[0][2]
695 return n
696
697 if t == token.NAME:
698 ### any processing to do?
699 n = Node('name', nodelist[0][1])
700 n.lineno = nodelist[0][2]
701 return n
702
703 raise error, "unknown node type"
704
705 # --------------------------------------------------------------
706 #
707 # INTERNAL PARSING UTILITIES
708 #
709
710 def com_node(self, node):
711 # Note: compile.c has handling in com_node for del_stmt, pass_stmt,
712 # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt,
713 # and compound_stmt.
714 # We'll just dispatch them.
715
716 #
717 # A ';' at the end of a line can make a NEWLINE token appear here,
718 # Render it harmless. (genc discards ('discard', ('const', xxxx)) Nodes)
719 #
720 if node[0] == token.NEWLINE:
721 return Node('discard', Node('const', None))
722
723 if node[0] not in _legal_node_types:
724 raise error, 'illegal node passed to com_node: %s' % node[0]
725
726 return self._dispatch[node[0]](node[1:])
727
728 def com_arglist(self, nodelist):
729 # varargslist:
730 # (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME]
731 # | fpdef ['=' test] (',' fpdef ['=' test])* [',']
732 # | ('**'|'*' '*') NAME)
733 # fpdef: NAME | '(' fplist ')'
734 # fplist: fpdef (',' fpdef)* [',']
735 names = [ ]
736 defaults = [ ]
737 flags = 0
738
739 i = 0
740 while i < len(nodelist):
741 node = nodelist[i]
742 if node[0] == token.STAR or node[0] == token.DOUBLESTAR:
743 if node[0] == token.STAR:
744 node = nodelist[i+1]
745 if node[0] == token.NAME:
746 names.append(node[1])
747 flags = flags | CO_VARARGS
748 i = i + 3
749
750 if i < len(nodelist):
751 # should be DOUBLESTAR or STAR STAR
752 if nodelist[i][0] == token.DOUBLESTAR:
753 node = nodelist[i+1]
754 else:
755 node = nodelist[i+2]
756 names.append(node[1])
757 flags = flags | CO_VARKEYWORDS
758
759 break
760
761 # fpdef: NAME | '(' fplist ')'
762 names.append(self.com_fpdef(node))
763
764 i = i + 1
765 if i >= len(nodelist):
766 break
767
768 if nodelist[i][0] == token.EQUAL:
769 defaults.append(self.com_node(nodelist[i + 1]))
770 i = i + 2
771 elif len(defaults):
772 # Treat "(a=1, b)" as "(a=1, b=None)"
773 defaults.append(Node('const', None))
774
775 i = i + 1
776
777 return names, defaults, flags
778
779 def com_fpdef(self, node):
780 # fpdef: NAME | '(' fplist ')'
781 if node[1][0] == token.LPAR:
782 return self.com_fplist(node[2])
783 return node[1][1]
784
785 def com_fplist(self, node):
786 # fplist: fpdef (',' fpdef)* [',']
787 if len(node) == 2:
788 return self.com_fpdef(node[1])
789 list = [ ]
790 for i in range(1, len(node), 2):
791 list.append(self.com_fpdef(node[i]))
792 return tuple(list)
793
794 def com_dotted_name(self, node):
795 # String together the dotted names and return the string
796 name = ""
797 for n in node:
798 if type(n) == type(()) and n[0] == 1:
799 name = name + n[1] + '.'
800 return name[:-1]
801
802 def com_bases(self, node):
803 bases = [ ]
804 for i in range(1, len(node), 2):
805 bases.append(self.com_node(node[i]))
806 return bases
807
808 def com_try_finally(self, nodelist):
809 # try_fin_stmt: "try" ":" suite "finally" ":" suite
810 n = Node('tryfinally', self.com_node(nodelist[2]), self.com_node(nodelist[5]))
811 n.lineno = nodelist[0][2]
812 return n
813
814 def com_try_except(self, nodelist):
815 # try_except: 'try' ':' suite (except_clause ':' suite)* ['else' suite]
816 #tryexcept: [TryNode, [except_clauses], elseNode)]
817 stmt = self.com_node(nodelist[2])
818 clauses = []
819 elseNode = None
820 for i in range(3, len(nodelist), 3):
821 node = nodelist[i]
822 if node[0] == symbol.except_clause:
823 # except_clause: 'except' [expr [',' expr]] */
824 if len(node) > 2:
825 expr1 = self.com_node(node[2])
826 if len(node) > 4:
827 expr2 = self.com_assign(node[4], OP_ASSIGN)
828 else:
829 expr2 = None
830 else:
831 expr1 = expr2 = None
832 clauses.append(expr1, expr2, self.com_node(nodelist[i+2]))
833
834 if node[0] == token.NAME:
835 elseNode = self.com_node(nodelist[i+2])
836 n = Node('tryexcept', self.com_node(nodelist[2]), clauses, elseNode)
837 n.lineno = nodelist[0][2]
838 return n
839
840 def com_assign(self, node, assigning):
841 # return a node suitable for use as an "lvalue"
842 # loop to avoid trivial recursion
843 while 1:
844 t = node[0]
845 if t == symbol.exprlist or t == symbol.testlist:
846 if len(node) > 2:
847 return self.com_assign_tuple(node, assigning)
848 node = node[1]
849 elif t in _assign_types:
850 if len(node) > 2:
851 raise SyntaxError, "can't assign to operator"
852 node = node[1]
853 elif t == symbol.power:
854 if node[1][0] != symbol.atom:
855 raise SyntaxError, "can't assign to operator"
856 if len(node) > 2:
857 primary = self.com_node(node[1])
858 for i in range(2, len(node)-1):
859 ch = node[i]
860 if ch[0] == token.DOUBLESTAR:
861 raise SyntaxError, "can't assign to operator"
862 primary = self.com_apply_trailer(primary, ch)
863 return self.com_assign_trailer(primary, node[-1], assigning)
864 node = node[1]
865 elif t == symbol.atom:
866 t = node[1][0]
867 if t == token.LPAR:
868 node = node[2]
869 if node[0] == token.RPAR:
870 raise SyntaxError, "can't assign to ()"
871 elif t == token.LSQB:
872 node = node[2]
873 if node[0] == token.RSQB:
874 raise SyntaxError, "can't assign to []"
875 return self.com_assign_list(node, assigning)
876 elif t == token.NAME:
877 return self.com_assign_name(node[1], assigning)
878 else:
879 raise SyntaxError, "can't assign to literal"
880 else:
881 raise SyntaxError, "bad assignment"
882
883 def com_assign_tuple(self, node, assigning):
884 assigns = [ ]
885 for i in range(1, len(node), 2):
886 assigns.append(self.com_assign(node[i], assigning))
887 return Node('ass_tuple', assigns)
888
889 def com_assign_list(self, node, assigning):
890 assigns = [ ]
891 for i in range(1, len(node), 2):
892 assigns.append(self.com_assign(node[i], assigning))
893 return Node('ass_list', assigns)
894
895 def com_assign_name(self, node, assigning):
896 return Node('ass_name', node[1], assigning)
897
898 def com_assign_trailer(self, primary, node, assigning):
899 t = node[1][0]
900 if t == token.LPAR:
901 raise SyntaxError, "can't assign to function call"
902 if t == token.DOT:
903 return self.com_assign_attr(primary, node[2], assigning)
904 if t == token.LSQB:
905 return self.com_subscriptlist(primary, node[2], assigning)
906 raise SyntaxError, "unknown trailer type: %s" % t
907
908 def com_assign_attr(self, primary, node, assigning):
909 return Node('ass_attr', primary, node[1], assigning)
910
911 def com_binary(self, type, nodelist):
912 "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])."
913 if len(nodelist) == 1:
914 return self.com_node(nodelist[0])
915 items = [ ]
916 for i in range(0, len(nodelist), 2):
917 items.append(self.com_node(nodelist[i]))
918 return Node(type, items)
919
920 def com_stmt(self, node):
921 #pprint.pprint(node)
922 result = self.com_node(node)
923 try:
924 result[0]
925 except:
926 print node[0]
927 if result[0] == 'stmt':
928 return result
929 return Node('stmt', [ result ])
930
931 def com_append_stmt(self, stmts, node):
932 result = self.com_node(node)
933 try:
934 result[0]
935 except:
936 print node
937 if result[0] == 'stmt':
938 stmts[len(stmts):] = result[1]
939 else:
940 stmts.append(result)
941
942 def com_list_constructor(self, nodelist):
943 values = [ ]
944 for i in range(1, len(nodelist), 2):
945 values.append(self.com_node(nodelist[i]))
946 return Node('list', values)
947
948 def com_dictmaker(self, nodelist):
949 # dictmaker: test ':' test (',' test ':' value)* [',']
950 items = [ ]
951 for i in range(1, len(nodelist), 4):
952 items.append(self.com_node(nodelist[i]), self.com_node(nodelist[i+2]))
953 return Node('dict', items)
954
955 def com_apply_trailer(self, primaryNode, nodelist):
956 t = nodelist[1][0]
957 if t == token.LPAR:
958 return self.com_call_function(primaryNode, nodelist[2])
959 if t == token.DOT:
960 return self.com_select_member(primaryNode, nodelist[2])
961 if t == token.LSQB:
962 return self.com_subscriptlist(primaryNode, nodelist[2], OP_APPLY)
963
964 raise SyntaxError, 'unknown node type: %s' % t
965
966 def com_select_member(self, primaryNode, nodelist):
967 if nodelist[0] != token.NAME:
968 raise SyntaxError, "member must be a name"
969 n = Node('getattr', primaryNode, nodelist[1])
970 n.lineno = nodelist[2]
971 return n
972
973 def com_call_function(self, primaryNode, nodelist):
974 if nodelist[0] == token.RPAR:
975 return Node('call_func', primaryNode, [ ])
976 args = [ ]
977 kw = 0
978 for i in range(1, len(nodelist), 2):
979 kw, result = self.com_argument(nodelist[i], kw)
980 args.append(result)
981 return Node('call_func', primaryNode, args)
982
983 def com_argument(self, nodelist, kw):
984 if len(nodelist) == 2:
985 if kw:
986 raise SyntaxError, "non-keyword arg after keyword arg"
987 return 0, self.com_node(nodelist[1])
988 result = self.com_node(nodelist[3])
989 n = nodelist[1]
990 while len(n) == 2 and n[0] != token.NAME:
991 n = n[1]
992 if n[0] != token.NAME:
993 raise SyntaxError, "keyword can't be an expression (%s)"%n[0]
994 n = Node('keyword', n[1], result)
995 n.lineno = result.lineno
996 return 1, n
997
998 def com_subscriptlist(self, primary, nodelist, assigning):
999 # slicing: simple_slicing | extended_slicing
1000 # simple_slicing: primary "[" short_slice "]"
1001 # extended_slicing: primary "[" slice_list "]"
1002 # slice_list: slice_item ("," slice_item)* [","]
1003
1004 # backwards compat slice for '[i:j]'
1005 if len(nodelist) == 2:
1006 sub = nodelist[1]
1007 if (sub[1][0] == token.COLON or \
1008 (len(sub) > 2 and sub[2][0] == token.COLON)) and \
1009 sub[-1][0] != symbol.sliceop:
1010 return self.com_slice(primary, sub, assigning)
1011
1012 subscripts = [ ]
1013 for i in range(1, len(nodelist), 2):
1014 subscripts.append(self.com_subscript(nodelist[i]))
1015
1016 return Node('subscript', primary, assigning, subscripts)
1017
1018 def com_subscript(self, node):
1019 # slice_item: expression | proper_slice | ellipsis
1020 ch = node[1]
1021 if ch[0] == token.DOT and node[2][0] == token.DOT:
1022 return ('ellipsis', None)
1023 if ch[0] == token.COLON or len(node) > 2:
1024 return self.com_sliceobj(node)
1025 return self.com_node(ch)
1026
1027 def com_sliceobj(self, node):
1028 # proper_slice: short_slice | long_slice
1029 # short_slice: [lower_bound] ":" [upper_bound]
1030 # long_slice: short_slice ":" [stride]
1031 # lower_bound: expression
1032 # upper_bound: expression
1033 # stride: expression
1034 #
1035 # Note: a stride may be further slicing...
1036
1037 items = [ ]
1038
1039 if node[1][0] == token.COLON:
1040 items.append(Node('const', None))
1041 i = 2
1042 else:
1043 items.append(self.com_node(node[1]))
1044 # i == 2 is a COLON
1045 i = 3
1046
1047 if i < len(node) and node[i][0] == symbol.test:
1048 items.append(self.com_node(node[i]))
1049 i = i + 1
1050 else:
1051 items.append(Node('const', None))
1052
1053 # a short_slice has been built. look for long_slice now by looking
1054 # for strides...
1055 for j in range(i, len(node)):
1056 ch = node[j]
1057 if len(ch) == 2:
1058 items.append(Node('const', None))
1059 else:
1060 items.append(self.com_node(ch[2]))
1061
1062 return Node('sliceobj', items)
1063
1064 def com_slice(self, primary, node, assigning):
1065 # short_slice: [lower_bound] ":" [upper_bound]
1066 lower = upper = None
1067 if len(node) == 3:
1068 if node[1][0] == token.COLON:
1069 upper = self.com_node(node[2])
1070 else:
1071 lower = self.com_node(node[1])
1072 elif len(node) == 4:
1073 lower = self.com_node(node[1])
1074 upper = self.com_node(node[3])
1075 return Node('slice', primary, assigning, lower, upper)
1076
1077 def get_docstring(self, node, n=None):
1078 if n is None:
1079 n = node[0]
1080 node = node[1:]
1081 if n == symbol.suite:
1082 if len(node) == 1:
1083 return self.get_docstring(node[0])
1084 for sub in node:
1085 if sub[0] == symbol.stmt:
1086 return self.get_docstring(sub)
1087 return None
1088 if n == symbol.file_input:
1089 for sub in node:
1090 if sub[0] == symbol.stmt:
1091 return self.get_docstring(sub)
1092 return None
1093 if n == symbol.atom:
1094 if node[0][0] == token.STRING:
1095 s = ''
1096 for t in node:
1097 s = s + eval(t[1])
1098 return s
1099 return None
1100 if n == symbol.stmt or n == symbol.simple_stmt or n == symbol.small_stmt:
1101 return self.get_docstring(node[0])
1102 if n in _doc_nodes and len(node) == 1:
1103 return self.get_docstring(node[0])
1104 return None
1105
1106
1107_doc_nodes = [
1108 symbol.expr_stmt,
1109 symbol.testlist,
1110 symbol.test,
1111 symbol.and_test,
1112 symbol.not_test,
1113 symbol.comparison,
1114 symbol.expr,
1115 symbol.xor_expr,
1116 symbol.and_expr,
1117 symbol.shift_expr,
1118 symbol.arith_expr,
1119 symbol.term,
1120 symbol.factor,
1121 symbol.power,
1122 ]
1123
1124# comp_op: '<' | '>' | '=' | '>=' | '<=' | '<>' | '!=' | '=='
1125# | 'in' | 'not' 'in' | 'is' | 'is' 'not'
1126_cmp_types = {
1127 token.LESS : '<',
1128 token.GREATER : '>',
1129 token.EQEQUAL : '==',
1130 token.EQUAL : '==',
1131 token.LESSEQUAL : '<=',
1132 token.GREATEREQUAL : '>=',
1133 token.NOTEQUAL : '!=',
1134 }
1135
1136_legal_node_types = [
1137 symbol.funcdef,
1138 symbol.classdef,
1139 symbol.stmt,
1140 symbol.small_stmt,
1141 symbol.flow_stmt,
1142 symbol.simple_stmt,
1143 symbol.compound_stmt,
1144 symbol.expr_stmt,
1145 symbol.print_stmt,
1146 symbol.del_stmt,
1147 symbol.pass_stmt,
1148 symbol.break_stmt,
1149 symbol.continue_stmt,
1150 symbol.return_stmt,
1151 symbol.raise_stmt,
1152 symbol.import_stmt,
1153 symbol.global_stmt,
1154 symbol.exec_stmt,
1155 symbol.assert_stmt,
1156 symbol.if_stmt,
1157 symbol.while_stmt,
1158 symbol.for_stmt,
1159 symbol.try_stmt,
1160 symbol.suite,
1161 symbol.testlist,
1162 symbol.test,
1163 symbol.and_test,
1164 symbol.not_test,
1165 symbol.comparison,
1166 symbol.exprlist,
1167 symbol.expr,
1168 symbol.xor_expr,
1169 symbol.and_expr,
1170 symbol.shift_expr,
1171 symbol.arith_expr,
1172 symbol.term,
1173 symbol.factor,
1174 symbol.power,
1175 symbol.atom,
1176 ]
1177
1178_assign_types = [
1179 symbol.test,
1180 symbol.and_test,
1181 symbol.not_test,
1182 symbol.comparison,
1183 symbol.expr,
1184 symbol.xor_expr,
1185 symbol.and_expr,
1186 symbol.shift_expr,
1187 symbol.arith_expr,
1188 symbol.term,
1189 symbol.factor,
1190 ]
1191
1192# Local Variables:
1193# mode: python
1194# indent-tabs-mode: nil
1195# py-indent-offset: 2
1196# py-smart-indentation: nil
1197# End:
1198