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