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