|
1 import imp |
|
2 import os |
|
3 import marshal |
|
4 import struct |
|
5 import sys |
|
6 from cStringIO import StringIO |
|
7 |
|
8 from compiler import ast, parse, walk, syntax |
|
9 from compiler import pyassem, misc, future, symbols |
|
10 from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL |
|
11 from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, |
|
12 CO_NESTED, CO_GENERATOR, CO_FUTURE_DIVISION, |
|
13 CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT) |
|
14 from compiler.pyassem import TupleArg |
|
15 |
|
16 # XXX The version-specific code can go, since this code only works with 2.x. |
|
17 # Do we have Python 1.x or Python 2.x? |
|
18 try: |
|
19 VERSION = sys.version_info[0] |
|
20 except AttributeError: |
|
21 VERSION = 1 |
|
22 |
|
23 callfunc_opcode_info = { |
|
24 # (Have *args, Have **args) : opcode |
|
25 (0,0) : "CALL_FUNCTION", |
|
26 (1,0) : "CALL_FUNCTION_VAR", |
|
27 (0,1) : "CALL_FUNCTION_KW", |
|
28 (1,1) : "CALL_FUNCTION_VAR_KW", |
|
29 } |
|
30 |
|
31 LOOP = 1 |
|
32 EXCEPT = 2 |
|
33 TRY_FINALLY = 3 |
|
34 END_FINALLY = 4 |
|
35 |
|
36 def compileFile(filename, display=0): |
|
37 f = open(filename, 'U') |
|
38 buf = f.read() |
|
39 f.close() |
|
40 mod = Module(buf, filename) |
|
41 try: |
|
42 mod.compile(display) |
|
43 except SyntaxError: |
|
44 raise |
|
45 else: |
|
46 f = open(filename + "c", "wb") |
|
47 mod.dump(f) |
|
48 f.close() |
|
49 |
|
50 def compile(source, filename, mode, flags=None, dont_inherit=None): |
|
51 """Replacement for builtin compile() function""" |
|
52 if flags is not None or dont_inherit is not None: |
|
53 raise RuntimeError, "not implemented yet" |
|
54 |
|
55 if mode == "single": |
|
56 gen = Interactive(source, filename) |
|
57 elif mode == "exec": |
|
58 gen = Module(source, filename) |
|
59 elif mode == "eval": |
|
60 gen = Expression(source, filename) |
|
61 else: |
|
62 raise ValueError("compile() 3rd arg must be 'exec' or " |
|
63 "'eval' or 'single'") |
|
64 gen.compile() |
|
65 return gen.code |
|
66 |
|
67 class AbstractCompileMode: |
|
68 |
|
69 mode = None # defined by subclass |
|
70 |
|
71 def __init__(self, source, filename): |
|
72 self.source = source |
|
73 self.filename = filename |
|
74 self.code = None |
|
75 |
|
76 def _get_tree(self): |
|
77 tree = parse(self.source, self.mode) |
|
78 misc.set_filename(self.filename, tree) |
|
79 syntax.check(tree) |
|
80 return tree |
|
81 |
|
82 def compile(self): |
|
83 pass # implemented by subclass |
|
84 |
|
85 def getCode(self): |
|
86 return self.code |
|
87 |
|
88 class Expression(AbstractCompileMode): |
|
89 |
|
90 mode = "eval" |
|
91 |
|
92 def compile(self): |
|
93 tree = self._get_tree() |
|
94 gen = ExpressionCodeGenerator(tree) |
|
95 self.code = gen.getCode() |
|
96 |
|
97 class Interactive(AbstractCompileMode): |
|
98 |
|
99 mode = "single" |
|
100 |
|
101 def compile(self): |
|
102 tree = self._get_tree() |
|
103 gen = InteractiveCodeGenerator(tree) |
|
104 self.code = gen.getCode() |
|
105 |
|
106 class Module(AbstractCompileMode): |
|
107 |
|
108 mode = "exec" |
|
109 |
|
110 def compile(self, display=0): |
|
111 tree = self._get_tree() |
|
112 gen = ModuleCodeGenerator(tree) |
|
113 if display: |
|
114 import pprint |
|
115 print pprint.pprint(tree) |
|
116 self.code = gen.getCode() |
|
117 |
|
118 def dump(self, f): |
|
119 f.write(self.getPycHeader()) |
|
120 marshal.dump(self.code, f) |
|
121 |
|
122 MAGIC = imp.get_magic() |
|
123 |
|
124 def getPycHeader(self): |
|
125 # compile.c uses marshal to write a long directly, with |
|
126 # calling the interface that would also generate a 1-byte code |
|
127 # to indicate the type of the value. simplest way to get the |
|
128 # same effect is to call marshal and then skip the code. |
|
129 mtime = os.path.getmtime(self.filename) |
|
130 mtime = struct.pack('<i', mtime) |
|
131 return self.MAGIC + mtime |
|
132 |
|
133 class LocalNameFinder: |
|
134 """Find local names in scope""" |
|
135 def __init__(self, names=()): |
|
136 self.names = misc.Set() |
|
137 self.globals = misc.Set() |
|
138 for name in names: |
|
139 self.names.add(name) |
|
140 |
|
141 # XXX list comprehensions and for loops |
|
142 |
|
143 def getLocals(self): |
|
144 for elt in self.globals.elements(): |
|
145 if self.names.has_elt(elt): |
|
146 self.names.remove(elt) |
|
147 return self.names |
|
148 |
|
149 def visitDict(self, node): |
|
150 pass |
|
151 |
|
152 def visitGlobal(self, node): |
|
153 for name in node.names: |
|
154 self.globals.add(name) |
|
155 |
|
156 def visitFunction(self, node): |
|
157 self.names.add(node.name) |
|
158 |
|
159 def visitLambda(self, node): |
|
160 pass |
|
161 |
|
162 def visitImport(self, node): |
|
163 for name, alias in node.names: |
|
164 self.names.add(alias or name) |
|
165 |
|
166 def visitFrom(self, node): |
|
167 for name, alias in node.names: |
|
168 self.names.add(alias or name) |
|
169 |
|
170 def visitClass(self, node): |
|
171 self.names.add(node.name) |
|
172 |
|
173 def visitAssName(self, node): |
|
174 self.names.add(node.name) |
|
175 |
|
176 def is_constant_false(node): |
|
177 if isinstance(node, ast.Const): |
|
178 if not node.value: |
|
179 return 1 |
|
180 return 0 |
|
181 |
|
182 class CodeGenerator: |
|
183 """Defines basic code generator for Python bytecode |
|
184 |
|
185 This class is an abstract base class. Concrete subclasses must |
|
186 define an __init__() that defines self.graph and then calls the |
|
187 __init__() defined in this class. |
|
188 |
|
189 The concrete class must also define the class attributes |
|
190 NameFinder, FunctionGen, and ClassGen. These attributes can be |
|
191 defined in the initClass() method, which is a hook for |
|
192 initializing these methods after all the classes have been |
|
193 defined. |
|
194 """ |
|
195 |
|
196 optimized = 0 # is namespace access optimized? |
|
197 __initialized = None |
|
198 class_name = None # provide default for instance variable |
|
199 |
|
200 def __init__(self): |
|
201 if self.__initialized is None: |
|
202 self.initClass() |
|
203 self.__class__.__initialized = 1 |
|
204 self.checkClass() |
|
205 self.locals = misc.Stack() |
|
206 self.setups = misc.Stack() |
|
207 self.last_lineno = None |
|
208 self._setupGraphDelegation() |
|
209 self._div_op = "BINARY_DIVIDE" |
|
210 |
|
211 # XXX set flags based on future features |
|
212 futures = self.get_module().futures |
|
213 for feature in futures: |
|
214 if feature == "division": |
|
215 self.graph.setFlag(CO_FUTURE_DIVISION) |
|
216 self._div_op = "BINARY_TRUE_DIVIDE" |
|
217 elif feature == "absolute_import": |
|
218 self.graph.setFlag(CO_FUTURE_ABSIMPORT) |
|
219 elif feature == "with_statement": |
|
220 self.graph.setFlag(CO_FUTURE_WITH_STATEMENT) |
|
221 |
|
222 def initClass(self): |
|
223 """This method is called once for each class""" |
|
224 |
|
225 def checkClass(self): |
|
226 """Verify that class is constructed correctly""" |
|
227 try: |
|
228 assert hasattr(self, 'graph') |
|
229 assert getattr(self, 'NameFinder') |
|
230 assert getattr(self, 'FunctionGen') |
|
231 assert getattr(self, 'ClassGen') |
|
232 except AssertionError, msg: |
|
233 intro = "Bad class construction for %s" % self.__class__.__name__ |
|
234 raise AssertionError, intro |
|
235 |
|
236 def _setupGraphDelegation(self): |
|
237 self.emit = self.graph.emit |
|
238 self.newBlock = self.graph.newBlock |
|
239 self.startBlock = self.graph.startBlock |
|
240 self.nextBlock = self.graph.nextBlock |
|
241 self.setDocstring = self.graph.setDocstring |
|
242 |
|
243 def getCode(self): |
|
244 """Return a code object""" |
|
245 return self.graph.getCode() |
|
246 |
|
247 def mangle(self, name): |
|
248 if self.class_name is not None: |
|
249 return misc.mangle(name, self.class_name) |
|
250 else: |
|
251 return name |
|
252 |
|
253 def parseSymbols(self, tree): |
|
254 s = symbols.SymbolVisitor() |
|
255 walk(tree, s) |
|
256 return s.scopes |
|
257 |
|
258 def get_module(self): |
|
259 raise RuntimeError, "should be implemented by subclasses" |
|
260 |
|
261 # Next five methods handle name access |
|
262 |
|
263 def isLocalName(self, name): |
|
264 return self.locals.top().has_elt(name) |
|
265 |
|
266 def storeName(self, name): |
|
267 self._nameOp('STORE', name) |
|
268 |
|
269 def loadName(self, name): |
|
270 self._nameOp('LOAD', name) |
|
271 |
|
272 def delName(self, name): |
|
273 self._nameOp('DELETE', name) |
|
274 |
|
275 def _nameOp(self, prefix, name): |
|
276 name = self.mangle(name) |
|
277 scope = self.scope.check_name(name) |
|
278 if scope == SC_LOCAL: |
|
279 if not self.optimized: |
|
280 self.emit(prefix + '_NAME', name) |
|
281 else: |
|
282 self.emit(prefix + '_FAST', name) |
|
283 elif scope == SC_GLOBAL: |
|
284 if not self.optimized: |
|
285 self.emit(prefix + '_NAME', name) |
|
286 else: |
|
287 self.emit(prefix + '_GLOBAL', name) |
|
288 elif scope == SC_FREE or scope == SC_CELL: |
|
289 self.emit(prefix + '_DEREF', name) |
|
290 else: |
|
291 raise RuntimeError, "unsupported scope for var %s: %d" % \ |
|
292 (name, scope) |
|
293 |
|
294 def _implicitNameOp(self, prefix, name): |
|
295 """Emit name ops for names generated implicitly by for loops |
|
296 |
|
297 The interpreter generates names that start with a period or |
|
298 dollar sign. The symbol table ignores these names because |
|
299 they aren't present in the program text. |
|
300 """ |
|
301 if self.optimized: |
|
302 self.emit(prefix + '_FAST', name) |
|
303 else: |
|
304 self.emit(prefix + '_NAME', name) |
|
305 |
|
306 # The set_lineno() function and the explicit emit() calls for |
|
307 # SET_LINENO below are only used to generate the line number table. |
|
308 # As of Python 2.3, the interpreter does not have a SET_LINENO |
|
309 # instruction. pyassem treats SET_LINENO opcodes as a special case. |
|
310 |
|
311 def set_lineno(self, node, force=False): |
|
312 """Emit SET_LINENO if necessary. |
|
313 |
|
314 The instruction is considered necessary if the node has a |
|
315 lineno attribute and it is different than the last lineno |
|
316 emitted. |
|
317 |
|
318 Returns true if SET_LINENO was emitted. |
|
319 |
|
320 There are no rules for when an AST node should have a lineno |
|
321 attribute. The transformer and AST code need to be reviewed |
|
322 and a consistent policy implemented and documented. Until |
|
323 then, this method works around missing line numbers. |
|
324 """ |
|
325 lineno = getattr(node, 'lineno', None) |
|
326 if lineno is not None and (lineno != self.last_lineno |
|
327 or force): |
|
328 self.emit('SET_LINENO', lineno) |
|
329 self.last_lineno = lineno |
|
330 return True |
|
331 return False |
|
332 |
|
333 # The first few visitor methods handle nodes that generator new |
|
334 # code objects. They use class attributes to determine what |
|
335 # specialized code generators to use. |
|
336 |
|
337 NameFinder = LocalNameFinder |
|
338 FunctionGen = None |
|
339 ClassGen = None |
|
340 |
|
341 def visitModule(self, node): |
|
342 self.scopes = self.parseSymbols(node) |
|
343 self.scope = self.scopes[node] |
|
344 self.emit('SET_LINENO', 0) |
|
345 if node.doc: |
|
346 self.emit('LOAD_CONST', node.doc) |
|
347 self.storeName('__doc__') |
|
348 lnf = walk(node.node, self.NameFinder(), verbose=0) |
|
349 self.locals.push(lnf.getLocals()) |
|
350 self.visit(node.node) |
|
351 self.emit('LOAD_CONST', None) |
|
352 self.emit('RETURN_VALUE') |
|
353 |
|
354 def visitExpression(self, node): |
|
355 self.set_lineno(node) |
|
356 self.scopes = self.parseSymbols(node) |
|
357 self.scope = self.scopes[node] |
|
358 self.visit(node.node) |
|
359 self.emit('RETURN_VALUE') |
|
360 |
|
361 def visitFunction(self, node): |
|
362 self._visitFuncOrLambda(node, isLambda=0) |
|
363 if node.doc: |
|
364 self.setDocstring(node.doc) |
|
365 self.storeName(node.name) |
|
366 |
|
367 def visitLambda(self, node): |
|
368 self._visitFuncOrLambda(node, isLambda=1) |
|
369 |
|
370 def _visitFuncOrLambda(self, node, isLambda=0): |
|
371 if not isLambda and node.decorators: |
|
372 for decorator in node.decorators.nodes: |
|
373 self.visit(decorator) |
|
374 ndecorators = len(node.decorators.nodes) |
|
375 else: |
|
376 ndecorators = 0 |
|
377 |
|
378 gen = self.FunctionGen(node, self.scopes, isLambda, |
|
379 self.class_name, self.get_module()) |
|
380 walk(node.code, gen) |
|
381 gen.finish() |
|
382 self.set_lineno(node) |
|
383 for default in node.defaults: |
|
384 self.visit(default) |
|
385 self._makeClosure(gen, len(node.defaults)) |
|
386 for i in range(ndecorators): |
|
387 self.emit('CALL_FUNCTION', 1) |
|
388 |
|
389 def visitClass(self, node): |
|
390 gen = self.ClassGen(node, self.scopes, |
|
391 self.get_module()) |
|
392 walk(node.code, gen) |
|
393 gen.finish() |
|
394 self.set_lineno(node) |
|
395 self.emit('LOAD_CONST', node.name) |
|
396 for base in node.bases: |
|
397 self.visit(base) |
|
398 self.emit('BUILD_TUPLE', len(node.bases)) |
|
399 self._makeClosure(gen, 0) |
|
400 self.emit('CALL_FUNCTION', 0) |
|
401 self.emit('BUILD_CLASS') |
|
402 self.storeName(node.name) |
|
403 |
|
404 # The rest are standard visitor methods |
|
405 |
|
406 # The next few implement control-flow statements |
|
407 |
|
408 def visitIf(self, node): |
|
409 end = self.newBlock() |
|
410 numtests = len(node.tests) |
|
411 for i in range(numtests): |
|
412 test, suite = node.tests[i] |
|
413 if is_constant_false(test): |
|
414 # XXX will need to check generator stuff here |
|
415 continue |
|
416 self.set_lineno(test) |
|
417 self.visit(test) |
|
418 nextTest = self.newBlock() |
|
419 self.emit('JUMP_IF_FALSE', nextTest) |
|
420 self.nextBlock() |
|
421 self.emit('POP_TOP') |
|
422 self.visit(suite) |
|
423 self.emit('JUMP_FORWARD', end) |
|
424 self.startBlock(nextTest) |
|
425 self.emit('POP_TOP') |
|
426 if node.else_: |
|
427 self.visit(node.else_) |
|
428 self.nextBlock(end) |
|
429 |
|
430 def visitWhile(self, node): |
|
431 self.set_lineno(node) |
|
432 |
|
433 loop = self.newBlock() |
|
434 else_ = self.newBlock() |
|
435 |
|
436 after = self.newBlock() |
|
437 self.emit('SETUP_LOOP', after) |
|
438 |
|
439 self.nextBlock(loop) |
|
440 self.setups.push((LOOP, loop)) |
|
441 |
|
442 self.set_lineno(node, force=True) |
|
443 self.visit(node.test) |
|
444 self.emit('JUMP_IF_FALSE', else_ or after) |
|
445 |
|
446 self.nextBlock() |
|
447 self.emit('POP_TOP') |
|
448 self.visit(node.body) |
|
449 self.emit('JUMP_ABSOLUTE', loop) |
|
450 |
|
451 self.startBlock(else_) # or just the POPs if not else clause |
|
452 self.emit('POP_TOP') |
|
453 self.emit('POP_BLOCK') |
|
454 self.setups.pop() |
|
455 if node.else_: |
|
456 self.visit(node.else_) |
|
457 self.nextBlock(after) |
|
458 |
|
459 def visitFor(self, node): |
|
460 start = self.newBlock() |
|
461 anchor = self.newBlock() |
|
462 after = self.newBlock() |
|
463 self.setups.push((LOOP, start)) |
|
464 |
|
465 self.set_lineno(node) |
|
466 self.emit('SETUP_LOOP', after) |
|
467 self.visit(node.list) |
|
468 self.emit('GET_ITER') |
|
469 |
|
470 self.nextBlock(start) |
|
471 self.set_lineno(node, force=1) |
|
472 self.emit('FOR_ITER', anchor) |
|
473 self.visit(node.assign) |
|
474 self.visit(node.body) |
|
475 self.emit('JUMP_ABSOLUTE', start) |
|
476 self.nextBlock(anchor) |
|
477 self.emit('POP_BLOCK') |
|
478 self.setups.pop() |
|
479 if node.else_: |
|
480 self.visit(node.else_) |
|
481 self.nextBlock(after) |
|
482 |
|
483 def visitBreak(self, node): |
|
484 if not self.setups: |
|
485 raise SyntaxError, "'break' outside loop (%s, %d)" % \ |
|
486 (node.filename, node.lineno) |
|
487 self.set_lineno(node) |
|
488 self.emit('BREAK_LOOP') |
|
489 |
|
490 def visitContinue(self, node): |
|
491 if not self.setups: |
|
492 raise SyntaxError, "'continue' outside loop (%s, %d)" % \ |
|
493 (node.filename, node.lineno) |
|
494 kind, block = self.setups.top() |
|
495 if kind == LOOP: |
|
496 self.set_lineno(node) |
|
497 self.emit('JUMP_ABSOLUTE', block) |
|
498 self.nextBlock() |
|
499 elif kind == EXCEPT or kind == TRY_FINALLY: |
|
500 self.set_lineno(node) |
|
501 # find the block that starts the loop |
|
502 top = len(self.setups) |
|
503 while top > 0: |
|
504 top = top - 1 |
|
505 kind, loop_block = self.setups[top] |
|
506 if kind == LOOP: |
|
507 break |
|
508 if kind != LOOP: |
|
509 raise SyntaxError, "'continue' outside loop (%s, %d)" % \ |
|
510 (node.filename, node.lineno) |
|
511 self.emit('CONTINUE_LOOP', loop_block) |
|
512 self.nextBlock() |
|
513 elif kind == END_FINALLY: |
|
514 msg = "'continue' not allowed inside 'finally' clause (%s, %d)" |
|
515 raise SyntaxError, msg % (node.filename, node.lineno) |
|
516 |
|
517 def visitTest(self, node, jump): |
|
518 end = self.newBlock() |
|
519 for child in node.nodes[:-1]: |
|
520 self.visit(child) |
|
521 self.emit(jump, end) |
|
522 self.nextBlock() |
|
523 self.emit('POP_TOP') |
|
524 self.visit(node.nodes[-1]) |
|
525 self.nextBlock(end) |
|
526 |
|
527 def visitAnd(self, node): |
|
528 self.visitTest(node, 'JUMP_IF_FALSE') |
|
529 |
|
530 def visitOr(self, node): |
|
531 self.visitTest(node, 'JUMP_IF_TRUE') |
|
532 |
|
533 def visitIfExp(self, node): |
|
534 endblock = self.newBlock() |
|
535 elseblock = self.newBlock() |
|
536 self.visit(node.test) |
|
537 self.emit('JUMP_IF_FALSE', elseblock) |
|
538 self.emit('POP_TOP') |
|
539 self.visit(node.then) |
|
540 self.emit('JUMP_FORWARD', endblock) |
|
541 self.nextBlock(elseblock) |
|
542 self.emit('POP_TOP') |
|
543 self.visit(node.else_) |
|
544 self.nextBlock(endblock) |
|
545 |
|
546 def visitCompare(self, node): |
|
547 self.visit(node.expr) |
|
548 cleanup = self.newBlock() |
|
549 for op, code in node.ops[:-1]: |
|
550 self.visit(code) |
|
551 self.emit('DUP_TOP') |
|
552 self.emit('ROT_THREE') |
|
553 self.emit('COMPARE_OP', op) |
|
554 self.emit('JUMP_IF_FALSE', cleanup) |
|
555 self.nextBlock() |
|
556 self.emit('POP_TOP') |
|
557 # now do the last comparison |
|
558 if node.ops: |
|
559 op, code = node.ops[-1] |
|
560 self.visit(code) |
|
561 self.emit('COMPARE_OP', op) |
|
562 if len(node.ops) > 1: |
|
563 end = self.newBlock() |
|
564 self.emit('JUMP_FORWARD', end) |
|
565 self.startBlock(cleanup) |
|
566 self.emit('ROT_TWO') |
|
567 self.emit('POP_TOP') |
|
568 self.nextBlock(end) |
|
569 |
|
570 # list comprehensions |
|
571 __list_count = 0 |
|
572 |
|
573 def visitListComp(self, node): |
|
574 self.set_lineno(node) |
|
575 # setup list |
|
576 append = "$append%d" % self.__list_count |
|
577 self.__list_count = self.__list_count + 1 |
|
578 self.emit('BUILD_LIST', 0) |
|
579 self.emit('DUP_TOP') |
|
580 self.emit('LOAD_ATTR', 'append') |
|
581 self._implicitNameOp('STORE', append) |
|
582 |
|
583 stack = [] |
|
584 for i, for_ in zip(range(len(node.quals)), node.quals): |
|
585 start, anchor = self.visit(for_) |
|
586 cont = None |
|
587 for if_ in for_.ifs: |
|
588 if cont is None: |
|
589 cont = self.newBlock() |
|
590 self.visit(if_, cont) |
|
591 stack.insert(0, (start, cont, anchor)) |
|
592 |
|
593 self._implicitNameOp('LOAD', append) |
|
594 self.visit(node.expr) |
|
595 self.emit('CALL_FUNCTION', 1) |
|
596 self.emit('POP_TOP') |
|
597 |
|
598 for start, cont, anchor in stack: |
|
599 if cont: |
|
600 skip_one = self.newBlock() |
|
601 self.emit('JUMP_FORWARD', skip_one) |
|
602 self.startBlock(cont) |
|
603 self.emit('POP_TOP') |
|
604 self.nextBlock(skip_one) |
|
605 self.emit('JUMP_ABSOLUTE', start) |
|
606 self.startBlock(anchor) |
|
607 self._implicitNameOp('DELETE', append) |
|
608 |
|
609 self.__list_count = self.__list_count - 1 |
|
610 |
|
611 def visitListCompFor(self, node): |
|
612 start = self.newBlock() |
|
613 anchor = self.newBlock() |
|
614 |
|
615 self.visit(node.list) |
|
616 self.emit('GET_ITER') |
|
617 self.nextBlock(start) |
|
618 self.set_lineno(node, force=True) |
|
619 self.emit('FOR_ITER', anchor) |
|
620 self.nextBlock() |
|
621 self.visit(node.assign) |
|
622 return start, anchor |
|
623 |
|
624 def visitListCompIf(self, node, branch): |
|
625 self.set_lineno(node, force=True) |
|
626 self.visit(node.test) |
|
627 self.emit('JUMP_IF_FALSE', branch) |
|
628 self.newBlock() |
|
629 self.emit('POP_TOP') |
|
630 |
|
631 def _makeClosure(self, gen, args): |
|
632 frees = gen.scope.get_free_vars() |
|
633 if frees: |
|
634 for name in frees: |
|
635 self.emit('LOAD_CLOSURE', name) |
|
636 self.emit('BUILD_TUPLE', len(frees)) |
|
637 self.emit('LOAD_CONST', gen) |
|
638 self.emit('MAKE_CLOSURE', args) |
|
639 else: |
|
640 self.emit('LOAD_CONST', gen) |
|
641 self.emit('MAKE_FUNCTION', args) |
|
642 |
|
643 def visitGenExpr(self, node): |
|
644 gen = GenExprCodeGenerator(node, self.scopes, self.class_name, |
|
645 self.get_module()) |
|
646 walk(node.code, gen) |
|
647 gen.finish() |
|
648 self.set_lineno(node) |
|
649 self._makeClosure(gen, 0) |
|
650 # precomputation of outmost iterable |
|
651 self.visit(node.code.quals[0].iter) |
|
652 self.emit('GET_ITER') |
|
653 self.emit('CALL_FUNCTION', 1) |
|
654 |
|
655 def visitGenExprInner(self, node): |
|
656 self.set_lineno(node) |
|
657 # setup list |
|
658 |
|
659 stack = [] |
|
660 for i, for_ in zip(range(len(node.quals)), node.quals): |
|
661 start, anchor, end = self.visit(for_) |
|
662 cont = None |
|
663 for if_ in for_.ifs: |
|
664 if cont is None: |
|
665 cont = self.newBlock() |
|
666 self.visit(if_, cont) |
|
667 stack.insert(0, (start, cont, anchor, end)) |
|
668 |
|
669 self.visit(node.expr) |
|
670 self.emit('YIELD_VALUE') |
|
671 self.emit('POP_TOP') |
|
672 |
|
673 for start, cont, anchor, end in stack: |
|
674 if cont: |
|
675 skip_one = self.newBlock() |
|
676 self.emit('JUMP_FORWARD', skip_one) |
|
677 self.startBlock(cont) |
|
678 self.emit('POP_TOP') |
|
679 self.nextBlock(skip_one) |
|
680 self.emit('JUMP_ABSOLUTE', start) |
|
681 self.startBlock(anchor) |
|
682 self.emit('POP_BLOCK') |
|
683 self.setups.pop() |
|
684 self.startBlock(end) |
|
685 |
|
686 self.emit('LOAD_CONST', None) |
|
687 |
|
688 def visitGenExprFor(self, node): |
|
689 start = self.newBlock() |
|
690 anchor = self.newBlock() |
|
691 end = self.newBlock() |
|
692 |
|
693 self.setups.push((LOOP, start)) |
|
694 self.emit('SETUP_LOOP', end) |
|
695 |
|
696 if node.is_outmost: |
|
697 self.loadName('.0') |
|
698 else: |
|
699 self.visit(node.iter) |
|
700 self.emit('GET_ITER') |
|
701 |
|
702 self.nextBlock(start) |
|
703 self.set_lineno(node, force=True) |
|
704 self.emit('FOR_ITER', anchor) |
|
705 self.nextBlock() |
|
706 self.visit(node.assign) |
|
707 return start, anchor, end |
|
708 |
|
709 def visitGenExprIf(self, node, branch): |
|
710 self.set_lineno(node, force=True) |
|
711 self.visit(node.test) |
|
712 self.emit('JUMP_IF_FALSE', branch) |
|
713 self.newBlock() |
|
714 self.emit('POP_TOP') |
|
715 |
|
716 # exception related |
|
717 |
|
718 def visitAssert(self, node): |
|
719 # XXX would be interesting to implement this via a |
|
720 # transformation of the AST before this stage |
|
721 if __debug__: |
|
722 end = self.newBlock() |
|
723 self.set_lineno(node) |
|
724 # XXX AssertionError appears to be special case -- it is always |
|
725 # loaded as a global even if there is a local name. I guess this |
|
726 # is a sort of renaming op. |
|
727 self.nextBlock() |
|
728 self.visit(node.test) |
|
729 self.emit('JUMP_IF_TRUE', end) |
|
730 self.nextBlock() |
|
731 self.emit('POP_TOP') |
|
732 self.emit('LOAD_GLOBAL', 'AssertionError') |
|
733 if node.fail: |
|
734 self.visit(node.fail) |
|
735 self.emit('RAISE_VARARGS', 2) |
|
736 else: |
|
737 self.emit('RAISE_VARARGS', 1) |
|
738 self.nextBlock(end) |
|
739 self.emit('POP_TOP') |
|
740 |
|
741 def visitRaise(self, node): |
|
742 self.set_lineno(node) |
|
743 n = 0 |
|
744 if node.expr1: |
|
745 self.visit(node.expr1) |
|
746 n = n + 1 |
|
747 if node.expr2: |
|
748 self.visit(node.expr2) |
|
749 n = n + 1 |
|
750 if node.expr3: |
|
751 self.visit(node.expr3) |
|
752 n = n + 1 |
|
753 self.emit('RAISE_VARARGS', n) |
|
754 |
|
755 def visitTryExcept(self, node): |
|
756 body = self.newBlock() |
|
757 handlers = self.newBlock() |
|
758 end = self.newBlock() |
|
759 if node.else_: |
|
760 lElse = self.newBlock() |
|
761 else: |
|
762 lElse = end |
|
763 self.set_lineno(node) |
|
764 self.emit('SETUP_EXCEPT', handlers) |
|
765 self.nextBlock(body) |
|
766 self.setups.push((EXCEPT, body)) |
|
767 self.visit(node.body) |
|
768 self.emit('POP_BLOCK') |
|
769 self.setups.pop() |
|
770 self.emit('JUMP_FORWARD', lElse) |
|
771 self.startBlock(handlers) |
|
772 |
|
773 last = len(node.handlers) - 1 |
|
774 for i in range(len(node.handlers)): |
|
775 expr, target, body = node.handlers[i] |
|
776 self.set_lineno(expr) |
|
777 if expr: |
|
778 self.emit('DUP_TOP') |
|
779 self.visit(expr) |
|
780 self.emit('COMPARE_OP', 'exception match') |
|
781 next = self.newBlock() |
|
782 self.emit('JUMP_IF_FALSE', next) |
|
783 self.nextBlock() |
|
784 self.emit('POP_TOP') |
|
785 self.emit('POP_TOP') |
|
786 if target: |
|
787 self.visit(target) |
|
788 else: |
|
789 self.emit('POP_TOP') |
|
790 self.emit('POP_TOP') |
|
791 self.visit(body) |
|
792 self.emit('JUMP_FORWARD', end) |
|
793 if expr: |
|
794 self.nextBlock(next) |
|
795 else: |
|
796 self.nextBlock() |
|
797 if expr: # XXX |
|
798 self.emit('POP_TOP') |
|
799 self.emit('END_FINALLY') |
|
800 if node.else_: |
|
801 self.nextBlock(lElse) |
|
802 self.visit(node.else_) |
|
803 self.nextBlock(end) |
|
804 |
|
805 def visitTryFinally(self, node): |
|
806 body = self.newBlock() |
|
807 final = self.newBlock() |
|
808 self.set_lineno(node) |
|
809 self.emit('SETUP_FINALLY', final) |
|
810 self.nextBlock(body) |
|
811 self.setups.push((TRY_FINALLY, body)) |
|
812 self.visit(node.body) |
|
813 self.emit('POP_BLOCK') |
|
814 self.setups.pop() |
|
815 self.emit('LOAD_CONST', None) |
|
816 self.nextBlock(final) |
|
817 self.setups.push((END_FINALLY, final)) |
|
818 self.visit(node.final) |
|
819 self.emit('END_FINALLY') |
|
820 self.setups.pop() |
|
821 |
|
822 __with_count = 0 |
|
823 |
|
824 def visitWith(self, node): |
|
825 body = self.newBlock() |
|
826 final = self.newBlock() |
|
827 exitvar = "$exit%d" % self.__with_count |
|
828 valuevar = "$value%d" % self.__with_count |
|
829 self.__with_count += 1 |
|
830 self.set_lineno(node) |
|
831 self.visit(node.expr) |
|
832 self.emit('DUP_TOP') |
|
833 self.emit('LOAD_ATTR', '__exit__') |
|
834 self._implicitNameOp('STORE', exitvar) |
|
835 self.emit('LOAD_ATTR', '__enter__') |
|
836 self.emit('CALL_FUNCTION', 0) |
|
837 if node.vars is None: |
|
838 self.emit('POP_TOP') |
|
839 else: |
|
840 self._implicitNameOp('STORE', valuevar) |
|
841 self.emit('SETUP_FINALLY', final) |
|
842 self.nextBlock(body) |
|
843 self.setups.push((TRY_FINALLY, body)) |
|
844 if node.vars is not None: |
|
845 self._implicitNameOp('LOAD', valuevar) |
|
846 self._implicitNameOp('DELETE', valuevar) |
|
847 self.visit(node.vars) |
|
848 self.visit(node.body) |
|
849 self.emit('POP_BLOCK') |
|
850 self.setups.pop() |
|
851 self.emit('LOAD_CONST', None) |
|
852 self.nextBlock(final) |
|
853 self.setups.push((END_FINALLY, final)) |
|
854 self._implicitNameOp('LOAD', exitvar) |
|
855 self._implicitNameOp('DELETE', exitvar) |
|
856 self.emit('WITH_CLEANUP') |
|
857 self.emit('END_FINALLY') |
|
858 self.setups.pop() |
|
859 self.__with_count -= 1 |
|
860 |
|
861 # misc |
|
862 |
|
863 def visitDiscard(self, node): |
|
864 self.set_lineno(node) |
|
865 self.visit(node.expr) |
|
866 self.emit('POP_TOP') |
|
867 |
|
868 def visitConst(self, node): |
|
869 self.emit('LOAD_CONST', node.value) |
|
870 |
|
871 def visitKeyword(self, node): |
|
872 self.emit('LOAD_CONST', node.name) |
|
873 self.visit(node.expr) |
|
874 |
|
875 def visitGlobal(self, node): |
|
876 # no code to generate |
|
877 pass |
|
878 |
|
879 def visitName(self, node): |
|
880 self.set_lineno(node) |
|
881 self.loadName(node.name) |
|
882 |
|
883 def visitPass(self, node): |
|
884 self.set_lineno(node) |
|
885 |
|
886 def visitImport(self, node): |
|
887 self.set_lineno(node) |
|
888 level = 0 if self.graph.checkFlag(CO_FUTURE_ABSIMPORT) else -1 |
|
889 for name, alias in node.names: |
|
890 if VERSION > 1: |
|
891 self.emit('LOAD_CONST', level) |
|
892 self.emit('LOAD_CONST', None) |
|
893 self.emit('IMPORT_NAME', name) |
|
894 mod = name.split(".")[0] |
|
895 if alias: |
|
896 self._resolveDots(name) |
|
897 self.storeName(alias) |
|
898 else: |
|
899 self.storeName(mod) |
|
900 |
|
901 def visitFrom(self, node): |
|
902 self.set_lineno(node) |
|
903 level = node.level |
|
904 if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT): |
|
905 level = -1 |
|
906 fromlist = map(lambda (name, alias): name, node.names) |
|
907 if VERSION > 1: |
|
908 self.emit('LOAD_CONST', level) |
|
909 self.emit('LOAD_CONST', tuple(fromlist)) |
|
910 self.emit('IMPORT_NAME', node.modname) |
|
911 for name, alias in node.names: |
|
912 if VERSION > 1: |
|
913 if name == '*': |
|
914 self.namespace = 0 |
|
915 self.emit('IMPORT_STAR') |
|
916 # There can only be one name w/ from ... import * |
|
917 assert len(node.names) == 1 |
|
918 return |
|
919 else: |
|
920 self.emit('IMPORT_FROM', name) |
|
921 self._resolveDots(name) |
|
922 self.storeName(alias or name) |
|
923 else: |
|
924 self.emit('IMPORT_FROM', name) |
|
925 self.emit('POP_TOP') |
|
926 |
|
927 def _resolveDots(self, name): |
|
928 elts = name.split(".") |
|
929 if len(elts) == 1: |
|
930 return |
|
931 for elt in elts[1:]: |
|
932 self.emit('LOAD_ATTR', elt) |
|
933 |
|
934 def visitGetattr(self, node): |
|
935 self.visit(node.expr) |
|
936 self.emit('LOAD_ATTR', self.mangle(node.attrname)) |
|
937 |
|
938 # next five implement assignments |
|
939 |
|
940 def visitAssign(self, node): |
|
941 self.set_lineno(node) |
|
942 self.visit(node.expr) |
|
943 dups = len(node.nodes) - 1 |
|
944 for i in range(len(node.nodes)): |
|
945 elt = node.nodes[i] |
|
946 if i < dups: |
|
947 self.emit('DUP_TOP') |
|
948 if isinstance(elt, ast.Node): |
|
949 self.visit(elt) |
|
950 |
|
951 def visitAssName(self, node): |
|
952 if node.flags == 'OP_ASSIGN': |
|
953 self.storeName(node.name) |
|
954 elif node.flags == 'OP_DELETE': |
|
955 self.set_lineno(node) |
|
956 self.delName(node.name) |
|
957 else: |
|
958 print "oops", node.flags |
|
959 |
|
960 def visitAssAttr(self, node): |
|
961 self.visit(node.expr) |
|
962 if node.flags == 'OP_ASSIGN': |
|
963 self.emit('STORE_ATTR', self.mangle(node.attrname)) |
|
964 elif node.flags == 'OP_DELETE': |
|
965 self.emit('DELETE_ATTR', self.mangle(node.attrname)) |
|
966 else: |
|
967 print "warning: unexpected flags:", node.flags |
|
968 print node |
|
969 |
|
970 def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'): |
|
971 if findOp(node) != 'OP_DELETE': |
|
972 self.emit(op, len(node.nodes)) |
|
973 for child in node.nodes: |
|
974 self.visit(child) |
|
975 |
|
976 if VERSION > 1: |
|
977 visitAssTuple = _visitAssSequence |
|
978 visitAssList = _visitAssSequence |
|
979 else: |
|
980 def visitAssTuple(self, node): |
|
981 self._visitAssSequence(node, 'UNPACK_TUPLE') |
|
982 |
|
983 def visitAssList(self, node): |
|
984 self._visitAssSequence(node, 'UNPACK_LIST') |
|
985 |
|
986 # augmented assignment |
|
987 |
|
988 def visitAugAssign(self, node): |
|
989 self.set_lineno(node) |
|
990 aug_node = wrap_aug(node.node) |
|
991 self.visit(aug_node, "load") |
|
992 self.visit(node.expr) |
|
993 self.emit(self._augmented_opcode[node.op]) |
|
994 self.visit(aug_node, "store") |
|
995 |
|
996 _augmented_opcode = { |
|
997 '+=' : 'INPLACE_ADD', |
|
998 '-=' : 'INPLACE_SUBTRACT', |
|
999 '*=' : 'INPLACE_MULTIPLY', |
|
1000 '/=' : 'INPLACE_DIVIDE', |
|
1001 '//=': 'INPLACE_FLOOR_DIVIDE', |
|
1002 '%=' : 'INPLACE_MODULO', |
|
1003 '**=': 'INPLACE_POWER', |
|
1004 '>>=': 'INPLACE_RSHIFT', |
|
1005 '<<=': 'INPLACE_LSHIFT', |
|
1006 '&=' : 'INPLACE_AND', |
|
1007 '^=' : 'INPLACE_XOR', |
|
1008 '|=' : 'INPLACE_OR', |
|
1009 } |
|
1010 |
|
1011 def visitAugName(self, node, mode): |
|
1012 if mode == "load": |
|
1013 self.loadName(node.name) |
|
1014 elif mode == "store": |
|
1015 self.storeName(node.name) |
|
1016 |
|
1017 def visitAugGetattr(self, node, mode): |
|
1018 if mode == "load": |
|
1019 self.visit(node.expr) |
|
1020 self.emit('DUP_TOP') |
|
1021 self.emit('LOAD_ATTR', self.mangle(node.attrname)) |
|
1022 elif mode == "store": |
|
1023 self.emit('ROT_TWO') |
|
1024 self.emit('STORE_ATTR', self.mangle(node.attrname)) |
|
1025 |
|
1026 def visitAugSlice(self, node, mode): |
|
1027 if mode == "load": |
|
1028 self.visitSlice(node, 1) |
|
1029 elif mode == "store": |
|
1030 slice = 0 |
|
1031 if node.lower: |
|
1032 slice = slice | 1 |
|
1033 if node.upper: |
|
1034 slice = slice | 2 |
|
1035 if slice == 0: |
|
1036 self.emit('ROT_TWO') |
|
1037 elif slice == 3: |
|
1038 self.emit('ROT_FOUR') |
|
1039 else: |
|
1040 self.emit('ROT_THREE') |
|
1041 self.emit('STORE_SLICE+%d' % slice) |
|
1042 |
|
1043 def visitAugSubscript(self, node, mode): |
|
1044 if mode == "load": |
|
1045 self.visitSubscript(node, 1) |
|
1046 elif mode == "store": |
|
1047 self.emit('ROT_THREE') |
|
1048 self.emit('STORE_SUBSCR') |
|
1049 |
|
1050 def visitExec(self, node): |
|
1051 self.visit(node.expr) |
|
1052 if node.locals is None: |
|
1053 self.emit('LOAD_CONST', None) |
|
1054 else: |
|
1055 self.visit(node.locals) |
|
1056 if node.globals is None: |
|
1057 self.emit('DUP_TOP') |
|
1058 else: |
|
1059 self.visit(node.globals) |
|
1060 self.emit('EXEC_STMT') |
|
1061 |
|
1062 def visitCallFunc(self, node): |
|
1063 pos = 0 |
|
1064 kw = 0 |
|
1065 self.set_lineno(node) |
|
1066 self.visit(node.node) |
|
1067 for arg in node.args: |
|
1068 self.visit(arg) |
|
1069 if isinstance(arg, ast.Keyword): |
|
1070 kw = kw + 1 |
|
1071 else: |
|
1072 pos = pos + 1 |
|
1073 if node.star_args is not None: |
|
1074 self.visit(node.star_args) |
|
1075 if node.dstar_args is not None: |
|
1076 self.visit(node.dstar_args) |
|
1077 have_star = node.star_args is not None |
|
1078 have_dstar = node.dstar_args is not None |
|
1079 opcode = callfunc_opcode_info[have_star, have_dstar] |
|
1080 self.emit(opcode, kw << 8 | pos) |
|
1081 |
|
1082 def visitPrint(self, node, newline=0): |
|
1083 self.set_lineno(node) |
|
1084 if node.dest: |
|
1085 self.visit(node.dest) |
|
1086 for child in node.nodes: |
|
1087 if node.dest: |
|
1088 self.emit('DUP_TOP') |
|
1089 self.visit(child) |
|
1090 if node.dest: |
|
1091 self.emit('ROT_TWO') |
|
1092 self.emit('PRINT_ITEM_TO') |
|
1093 else: |
|
1094 self.emit('PRINT_ITEM') |
|
1095 if node.dest and not newline: |
|
1096 self.emit('POP_TOP') |
|
1097 |
|
1098 def visitPrintnl(self, node): |
|
1099 self.visitPrint(node, newline=1) |
|
1100 if node.dest: |
|
1101 self.emit('PRINT_NEWLINE_TO') |
|
1102 else: |
|
1103 self.emit('PRINT_NEWLINE') |
|
1104 |
|
1105 def visitReturn(self, node): |
|
1106 self.set_lineno(node) |
|
1107 self.visit(node.value) |
|
1108 self.emit('RETURN_VALUE') |
|
1109 |
|
1110 def visitYield(self, node): |
|
1111 self.set_lineno(node) |
|
1112 self.visit(node.value) |
|
1113 self.emit('YIELD_VALUE') |
|
1114 |
|
1115 # slice and subscript stuff |
|
1116 |
|
1117 def visitSlice(self, node, aug_flag=None): |
|
1118 # aug_flag is used by visitAugSlice |
|
1119 self.visit(node.expr) |
|
1120 slice = 0 |
|
1121 if node.lower: |
|
1122 self.visit(node.lower) |
|
1123 slice = slice | 1 |
|
1124 if node.upper: |
|
1125 self.visit(node.upper) |
|
1126 slice = slice | 2 |
|
1127 if aug_flag: |
|
1128 if slice == 0: |
|
1129 self.emit('DUP_TOP') |
|
1130 elif slice == 3: |
|
1131 self.emit('DUP_TOPX', 3) |
|
1132 else: |
|
1133 self.emit('DUP_TOPX', 2) |
|
1134 if node.flags == 'OP_APPLY': |
|
1135 self.emit('SLICE+%d' % slice) |
|
1136 elif node.flags == 'OP_ASSIGN': |
|
1137 self.emit('STORE_SLICE+%d' % slice) |
|
1138 elif node.flags == 'OP_DELETE': |
|
1139 self.emit('DELETE_SLICE+%d' % slice) |
|
1140 else: |
|
1141 print "weird slice", node.flags |
|
1142 raise |
|
1143 |
|
1144 def visitSubscript(self, node, aug_flag=None): |
|
1145 self.visit(node.expr) |
|
1146 for sub in node.subs: |
|
1147 self.visit(sub) |
|
1148 if len(node.subs) > 1: |
|
1149 self.emit('BUILD_TUPLE', len(node.subs)) |
|
1150 if aug_flag: |
|
1151 self.emit('DUP_TOPX', 2) |
|
1152 if node.flags == 'OP_APPLY': |
|
1153 self.emit('BINARY_SUBSCR') |
|
1154 elif node.flags == 'OP_ASSIGN': |
|
1155 self.emit('STORE_SUBSCR') |
|
1156 elif node.flags == 'OP_DELETE': |
|
1157 self.emit('DELETE_SUBSCR') |
|
1158 |
|
1159 # binary ops |
|
1160 |
|
1161 def binaryOp(self, node, op): |
|
1162 self.visit(node.left) |
|
1163 self.visit(node.right) |
|
1164 self.emit(op) |
|
1165 |
|
1166 def visitAdd(self, node): |
|
1167 return self.binaryOp(node, 'BINARY_ADD') |
|
1168 |
|
1169 def visitSub(self, node): |
|
1170 return self.binaryOp(node, 'BINARY_SUBTRACT') |
|
1171 |
|
1172 def visitMul(self, node): |
|
1173 return self.binaryOp(node, 'BINARY_MULTIPLY') |
|
1174 |
|
1175 def visitDiv(self, node): |
|
1176 return self.binaryOp(node, self._div_op) |
|
1177 |
|
1178 def visitFloorDiv(self, node): |
|
1179 return self.binaryOp(node, 'BINARY_FLOOR_DIVIDE') |
|
1180 |
|
1181 def visitMod(self, node): |
|
1182 return self.binaryOp(node, 'BINARY_MODULO') |
|
1183 |
|
1184 def visitPower(self, node): |
|
1185 return self.binaryOp(node, 'BINARY_POWER') |
|
1186 |
|
1187 def visitLeftShift(self, node): |
|
1188 return self.binaryOp(node, 'BINARY_LSHIFT') |
|
1189 |
|
1190 def visitRightShift(self, node): |
|
1191 return self.binaryOp(node, 'BINARY_RSHIFT') |
|
1192 |
|
1193 # unary ops |
|
1194 |
|
1195 def unaryOp(self, node, op): |
|
1196 self.visit(node.expr) |
|
1197 self.emit(op) |
|
1198 |
|
1199 def visitInvert(self, node): |
|
1200 return self.unaryOp(node, 'UNARY_INVERT') |
|
1201 |
|
1202 def visitUnarySub(self, node): |
|
1203 return self.unaryOp(node, 'UNARY_NEGATIVE') |
|
1204 |
|
1205 def visitUnaryAdd(self, node): |
|
1206 return self.unaryOp(node, 'UNARY_POSITIVE') |
|
1207 |
|
1208 def visitUnaryInvert(self, node): |
|
1209 return self.unaryOp(node, 'UNARY_INVERT') |
|
1210 |
|
1211 def visitNot(self, node): |
|
1212 return self.unaryOp(node, 'UNARY_NOT') |
|
1213 |
|
1214 def visitBackquote(self, node): |
|
1215 return self.unaryOp(node, 'UNARY_CONVERT') |
|
1216 |
|
1217 # bit ops |
|
1218 |
|
1219 def bitOp(self, nodes, op): |
|
1220 self.visit(nodes[0]) |
|
1221 for node in nodes[1:]: |
|
1222 self.visit(node) |
|
1223 self.emit(op) |
|
1224 |
|
1225 def visitBitand(self, node): |
|
1226 return self.bitOp(node.nodes, 'BINARY_AND') |
|
1227 |
|
1228 def visitBitor(self, node): |
|
1229 return self.bitOp(node.nodes, 'BINARY_OR') |
|
1230 |
|
1231 def visitBitxor(self, node): |
|
1232 return self.bitOp(node.nodes, 'BINARY_XOR') |
|
1233 |
|
1234 # object constructors |
|
1235 |
|
1236 def visitEllipsis(self, node): |
|
1237 self.emit('LOAD_CONST', Ellipsis) |
|
1238 |
|
1239 def visitTuple(self, node): |
|
1240 self.set_lineno(node) |
|
1241 for elt in node.nodes: |
|
1242 self.visit(elt) |
|
1243 self.emit('BUILD_TUPLE', len(node.nodes)) |
|
1244 |
|
1245 def visitList(self, node): |
|
1246 self.set_lineno(node) |
|
1247 for elt in node.nodes: |
|
1248 self.visit(elt) |
|
1249 self.emit('BUILD_LIST', len(node.nodes)) |
|
1250 |
|
1251 def visitSliceobj(self, node): |
|
1252 for child in node.nodes: |
|
1253 self.visit(child) |
|
1254 self.emit('BUILD_SLICE', len(node.nodes)) |
|
1255 |
|
1256 def visitDict(self, node): |
|
1257 self.set_lineno(node) |
|
1258 self.emit('BUILD_MAP', 0) |
|
1259 for k, v in node.items: |
|
1260 self.emit('DUP_TOP') |
|
1261 self.visit(k) |
|
1262 self.visit(v) |
|
1263 self.emit('ROT_THREE') |
|
1264 self.emit('STORE_SUBSCR') |
|
1265 |
|
1266 class NestedScopeMixin: |
|
1267 """Defines initClass() for nested scoping (Python 2.2-compatible)""" |
|
1268 def initClass(self): |
|
1269 self.__class__.NameFinder = LocalNameFinder |
|
1270 self.__class__.FunctionGen = FunctionCodeGenerator |
|
1271 self.__class__.ClassGen = ClassCodeGenerator |
|
1272 |
|
1273 class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator): |
|
1274 __super_init = CodeGenerator.__init__ |
|
1275 |
|
1276 scopes = None |
|
1277 |
|
1278 def __init__(self, tree): |
|
1279 self.graph = pyassem.PyFlowGraph("<module>", tree.filename) |
|
1280 self.futures = future.find_futures(tree) |
|
1281 self.__super_init() |
|
1282 walk(tree, self) |
|
1283 |
|
1284 def get_module(self): |
|
1285 return self |
|
1286 |
|
1287 class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator): |
|
1288 __super_init = CodeGenerator.__init__ |
|
1289 |
|
1290 scopes = None |
|
1291 futures = () |
|
1292 |
|
1293 def __init__(self, tree): |
|
1294 self.graph = pyassem.PyFlowGraph("<expression>", tree.filename) |
|
1295 self.__super_init() |
|
1296 walk(tree, self) |
|
1297 |
|
1298 def get_module(self): |
|
1299 return self |
|
1300 |
|
1301 class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator): |
|
1302 |
|
1303 __super_init = CodeGenerator.__init__ |
|
1304 |
|
1305 scopes = None |
|
1306 futures = () |
|
1307 |
|
1308 def __init__(self, tree): |
|
1309 self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename) |
|
1310 self.__super_init() |
|
1311 self.set_lineno(tree) |
|
1312 walk(tree, self) |
|
1313 self.emit('RETURN_VALUE') |
|
1314 |
|
1315 def get_module(self): |
|
1316 return self |
|
1317 |
|
1318 def visitDiscard(self, node): |
|
1319 # XXX Discard means it's an expression. Perhaps this is a bad |
|
1320 # name. |
|
1321 self.visit(node.expr) |
|
1322 self.emit('PRINT_EXPR') |
|
1323 |
|
1324 class AbstractFunctionCode: |
|
1325 optimized = 1 |
|
1326 lambdaCount = 0 |
|
1327 |
|
1328 def __init__(self, func, scopes, isLambda, class_name, mod): |
|
1329 self.class_name = class_name |
|
1330 self.module = mod |
|
1331 if isLambda: |
|
1332 klass = FunctionCodeGenerator |
|
1333 name = "<lambda.%d>" % klass.lambdaCount |
|
1334 klass.lambdaCount = klass.lambdaCount + 1 |
|
1335 else: |
|
1336 name = func.name |
|
1337 |
|
1338 args, hasTupleArg = generateArgList(func.argnames) |
|
1339 self.graph = pyassem.PyFlowGraph(name, func.filename, args, |
|
1340 optimized=1) |
|
1341 self.isLambda = isLambda |
|
1342 self.super_init() |
|
1343 |
|
1344 if not isLambda and func.doc: |
|
1345 self.setDocstring(func.doc) |
|
1346 |
|
1347 lnf = walk(func.code, self.NameFinder(args), verbose=0) |
|
1348 self.locals.push(lnf.getLocals()) |
|
1349 if func.varargs: |
|
1350 self.graph.setFlag(CO_VARARGS) |
|
1351 if func.kwargs: |
|
1352 self.graph.setFlag(CO_VARKEYWORDS) |
|
1353 self.set_lineno(func) |
|
1354 if hasTupleArg: |
|
1355 self.generateArgUnpack(func.argnames) |
|
1356 |
|
1357 def get_module(self): |
|
1358 return self.module |
|
1359 |
|
1360 def finish(self): |
|
1361 self.graph.startExitBlock() |
|
1362 if not self.isLambda: |
|
1363 self.emit('LOAD_CONST', None) |
|
1364 self.emit('RETURN_VALUE') |
|
1365 |
|
1366 def generateArgUnpack(self, args): |
|
1367 for i in range(len(args)): |
|
1368 arg = args[i] |
|
1369 if isinstance(arg, tuple): |
|
1370 self.emit('LOAD_FAST', '.%d' % (i * 2)) |
|
1371 self.unpackSequence(arg) |
|
1372 |
|
1373 def unpackSequence(self, tup): |
|
1374 if VERSION > 1: |
|
1375 self.emit('UNPACK_SEQUENCE', len(tup)) |
|
1376 else: |
|
1377 self.emit('UNPACK_TUPLE', len(tup)) |
|
1378 for elt in tup: |
|
1379 if isinstance(elt, tuple): |
|
1380 self.unpackSequence(elt) |
|
1381 else: |
|
1382 self._nameOp('STORE', elt) |
|
1383 |
|
1384 unpackTuple = unpackSequence |
|
1385 |
|
1386 class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode, |
|
1387 CodeGenerator): |
|
1388 super_init = CodeGenerator.__init__ # call be other init |
|
1389 scopes = None |
|
1390 |
|
1391 __super_init = AbstractFunctionCode.__init__ |
|
1392 |
|
1393 def __init__(self, func, scopes, isLambda, class_name, mod): |
|
1394 self.scopes = scopes |
|
1395 self.scope = scopes[func] |
|
1396 self.__super_init(func, scopes, isLambda, class_name, mod) |
|
1397 self.graph.setFreeVars(self.scope.get_free_vars()) |
|
1398 self.graph.setCellVars(self.scope.get_cell_vars()) |
|
1399 if self.scope.generator is not None: |
|
1400 self.graph.setFlag(CO_GENERATOR) |
|
1401 |
|
1402 class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode, |
|
1403 CodeGenerator): |
|
1404 super_init = CodeGenerator.__init__ # call be other init |
|
1405 scopes = None |
|
1406 |
|
1407 __super_init = AbstractFunctionCode.__init__ |
|
1408 |
|
1409 def __init__(self, gexp, scopes, class_name, mod): |
|
1410 self.scopes = scopes |
|
1411 self.scope = scopes[gexp] |
|
1412 self.__super_init(gexp, scopes, 1, class_name, mod) |
|
1413 self.graph.setFreeVars(self.scope.get_free_vars()) |
|
1414 self.graph.setCellVars(self.scope.get_cell_vars()) |
|
1415 self.graph.setFlag(CO_GENERATOR) |
|
1416 |
|
1417 class AbstractClassCode: |
|
1418 |
|
1419 def __init__(self, klass, scopes, module): |
|
1420 self.class_name = klass.name |
|
1421 self.module = module |
|
1422 self.graph = pyassem.PyFlowGraph(klass.name, klass.filename, |
|
1423 optimized=0, klass=1) |
|
1424 self.super_init() |
|
1425 lnf = walk(klass.code, self.NameFinder(), verbose=0) |
|
1426 self.locals.push(lnf.getLocals()) |
|
1427 self.graph.setFlag(CO_NEWLOCALS) |
|
1428 if klass.doc: |
|
1429 self.setDocstring(klass.doc) |
|
1430 |
|
1431 def get_module(self): |
|
1432 return self.module |
|
1433 |
|
1434 def finish(self): |
|
1435 self.graph.startExitBlock() |
|
1436 self.emit('LOAD_LOCALS') |
|
1437 self.emit('RETURN_VALUE') |
|
1438 |
|
1439 class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator): |
|
1440 super_init = CodeGenerator.__init__ |
|
1441 scopes = None |
|
1442 |
|
1443 __super_init = AbstractClassCode.__init__ |
|
1444 |
|
1445 def __init__(self, klass, scopes, module): |
|
1446 self.scopes = scopes |
|
1447 self.scope = scopes[klass] |
|
1448 self.__super_init(klass, scopes, module) |
|
1449 self.graph.setFreeVars(self.scope.get_free_vars()) |
|
1450 self.graph.setCellVars(self.scope.get_cell_vars()) |
|
1451 self.set_lineno(klass) |
|
1452 self.emit("LOAD_GLOBAL", "__name__") |
|
1453 self.storeName("__module__") |
|
1454 if klass.doc: |
|
1455 self.emit("LOAD_CONST", klass.doc) |
|
1456 self.storeName('__doc__') |
|
1457 |
|
1458 def generateArgList(arglist): |
|
1459 """Generate an arg list marking TupleArgs""" |
|
1460 args = [] |
|
1461 extra = [] |
|
1462 count = 0 |
|
1463 for i in range(len(arglist)): |
|
1464 elt = arglist[i] |
|
1465 if isinstance(elt, str): |
|
1466 args.append(elt) |
|
1467 elif isinstance(elt, tuple): |
|
1468 args.append(TupleArg(i * 2, elt)) |
|
1469 extra.extend(misc.flatten(elt)) |
|
1470 count = count + 1 |
|
1471 else: |
|
1472 raise ValueError, "unexpect argument type:", elt |
|
1473 return args + extra, count |
|
1474 |
|
1475 def findOp(node): |
|
1476 """Find the op (DELETE, LOAD, STORE) in an AssTuple tree""" |
|
1477 v = OpFinder() |
|
1478 walk(node, v, verbose=0) |
|
1479 return v.op |
|
1480 |
|
1481 class OpFinder: |
|
1482 def __init__(self): |
|
1483 self.op = None |
|
1484 def visitAssName(self, node): |
|
1485 if self.op is None: |
|
1486 self.op = node.flags |
|
1487 elif self.op != node.flags: |
|
1488 raise ValueError, "mixed ops in stmt" |
|
1489 visitAssAttr = visitAssName |
|
1490 visitSubscript = visitAssName |
|
1491 |
|
1492 class Delegator: |
|
1493 """Base class to support delegation for augmented assignment nodes |
|
1494 |
|
1495 To generator code for augmented assignments, we use the following |
|
1496 wrapper classes. In visitAugAssign, the left-hand expression node |
|
1497 is visited twice. The first time the visit uses the normal method |
|
1498 for that node . The second time the visit uses a different method |
|
1499 that generates the appropriate code to perform the assignment. |
|
1500 These delegator classes wrap the original AST nodes in order to |
|
1501 support the variant visit methods. |
|
1502 """ |
|
1503 def __init__(self, obj): |
|
1504 self.obj = obj |
|
1505 |
|
1506 def __getattr__(self, attr): |
|
1507 return getattr(self.obj, attr) |
|
1508 |
|
1509 class AugGetattr(Delegator): |
|
1510 pass |
|
1511 |
|
1512 class AugName(Delegator): |
|
1513 pass |
|
1514 |
|
1515 class AugSlice(Delegator): |
|
1516 pass |
|
1517 |
|
1518 class AugSubscript(Delegator): |
|
1519 pass |
|
1520 |
|
1521 wrapper = { |
|
1522 ast.Getattr: AugGetattr, |
|
1523 ast.Name: AugName, |
|
1524 ast.Slice: AugSlice, |
|
1525 ast.Subscript: AugSubscript, |
|
1526 } |
|
1527 |
|
1528 def wrap_aug(node): |
|
1529 return wrapper[node.__class__](node) |
|
1530 |
|
1531 if __name__ == "__main__": |
|
1532 for file in sys.argv[1:]: |
|
1533 compileFile(file) |