blob: a697b55759044e4c2dcf60b0738c2dc50789bc7e [file] [log] [blame]
Jeremy Hylton53187f32000-02-08 19:01:29 +00001import os
Jeremy Hylton36cc6a22000-03-16 20:06:59 +00002import marshal
Jeremy Hylton53187f32000-02-08 19:01:29 +00003import stat
4import struct
Jeremy Hyltonad9a86f2000-02-16 00:55:44 +00005import types
Jeremy Hylton36cc6a22000-03-16 20:06:59 +00006from cStringIO import StringIO
7
8from compiler import ast, parse, walk
9from compiler import pyassem, misc
10from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, TupleArg
11
Jeremy Hyltonbe317e62000-05-02 22:32:59 +000012callfunc_opcode_info = {
13 # (Have *args, Have **args) : opcode
14 (0,0) : "CALL_FUNCTION",
15 (1,0) : "CALL_FUNCTION_VAR",
16 (0,1) : "CALL_FUNCTION_KW",
17 (1,1) : "CALL_FUNCTION_VAR_KW",
18}
19
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000020def compile(filename):
21 f = open(filename)
22 buf = f.read()
23 f.close()
24 mod = Module(buf, filename)
25 mod.compile()
26 f = open(filename + "c", "wb")
27 mod.dump(f)
28 f.close()
29
30class Module:
31 def __init__(self, source, filename):
32 self.filename = filename
33 self.source = source
34 self.code = None
35
36 def compile(self):
37 ast = parse(self.source)
38 root, filename = os.path.split(self.filename)
39 gen = ModuleCodeGenerator(filename)
40 walk(ast, gen, 1)
41 self.code = gen.getCode()
42
43 def dump(self, f):
44 f.write(self.getPycHeader())
45 marshal.dump(self.code, f)
46
47 MAGIC = (20121 | (ord('\r')<<16) | (ord('\n')<<24))
48
49 def getPycHeader(self):
50 # compile.c uses marshal to write a long directly, with
51 # calling the interface that would also generate a 1-byte code
52 # to indicate the type of the value. simplest way to get the
53 # same effect is to call marshal and then skip the code.
54 magic = marshal.dumps(self.MAGIC)[1:]
55 mtime = os.stat(self.filename)[stat.ST_MTIME]
56 mtime = struct.pack('i', mtime)
57 return magic + mtime
Jeremy Hylton8b6323d2000-02-04 00:28:21 +000058
Jeremy Hylton8b6323d2000-02-04 00:28:21 +000059class CodeGenerator:
Jeremy Hylton3e0910c2000-02-10 17:20:39 +000060
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000061 optimized = 0 # is namespace access optimized?
Jeremy Hylton3050d512000-02-12 00:12:38 +000062
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000063 def __init__(self, filename):
64## Subclasses must define a constructor that intializes self.graph
65## before calling this init function
66## self.graph = pyassem.PyFlowGraph()
67 self.filename = filename
68 self.locals = misc.Stack()
69 self.loops = misc.Stack()
70 self.curStack = 0
71 self.maxStack = 0
72 self._setupGraphDelegation()
Jeremy Hylton53187f32000-02-08 19:01:29 +000073
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000074 def _setupGraphDelegation(self):
75 self.emit = self.graph.emit
76 self.newBlock = self.graph.newBlock
77 self.startBlock = self.graph.startBlock
78 self.nextBlock = self.graph.nextBlock
79 self.setDocstring = self.graph.setDocstring
Jeremy Hyltona5058122000-02-14 14:14:29 +000080
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000081 def getCode(self):
82 """Return a code object"""
83 return self.graph.getCode()
Jeremy Hylton76d01b82000-02-11 20:27:07 +000084
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000085 # Next five methods handle name access
Jeremy Hylton53187f32000-02-08 19:01:29 +000086
Jeremy Hylton40245602000-02-08 21:15:48 +000087 def isLocalName(self, name):
Jeremy Hylton873bdc12000-02-17 17:56:29 +000088 return self.locals.top().has_elt(name)
Jeremy Hylton40245602000-02-08 21:15:48 +000089
Jeremy Hylton3e0910c2000-02-10 17:20:39 +000090 def storeName(self, name):
91 self._nameOp('STORE', name)
92
93 def loadName(self, name):
94 self._nameOp('LOAD', name)
95
96 def delName(self, name):
97 self._nameOp('DELETE', name)
98
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000099 def _nameOp(self, prefix, name):
100 if not self.optimized:
101 self.emit(prefix + '_NAME', name)
102 return
103 if self.isLocalName(name):
104 self.emit(prefix + '_FAST', name)
105 else:
106 self.emit(prefix + '_GLOBAL', name)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000107
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000108 # The first few visitor methods handle nodes that generator new
109 # code objects
110
111 def visitModule(self, node):
112 lnf = walk(node.node, LocalNameFinder(), 0)
113 self.locals.push(lnf.getLocals())
114 self.setDocstring(node.doc)
115 self.visit(node.node)
116 self.emit('LOAD_CONST', None)
117 self.emit('RETURN_VALUE')
118
119 def visitFunction(self, node):
120 self._visitFuncOrLambda(node, isLambda=0)
121 self.storeName(node.name)
122
123 def visitLambda(self, node):
124 self._visitFuncOrLambda(node, isLambda=1)
125## self.storeName("<lambda>")
126
127 def _visitFuncOrLambda(self, node, isLambda):
128 gen = FunctionCodeGenerator(node, self.filename, isLambda)
129 walk(node.code, gen)
130 gen.finish()
131 self.emit('SET_LINENO', node.lineno)
132 for default in node.defaults:
133 self.visit(default)
134 self.emit('LOAD_CONST', gen.getCode())
135 self.emit('MAKE_FUNCTION', len(node.defaults))
136
137 def visitClass(self, node):
138 gen = ClassCodeGenerator(node, self.filename)
139 walk(node.code, gen)
140 gen.finish()
141 self.emit('SET_LINENO', node.lineno)
142 self.emit('LOAD_CONST', node.name)
143 for base in node.bases:
144 self.visit(base)
145 self.emit('BUILD_TUPLE', len(node.bases))
146 self.emit('LOAD_CONST', gen.getCode())
147 self.emit('MAKE_FUNCTION', 0)
148 self.emit('CALL_FUNCTION', 0)
149 self.emit('BUILD_CLASS')
150 self.storeName(node.name)
151
152 # The rest are standard visitor methods
153
154 # The next few implement control-flow statements
155
156 def visitIf(self, node):
157 end = self.newBlock()
158 numtests = len(node.tests)
159 for i in range(numtests):
160 test, suite = node.tests[i]
161 if hasattr(test, 'lineno'):
162 self.emit('SET_LINENO', test.lineno)
163 self.visit(test)
164## if i == numtests - 1 and not node.else_:
165## nextTest = end
166## else:
167## nextTest = self.newBlock()
168 nextTest = self.newBlock()
169 self.emit('JUMP_IF_FALSE', nextTest)
170 self.nextBlock()
171 self.emit('POP_TOP')
172 self.visit(suite)
173 self.emit('JUMP_FORWARD', end)
174 self.nextBlock(nextTest)
175 self.emit('POP_TOP')
176 if node.else_:
177 self.visit(node.else_)
178 self.nextBlock(end)
179
180 def visitWhile(self, node):
181 self.emit('SET_LINENO', node.lineno)
182
183 loop = self.newBlock()
184 else_ = self.newBlock()
185
186 after = self.newBlock()
187 self.emit('SETUP_LOOP', after)
188
189 self.nextBlock(loop)
190 self.loops.push(loop)
191
192 self.emit('SET_LINENO', node.lineno)
193 self.visit(node.test)
194 self.emit('JUMP_IF_FALSE', else_ or after)
195
196 self.nextBlock()
197 self.emit('POP_TOP')
198 self.visit(node.body)
199 self.emit('JUMP_ABSOLUTE', loop)
200
201 self.startBlock(else_) # or just the POPs if not else clause
202 self.emit('POP_TOP')
203 self.emit('POP_BLOCK')
204 if node.else_:
205 self.visit(node.else_)
206 self.loops.pop()
207 self.nextBlock(after)
208
209 def visitFor(self, node):
210 start = self.newBlock()
211 anchor = self.newBlock()
212 after = self.newBlock()
213 self.loops.push(start)
214
215 self.emit('SET_LINENO', node.lineno)
216 self.emit('SETUP_LOOP', after)
217 self.visit(node.list)
218 self.visit(ast.Const(0))
219 self.nextBlock(start)
220 self.emit('SET_LINENO', node.lineno)
221 self.emit('FOR_LOOP', anchor)
222 self.visit(node.assign)
223 self.visit(node.body)
224 self.emit('JUMP_ABSOLUTE', start)
225 self.nextBlock(anchor)
226 self.emit('POP_BLOCK')
227 if node.else_:
228 self.visit(node.else_)
229 self.loops.pop()
230 self.nextBlock(after)
231
232 def visitBreak(self, node):
233 if not self.loops:
234 raise SyntaxError, "'break' outside loop (%s, %d)" % \
235 (self.filename, node.lineno)
236 self.emit('SET_LINENO', node.lineno)
237 self.emit('BREAK_LOOP')
238
239 def visitContinue(self, node):
240 if not self.loops:
241 raise SyntaxError, "'continue' outside loop (%s, %d)" % \
242 (self.filename, node.lineno)
243 l = self.loops.top()
244 self.emit('SET_LINENO', node.lineno)
245 self.emit('JUMP_ABSOLUTE', l)
246 self.nextBlock()
247
248 def visitTest(self, node, jump):
249 end = self.newBlock()
250 for child in node.nodes[:-1]:
251 self.visit(child)
252 self.emit(jump, end)
253 self.nextBlock()
254 self.emit('POP_TOP')
255 self.visit(node.nodes[-1])
256 self.nextBlock(end)
257
258 def visitAnd(self, node):
259 self.visitTest(node, 'JUMP_IF_FALSE')
260
261 def visitOr(self, node):
262 self.visitTest(node, 'JUMP_IF_TRUE')
263
264 def visitCompare(self, node):
265 self.visit(node.expr)
266 cleanup = self.newBlock()
267 for op, code in node.ops[:-1]:
268 self.visit(code)
269 self.emit('DUP_TOP')
270 self.emit('ROT_THREE')
271 self.emit('COMPARE_OP', op)
272 self.emit('JUMP_IF_FALSE', cleanup)
273 self.nextBlock()
274 self.emit('POP_TOP')
275 # now do the last comparison
276 if node.ops:
277 op, code = node.ops[-1]
278 self.visit(code)
279 self.emit('COMPARE_OP', op)
280 if len(node.ops) > 1:
281 end = self.newBlock()
282 self.emit('JUMP_FORWARD', end)
283 self.nextBlock(cleanup)
284 self.emit('ROT_TWO')
285 self.emit('POP_TOP')
286 self.nextBlock(end)
287
288 # exception related
289
290 def visitAssert(self, node):
291 # XXX would be interesting to implement this via a
292 # transformation of the AST before this stage
293 end = self.newBlock()
294 self.emit('SET_LINENO', node.lineno)
295 # XXX __debug__ and AssertionError appear to be special cases
296 # -- they are always loaded as globals even if there are local
297 # names. I guess this is a sort of renaming op.
298 self.emit('LOAD_GLOBAL', '__debug__')
299 self.emit('JUMP_IF_FALSE', end)
300 self.nextBlock()
301 self.emit('POP_TOP')
302 self.visit(node.test)
303 self.emit('JUMP_IF_TRUE', end)
304 self.nextBlock()
305 self.emit('LOAD_GLOBAL', 'AssertionError')
306 self.visit(node.fail)
307 self.emit('RAISE_VARARGS', 2)
308 self.nextBlock(end)
309 self.emit('POP_TOP')
310
311 def visitRaise(self, node):
312 self.emit('SET_LINENO', node.lineno)
313 n = 0
314 if node.expr1:
315 self.visit(node.expr1)
316 n = n + 1
317 if node.expr2:
318 self.visit(node.expr2)
319 n = n + 1
320 if node.expr3:
321 self.visit(node.expr3)
322 n = n + 1
323 self.emit('RAISE_VARARGS', n)
324
325 def visitTryExcept(self, node):
326 handlers = self.newBlock()
327 end = self.newBlock()
328 if node.else_:
329 lElse = self.newBlock()
330 else:
331 lElse = end
332 self.emit('SET_LINENO', node.lineno)
333 self.emit('SETUP_EXCEPT', handlers)
334 self.visit(node.body)
335 self.emit('POP_BLOCK')
336 self.emit('JUMP_FORWARD', lElse)
337 self.nextBlock(handlers)
338
339 last = len(node.handlers) - 1
340 for i in range(len(node.handlers)):
341 expr, target, body = node.handlers[i]
342 if hasattr(expr, 'lineno'):
343 self.emit('SET_LINENO', expr.lineno)
344 if expr:
345 self.emit('DUP_TOP')
346 self.visit(expr)
347 self.emit('COMPARE_OP', 'exception match')
348 next = self.newBlock()
349 self.emit('JUMP_IF_FALSE', next)
350 self.nextBlock()
351 self.emit('POP_TOP')
352 self.emit('POP_TOP')
353 if target:
354 self.visit(target)
355 else:
356 self.emit('POP_TOP')
357 self.emit('POP_TOP')
358 self.visit(body)
359 self.emit('JUMP_FORWARD', end)
360 if expr:
361 self.nextBlock(next)
362 self.emit('POP_TOP')
363 self.emit('END_FINALLY')
364 if node.else_:
365 self.nextBlock(lElse)
366 self.visit(node.else_)
367 self.nextBlock(end)
368
369 def visitTryFinally(self, node):
370 final = self.newBlock()
371 self.emit('SET_LINENO', node.lineno)
372 self.emit('SETUP_FINALLY', final)
373 self.visit(node.body)
374 self.emit('POP_BLOCK')
375 self.emit('LOAD_CONST', None)
376 self.nextBlock(final)
377 self.visit(node.final)
378 self.emit('END_FINALLY')
379
380 # misc
381
382## def visitStmt(self, node):
383## # nothing to do except walk the children
384## pass
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000385
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000386 def visitDiscard(self, node):
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000387 self.visit(node.expr)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000388 self.emit('POP_TOP')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000389
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000390 def visitConst(self, node):
391 self.emit('LOAD_CONST', node.value)
392
393 def visitKeyword(self, node):
394 self.emit('LOAD_CONST', node.name)
395 self.visit(node.expr)
396
397 def visitGlobal(self, node):
398 # no code to generate
399 pass
400
401 def visitName(self, node):
402 self.loadName(node.name)
403
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000404 def visitPass(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000405 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000406
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000407 def visitImport(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000408 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000409 for name in node.names:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000410 self.emit('IMPORT_NAME', name)
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000411 self.storeName(name)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000412
413 def visitFrom(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000414 self.emit('SET_LINENO', node.lineno)
415 self.emit('IMPORT_NAME', node.modname)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000416 for name in node.names:
Jeremy Hylton126960b2000-02-14 21:33:10 +0000417 if name == '*':
418 self.namespace = 0
Jeremy Hyltona5058122000-02-14 14:14:29 +0000419 self.emit('IMPORT_FROM', name)
420 self.emit('POP_TOP')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000421
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000422 def visitGetattr(self, node):
423 self.visit(node.expr)
424 self.emit('LOAD_ATTR', node.attrname)
425
426 # next five implement assignments
427
428 def visitAssign(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000429 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000430 self.visit(node.expr)
431 dups = len(node.nodes) - 1
432 for i in range(len(node.nodes)):
433 elt = node.nodes[i]
434 if i < dups:
435 self.emit('DUP_TOP')
436 if isinstance(elt, ast.Node):
437 self.visit(elt)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000438
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000439 def visitAssName(self, node):
440 if node.flags == 'OP_ASSIGN':
441 self.storeName(node.name)
442 elif node.flags == 'OP_DELETE':
443 self.delName(node.name)
444 else:
445 print "oops", node.flags
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000446
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000447 def visitAssAttr(self, node):
448 self.visit(node.expr)
449 if node.flags == 'OP_ASSIGN':
450 self.emit('STORE_ATTR', node.attrname)
451 elif node.flags == 'OP_DELETE':
452 self.emit('DELETE_ATTR', node.attrname)
453 else:
454 print "warning: unexpected flags:", node.flags
455 print node
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000456
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000457 def visitAssTuple(self, node):
458 if findOp(node) != 'OP_DELETE':
459 self.emit('UNPACK_TUPLE', len(node.nodes))
460 for child in node.nodes:
461 self.visit(child)
462
463 visitAssList = visitAssTuple
464
465 def visitExec(self, node):
466 self.visit(node.expr)
467 if node.locals is None:
468 self.emit('LOAD_CONST', None)
469 else:
470 self.visit(node.locals)
471 if node.globals is None:
472 self.emit('DUP_TOP')
473 else:
474 self.visit(node.globals)
475 self.emit('EXEC_STMT')
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000476
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000477 def visitCallFunc(self, node):
Jeremy Hylton3050d512000-02-12 00:12:38 +0000478 pos = 0
479 kw = 0
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000480 if hasattr(node, 'lineno'):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000481 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000482 self.visit(node.node)
483 for arg in node.args:
484 self.visit(arg)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000485 if isinstance(arg, ast.Keyword):
486 kw = kw + 1
487 else:
488 pos = pos + 1
Jeremy Hyltonbe317e62000-05-02 22:32:59 +0000489 if node.star_args is not None:
490 self.visit(node.star_args)
491 if node.dstar_args is not None:
492 self.visit(node.dstar_args)
493 have_star = node.star_args is not None
494 have_dstar = node.dstar_args is not None
495 opcode = callfunc_opcode_info[have_star, have_dstar]
496 self.emit(opcode, kw << 8 | pos)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000497
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000498 def visitPrint(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000499 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000500 for child in node.nodes:
501 self.visit(child)
502 self.emit('PRINT_ITEM')
503
504 def visitPrintnl(self, node):
505 self.visitPrint(node)
506 self.emit('PRINT_NEWLINE')
507
508 def visitReturn(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000509 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000510 self.visit(node.value)
511 self.emit('RETURN_VALUE')
Jeremy Hylton40245602000-02-08 21:15:48 +0000512
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000513 # slice and subscript stuff
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000514
515 def visitSlice(self, node):
516 self.visit(node.expr)
517 slice = 0
518 if node.lower:
519 self.visit(node.lower)
520 slice = slice | 1
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000521 if node.upper:
522 self.visit(node.upper)
523 slice = slice | 2
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000524 if node.flags == 'OP_APPLY':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000525 self.emit('SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000526 elif node.flags == 'OP_ASSIGN':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000527 self.emit('STORE_SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000528 elif node.flags == 'OP_DELETE':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000529 self.emit('DELETE_SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000530 else:
Jeremy Hylton4f6bcd82000-02-15 23:45:26 +0000531 print "weird slice", node.flags
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000532 raise
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000533
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000534 def visitSubscript(self, node):
Jeremy Hylton40245602000-02-08 21:15:48 +0000535 self.visit(node.expr)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000536 for sub in node.subs:
537 self.visit(sub)
538 if len(node.subs) > 1:
539 self.emit('BUILD_TUPLE', len(node.subs))
540 if node.flags == 'OP_APPLY':
541 self.emit('BINARY_SUBSCR')
542 elif node.flags == 'OP_ASSIGN':
543 self.emit('STORE_SUBSCR')
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000544 elif node.flags == 'OP_DELETE':
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000545 self.emit('DELETE_SUBSCR')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000546
Jeremy Hylton7fab23e2000-03-06 19:10:54 +0000547 # binary ops
548
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000549 def binaryOp(self, node, op):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000550 self.visit(node.left)
551 self.visit(node.right)
552 self.emit(op)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000553
554 def visitAdd(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000555 return self.binaryOp(node, 'BINARY_ADD')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000556
557 def visitSub(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000558 return self.binaryOp(node, 'BINARY_SUBTRACT')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000559
560 def visitMul(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000561 return self.binaryOp(node, 'BINARY_MULTIPLY')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000562
563 def visitDiv(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000564 return self.binaryOp(node, 'BINARY_DIVIDE')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000565
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000566 def visitMod(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000567 return self.binaryOp(node, 'BINARY_MODULO')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000568
Jeremy Hylton126960b2000-02-14 21:33:10 +0000569 def visitPower(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000570 return self.binaryOp(node, 'BINARY_POWER')
Jeremy Hylton126960b2000-02-14 21:33:10 +0000571
572 def visitLeftShift(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000573 return self.binaryOp(node, 'BINARY_LSHIFT')
Jeremy Hylton126960b2000-02-14 21:33:10 +0000574
575 def visitRightShift(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000576 return self.binaryOp(node, 'BINARY_RSHIFT')
Jeremy Hylton126960b2000-02-14 21:33:10 +0000577
Jeremy Hylton7fab23e2000-03-06 19:10:54 +0000578 # unary ops
579
580 def unaryOp(self, node, op):
581 self.visit(node.expr)
582 self.emit(op)
Jeremy Hylton7fab23e2000-03-06 19:10:54 +0000583
Jeremy Hylton126960b2000-02-14 21:33:10 +0000584 def visitInvert(self, node):
585 return self.unaryOp(node, 'UNARY_INVERT')
586
Jeremy Hylton40245602000-02-08 21:15:48 +0000587 def visitUnarySub(self, node):
588 return self.unaryOp(node, 'UNARY_NEGATIVE')
589
590 def visitUnaryAdd(self, node):
591 return self.unaryOp(node, 'UNARY_POSITIVE')
592
593 def visitUnaryInvert(self, node):
594 return self.unaryOp(node, 'UNARY_INVERT')
595
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000596 def visitNot(self, node):
597 return self.unaryOp(node, 'UNARY_NOT')
598
Jeremy Hylton40245602000-02-08 21:15:48 +0000599 def visitBackquote(self, node):
600 return self.unaryOp(node, 'UNARY_CONVERT')
601
Jeremy Hylton7fab23e2000-03-06 19:10:54 +0000602 # bit ops
603
Jeremy Hyltona5058122000-02-14 14:14:29 +0000604 def bitOp(self, nodes, op):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000605 self.visit(nodes[0])
606 for node in nodes[1:]:
607 self.visit(node)
608 self.emit(op)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000609
610 def visitBitand(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000611 return self.bitOp(node.nodes, 'BINARY_AND')
Jeremy Hyltona5058122000-02-14 14:14:29 +0000612
613 def visitBitor(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000614 return self.bitOp(node.nodes, 'BINARY_OR')
Jeremy Hyltona5058122000-02-14 14:14:29 +0000615
616 def visitBitxor(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000617 return self.bitOp(node.nodes, 'BINARY_XOR')
Jeremy Hyltona5058122000-02-14 14:14:29 +0000618
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000619 # object constructors
Jeremy Hylton40245602000-02-08 21:15:48 +0000620
Jeremy Hyltona5058122000-02-14 14:14:29 +0000621 def visitEllipsis(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000622 self.emit('LOAD_CONST', Ellipsis)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000623
Jeremy Hylton40245602000-02-08 21:15:48 +0000624 def visitTuple(self, node):
625 for elt in node.nodes:
626 self.visit(elt)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000627 self.emit('BUILD_TUPLE', len(node.nodes))
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000628
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000629 def visitList(self, node):
630 for elt in node.nodes:
631 self.visit(elt)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000632 self.emit('BUILD_LIST', len(node.nodes))
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000633
634 def visitSliceobj(self, node):
635 for child in node.nodes:
636 self.visit(child)
637 self.emit('BUILD_SLICE', len(node.nodes))
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000638
Jeremy Hyltona5058122000-02-14 14:14:29 +0000639 def visitDict(self, node):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000640 # XXX is this a good general strategy? could it be done
641 # separately from the general visitor
642 lineno = getattr(node, 'lineno', None)
643 if lineno:
644 self.emit('SET_LINENO', lineno)
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000645 self.emit('BUILD_MAP', 0)
646 for k, v in node.items:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000647 lineno2 = getattr(node, 'lineno', None)
648 if lineno != lineno2:
649 self.emit('SET_LINENO', lineno2)
650 lineno = lineno2
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000651 self.emit('DUP_TOP')
652 self.visit(v)
653 self.emit('ROT_TWO')
654 self.visit(k)
655 self.emit('STORE_SUBSCR')
Jeremy Hyltona5058122000-02-14 14:14:29 +0000656
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000657class ModuleCodeGenerator(CodeGenerator):
658 super_init = CodeGenerator.__init__
659
660 def __init__(self, filename):
661 # XXX <module> is ? in compile.c
662 self.graph = pyassem.PyFlowGraph("<module>", filename)
663 self.super_init(filename)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000664
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000665class FunctionCodeGenerator(CodeGenerator):
666 super_init = CodeGenerator.__init__
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000667
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000668 optimized = 1
669 lambdaCount = 0
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000670
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000671 def __init__(self, func, filename, isLambda=0):
672 if isLambda:
673 klass = FunctionCodeGenerator
674 name = "<lambda.%d>" % klass.lambdaCount
675 klass.lambdaCount = klass.lambdaCount + 1
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000676 else:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000677 name = func.name
678 args, hasTupleArg = generateArgList(func.argnames)
679 self.graph = pyassem.PyFlowGraph(name, filename, args,
680 optimized=1)
681 self.isLambda = isLambda
682 self.super_init(filename)
683
684 lnf = walk(func.code, LocalNameFinder(args), 0)
685 self.locals.push(lnf.getLocals())
686 if func.varargs:
687 self.graph.setFlag(CO_VARARGS)
688 if func.kwargs:
689 self.graph.setFlag(CO_VARKEYWORDS)
690 self.emit('SET_LINENO', func.lineno)
691 if hasTupleArg:
692 self.generateArgUnpack(func.argnames)
693
694 def finish(self):
695 self.graph.startExitBlock()
696 if not self.isLambda:
697 self.emit('LOAD_CONST', None)
698 self.emit('RETURN_VALUE')
699
700 def generateArgUnpack(self, args):
701 count = 0
702 for arg in args:
703 if type(arg) == types.TupleType:
704 self.emit('LOAD_FAST', '.nested%d' % count)
705 count = count + 1
706 self.unpackTuple(arg)
707
708 def unpackTuple(self, tup):
709 self.emit('UNPACK_TUPLE', len(tup))
710 for elt in tup:
711 if type(elt) == types.TupleType:
712 self.unpackTuple(elt)
713 else:
714 self.emit('STORE_FAST', elt)
715
716class ClassCodeGenerator(CodeGenerator):
717 super_init = CodeGenerator.__init__
718
719 def __init__(self, klass, filename):
720 self.graph = pyassem.PyFlowGraph(klass.name, filename,
721 optimized=0)
722 self.super_init(filename)
723 lnf = walk(klass.code, LocalNameFinder(), 0)
724 self.locals.push(lnf.getLocals())
725
726 def finish(self):
727 self.graph.startExitBlock()
728 self.emit('LOAD_LOCALS')
729 self.emit('RETURN_VALUE')
730
731
732def generateArgList(arglist):
733 """Generate an arg list marking TupleArgs"""
734 args = []
735 extra = []
736 count = 0
737 for elt in arglist:
738 if type(elt) == types.StringType:
739 args.append(elt)
740 elif type(elt) == types.TupleType:
741 args.append(TupleArg(count, elt))
742 count = count + 1
743 extra.extend(misc.flatten(elt))
744 else:
745 raise ValueError, "unexpect argument type:", elt
746 return args + extra, count
Jeremy Hyltona5058122000-02-14 14:14:29 +0000747
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000748class LocalNameFinder:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000749 """Find local names in scope"""
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000750 def __init__(self, names=()):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000751 self.names = misc.Set()
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000752 self.globals = misc.Set()
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000753 for name in names:
754 self.names.add(name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000755
756 def getLocals(self):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000757 for elt in self.globals.elements():
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000758 if self.names.has_elt(elt):
759 self.names.remove(elt)
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000760 return self.names
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000761
Jeremy Hyltona5058122000-02-14 14:14:29 +0000762 def visitDict(self, node):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000763 pass
Jeremy Hyltona5058122000-02-14 14:14:29 +0000764
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000765 def visitGlobal(self, node):
766 for name in node.names:
767 self.globals.add(name)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000768
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000769 def visitFunction(self, node):
770 self.names.add(node.name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000771
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000772 def visitLambda(self, node):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000773 pass
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000774
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000775 def visitImport(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000776 for name in node.names:
777 self.names.add(name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000778
779 def visitFrom(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000780 for name in node.names:
781 self.names.add(name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000782
Jeremy Hylton7fab23e2000-03-06 19:10:54 +0000783 def visitClass(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000784 self.names.add(node.name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000785
786 def visitAssName(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000787 self.names.add(node.name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000788
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000789def findOp(node):
790 """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
791 v = OpFinder()
792 walk(node, v, 0)
793 return v.op
794
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000795class OpFinder:
796 def __init__(self):
797 self.op = None
798 def visitAssName(self, node):
799 if self.op is None:
800 self.op = node.flags
801 elif self.op != node.flags:
802 raise ValueError, "mixed ops in stmt"
803
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000804if __name__ == "__main__":
805 import sys
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000806
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000807 for file in sys.argv[1:]:
808 compile(file)