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