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