blob: 2e98d4e633c0e53de7b5d4d165c15ba7bc12e838 [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
12def compile(filename):
13 f = open(filename)
14 buf = f.read()
15 f.close()
16 mod = Module(buf, filename)
17 mod.compile()
18 f = open(filename + "c", "wb")
19 mod.dump(f)
20 f.close()
21
22class Module:
23 def __init__(self, source, filename):
24 self.filename = filename
25 self.source = source
26 self.code = None
27
28 def compile(self):
29 ast = parse(self.source)
30 root, filename = os.path.split(self.filename)
31 gen = ModuleCodeGenerator(filename)
32 walk(ast, gen, 1)
33 self.code = gen.getCode()
34
35 def dump(self, f):
36 f.write(self.getPycHeader())
37 marshal.dump(self.code, f)
38
39 MAGIC = (20121 | (ord('\r')<<16) | (ord('\n')<<24))
40
41 def getPycHeader(self):
42 # compile.c uses marshal to write a long directly, with
43 # calling the interface that would also generate a 1-byte code
44 # to indicate the type of the value. simplest way to get the
45 # same effect is to call marshal and then skip the code.
46 magic = marshal.dumps(self.MAGIC)[1:]
47 mtime = os.stat(self.filename)[stat.ST_MTIME]
48 mtime = struct.pack('i', mtime)
49 return magic + mtime
Jeremy Hylton8b6323d2000-02-04 00:28:21 +000050
Jeremy Hylton8b6323d2000-02-04 00:28:21 +000051class CodeGenerator:
Jeremy Hylton3e0910c2000-02-10 17:20:39 +000052
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000053 optimized = 0 # is namespace access optimized?
Jeremy Hylton3050d512000-02-12 00:12:38 +000054
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000055 def __init__(self, filename):
56## Subclasses must define a constructor that intializes self.graph
57## before calling this init function
58## self.graph = pyassem.PyFlowGraph()
59 self.filename = filename
60 self.locals = misc.Stack()
61 self.loops = misc.Stack()
62 self.curStack = 0
63 self.maxStack = 0
64 self._setupGraphDelegation()
Jeremy Hylton53187f32000-02-08 19:01:29 +000065
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000066 def _setupGraphDelegation(self):
67 self.emit = self.graph.emit
68 self.newBlock = self.graph.newBlock
69 self.startBlock = self.graph.startBlock
70 self.nextBlock = self.graph.nextBlock
71 self.setDocstring = self.graph.setDocstring
Jeremy Hyltona5058122000-02-14 14:14:29 +000072
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000073 def getCode(self):
74 """Return a code object"""
75 return self.graph.getCode()
Jeremy Hylton76d01b82000-02-11 20:27:07 +000076
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000077 # Next five methods handle name access
Jeremy Hylton53187f32000-02-08 19:01:29 +000078
Jeremy Hylton40245602000-02-08 21:15:48 +000079 def isLocalName(self, name):
Jeremy Hylton873bdc12000-02-17 17:56:29 +000080 return self.locals.top().has_elt(name)
Jeremy Hylton40245602000-02-08 21:15:48 +000081
Jeremy Hylton3e0910c2000-02-10 17:20:39 +000082 def storeName(self, name):
83 self._nameOp('STORE', name)
84
85 def loadName(self, name):
86 self._nameOp('LOAD', name)
87
88 def delName(self, name):
89 self._nameOp('DELETE', name)
90
Jeremy Hylton36cc6a22000-03-16 20:06:59 +000091 def _nameOp(self, prefix, name):
92 if not self.optimized:
93 self.emit(prefix + '_NAME', name)
94 return
95 if self.isLocalName(name):
96 self.emit(prefix + '_FAST', name)
97 else:
98 self.emit(prefix + '_GLOBAL', name)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +000099
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000100 # The first few visitor methods handle nodes that generator new
101 # code objects
102
103 def visitModule(self, node):
104 lnf = walk(node.node, LocalNameFinder(), 0)
105 self.locals.push(lnf.getLocals())
106 self.setDocstring(node.doc)
107 self.visit(node.node)
108 self.emit('LOAD_CONST', None)
109 self.emit('RETURN_VALUE')
110
111 def visitFunction(self, node):
112 self._visitFuncOrLambda(node, isLambda=0)
113 self.storeName(node.name)
114
115 def visitLambda(self, node):
116 self._visitFuncOrLambda(node, isLambda=1)
117## self.storeName("<lambda>")
118
119 def _visitFuncOrLambda(self, node, isLambda):
120 gen = FunctionCodeGenerator(node, self.filename, isLambda)
121 walk(node.code, gen)
122 gen.finish()
123 self.emit('SET_LINENO', node.lineno)
124 for default in node.defaults:
125 self.visit(default)
126 self.emit('LOAD_CONST', gen.getCode())
127 self.emit('MAKE_FUNCTION', len(node.defaults))
128
129 def visitClass(self, node):
130 gen = ClassCodeGenerator(node, self.filename)
131 walk(node.code, gen)
132 gen.finish()
133 self.emit('SET_LINENO', node.lineno)
134 self.emit('LOAD_CONST', node.name)
135 for base in node.bases:
136 self.visit(base)
137 self.emit('BUILD_TUPLE', len(node.bases))
138 self.emit('LOAD_CONST', gen.getCode())
139 self.emit('MAKE_FUNCTION', 0)
140 self.emit('CALL_FUNCTION', 0)
141 self.emit('BUILD_CLASS')
142 self.storeName(node.name)
143
144 # The rest are standard visitor methods
145
146 # The next few implement control-flow statements
147
148 def visitIf(self, node):
149 end = self.newBlock()
150 numtests = len(node.tests)
151 for i in range(numtests):
152 test, suite = node.tests[i]
153 if hasattr(test, 'lineno'):
154 self.emit('SET_LINENO', test.lineno)
155 self.visit(test)
156## if i == numtests - 1 and not node.else_:
157## nextTest = end
158## else:
159## nextTest = self.newBlock()
160 nextTest = self.newBlock()
161 self.emit('JUMP_IF_FALSE', nextTest)
162 self.nextBlock()
163 self.emit('POP_TOP')
164 self.visit(suite)
165 self.emit('JUMP_FORWARD', end)
166 self.nextBlock(nextTest)
167 self.emit('POP_TOP')
168 if node.else_:
169 self.visit(node.else_)
170 self.nextBlock(end)
171
172 def visitWhile(self, node):
173 self.emit('SET_LINENO', node.lineno)
174
175 loop = self.newBlock()
176 else_ = self.newBlock()
177
178 after = self.newBlock()
179 self.emit('SETUP_LOOP', after)
180
181 self.nextBlock(loop)
182 self.loops.push(loop)
183
184 self.emit('SET_LINENO', node.lineno)
185 self.visit(node.test)
186 self.emit('JUMP_IF_FALSE', else_ or after)
187
188 self.nextBlock()
189 self.emit('POP_TOP')
190 self.visit(node.body)
191 self.emit('JUMP_ABSOLUTE', loop)
192
193 self.startBlock(else_) # or just the POPs if not else clause
194 self.emit('POP_TOP')
195 self.emit('POP_BLOCK')
196 if node.else_:
197 self.visit(node.else_)
198 self.loops.pop()
199 self.nextBlock(after)
200
201 def visitFor(self, node):
202 start = self.newBlock()
203 anchor = self.newBlock()
204 after = self.newBlock()
205 self.loops.push(start)
206
207 self.emit('SET_LINENO', node.lineno)
208 self.emit('SETUP_LOOP', after)
209 self.visit(node.list)
210 self.visit(ast.Const(0))
211 self.nextBlock(start)
212 self.emit('SET_LINENO', node.lineno)
213 self.emit('FOR_LOOP', anchor)
214 self.visit(node.assign)
215 self.visit(node.body)
216 self.emit('JUMP_ABSOLUTE', start)
217 self.nextBlock(anchor)
218 self.emit('POP_BLOCK')
219 if node.else_:
220 self.visit(node.else_)
221 self.loops.pop()
222 self.nextBlock(after)
223
224 def visitBreak(self, node):
225 if not self.loops:
226 raise SyntaxError, "'break' outside loop (%s, %d)" % \
227 (self.filename, node.lineno)
228 self.emit('SET_LINENO', node.lineno)
229 self.emit('BREAK_LOOP')
230
231 def visitContinue(self, node):
232 if not self.loops:
233 raise SyntaxError, "'continue' outside loop (%s, %d)" % \
234 (self.filename, node.lineno)
235 l = self.loops.top()
236 self.emit('SET_LINENO', node.lineno)
237 self.emit('JUMP_ABSOLUTE', l)
238 self.nextBlock()
239
240 def visitTest(self, node, jump):
241 end = self.newBlock()
242 for child in node.nodes[:-1]:
243 self.visit(child)
244 self.emit(jump, end)
245 self.nextBlock()
246 self.emit('POP_TOP')
247 self.visit(node.nodes[-1])
248 self.nextBlock(end)
249
250 def visitAnd(self, node):
251 self.visitTest(node, 'JUMP_IF_FALSE')
252
253 def visitOr(self, node):
254 self.visitTest(node, 'JUMP_IF_TRUE')
255
256 def visitCompare(self, node):
257 self.visit(node.expr)
258 cleanup = self.newBlock()
259 for op, code in node.ops[:-1]:
260 self.visit(code)
261 self.emit('DUP_TOP')
262 self.emit('ROT_THREE')
263 self.emit('COMPARE_OP', op)
264 self.emit('JUMP_IF_FALSE', cleanup)
265 self.nextBlock()
266 self.emit('POP_TOP')
267 # now do the last comparison
268 if node.ops:
269 op, code = node.ops[-1]
270 self.visit(code)
271 self.emit('COMPARE_OP', op)
272 if len(node.ops) > 1:
273 end = self.newBlock()
274 self.emit('JUMP_FORWARD', end)
275 self.nextBlock(cleanup)
276 self.emit('ROT_TWO')
277 self.emit('POP_TOP')
278 self.nextBlock(end)
279
280 # exception related
281
282 def visitAssert(self, node):
283 # XXX would be interesting to implement this via a
284 # transformation of the AST before this stage
285 end = self.newBlock()
286 self.emit('SET_LINENO', node.lineno)
287 # XXX __debug__ and AssertionError appear to be special cases
288 # -- they are always loaded as globals even if there are local
289 # names. I guess this is a sort of renaming op.
290 self.emit('LOAD_GLOBAL', '__debug__')
291 self.emit('JUMP_IF_FALSE', end)
292 self.nextBlock()
293 self.emit('POP_TOP')
294 self.visit(node.test)
295 self.emit('JUMP_IF_TRUE', end)
296 self.nextBlock()
297 self.emit('LOAD_GLOBAL', 'AssertionError')
298 self.visit(node.fail)
299 self.emit('RAISE_VARARGS', 2)
300 self.nextBlock(end)
301 self.emit('POP_TOP')
302
303 def visitRaise(self, node):
304 self.emit('SET_LINENO', node.lineno)
305 n = 0
306 if node.expr1:
307 self.visit(node.expr1)
308 n = n + 1
309 if node.expr2:
310 self.visit(node.expr2)
311 n = n + 1
312 if node.expr3:
313 self.visit(node.expr3)
314 n = n + 1
315 self.emit('RAISE_VARARGS', n)
316
317 def visitTryExcept(self, node):
318 handlers = self.newBlock()
319 end = self.newBlock()
320 if node.else_:
321 lElse = self.newBlock()
322 else:
323 lElse = end
324 self.emit('SET_LINENO', node.lineno)
325 self.emit('SETUP_EXCEPT', handlers)
326 self.visit(node.body)
327 self.emit('POP_BLOCK')
328 self.emit('JUMP_FORWARD', lElse)
329 self.nextBlock(handlers)
330
331 last = len(node.handlers) - 1
332 for i in range(len(node.handlers)):
333 expr, target, body = node.handlers[i]
334 if hasattr(expr, 'lineno'):
335 self.emit('SET_LINENO', expr.lineno)
336 if expr:
337 self.emit('DUP_TOP')
338 self.visit(expr)
339 self.emit('COMPARE_OP', 'exception match')
340 next = self.newBlock()
341 self.emit('JUMP_IF_FALSE', next)
342 self.nextBlock()
343 self.emit('POP_TOP')
344 self.emit('POP_TOP')
345 if target:
346 self.visit(target)
347 else:
348 self.emit('POP_TOP')
349 self.emit('POP_TOP')
350 self.visit(body)
351 self.emit('JUMP_FORWARD', end)
352 if expr:
353 self.nextBlock(next)
354 self.emit('POP_TOP')
355 self.emit('END_FINALLY')
356 if node.else_:
357 self.nextBlock(lElse)
358 self.visit(node.else_)
359 self.nextBlock(end)
360
361 def visitTryFinally(self, node):
362 final = self.newBlock()
363 self.emit('SET_LINENO', node.lineno)
364 self.emit('SETUP_FINALLY', final)
365 self.visit(node.body)
366 self.emit('POP_BLOCK')
367 self.emit('LOAD_CONST', None)
368 self.nextBlock(final)
369 self.visit(node.final)
370 self.emit('END_FINALLY')
371
372 # misc
373
374## def visitStmt(self, node):
375## # nothing to do except walk the children
376## pass
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000377
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000378 def visitDiscard(self, node):
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000379 self.visit(node.expr)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000380 self.emit('POP_TOP')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000381
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000382 def visitConst(self, node):
383 self.emit('LOAD_CONST', node.value)
384
385 def visitKeyword(self, node):
386 self.emit('LOAD_CONST', node.name)
387 self.visit(node.expr)
388
389 def visitGlobal(self, node):
390 # no code to generate
391 pass
392
393 def visitName(self, node):
394 self.loadName(node.name)
395
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000396 def visitPass(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000397 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000398
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000399 def visitImport(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000400 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000401 for name in node.names:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000402 self.emit('IMPORT_NAME', name)
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000403 self.storeName(name)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000404
405 def visitFrom(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000406 self.emit('SET_LINENO', node.lineno)
407 self.emit('IMPORT_NAME', node.modname)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000408 for name in node.names:
Jeremy Hylton126960b2000-02-14 21:33:10 +0000409 if name == '*':
410 self.namespace = 0
Jeremy Hyltona5058122000-02-14 14:14:29 +0000411 self.emit('IMPORT_FROM', name)
412 self.emit('POP_TOP')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000413
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000414 def visitGetattr(self, node):
415 self.visit(node.expr)
416 self.emit('LOAD_ATTR', node.attrname)
417
418 # next five implement assignments
419
420 def visitAssign(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000421 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000422 self.visit(node.expr)
423 dups = len(node.nodes) - 1
424 for i in range(len(node.nodes)):
425 elt = node.nodes[i]
426 if i < dups:
427 self.emit('DUP_TOP')
428 if isinstance(elt, ast.Node):
429 self.visit(elt)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000430
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000431 def visitAssName(self, node):
432 if node.flags == 'OP_ASSIGN':
433 self.storeName(node.name)
434 elif node.flags == 'OP_DELETE':
435 self.delName(node.name)
436 else:
437 print "oops", node.flags
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000438
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000439 def visitAssAttr(self, node):
440 self.visit(node.expr)
441 if node.flags == 'OP_ASSIGN':
442 self.emit('STORE_ATTR', node.attrname)
443 elif node.flags == 'OP_DELETE':
444 self.emit('DELETE_ATTR', node.attrname)
445 else:
446 print "warning: unexpected flags:", node.flags
447 print node
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000448
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000449 def visitAssTuple(self, node):
450 if findOp(node) != 'OP_DELETE':
451 self.emit('UNPACK_TUPLE', len(node.nodes))
452 for child in node.nodes:
453 self.visit(child)
454
455 visitAssList = visitAssTuple
456
457 def visitExec(self, node):
458 self.visit(node.expr)
459 if node.locals is None:
460 self.emit('LOAD_CONST', None)
461 else:
462 self.visit(node.locals)
463 if node.globals is None:
464 self.emit('DUP_TOP')
465 else:
466 self.visit(node.globals)
467 self.emit('EXEC_STMT')
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000468
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000469 def visitCallFunc(self, node):
Jeremy Hylton3050d512000-02-12 00:12:38 +0000470 pos = 0
471 kw = 0
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000472 if hasattr(node, 'lineno'):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000473 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000474 self.visit(node.node)
475 for arg in node.args:
476 self.visit(arg)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000477 if isinstance(arg, ast.Keyword):
478 kw = kw + 1
479 else:
480 pos = pos + 1
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000481 self.emit('CALL_FUNCTION', kw << 8 | pos)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000482
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000483 def visitPrint(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000484 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000485 for child in node.nodes:
486 self.visit(child)
487 self.emit('PRINT_ITEM')
488
489 def visitPrintnl(self, node):
490 self.visitPrint(node)
491 self.emit('PRINT_NEWLINE')
492
493 def visitReturn(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000494 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000495 self.visit(node.value)
496 self.emit('RETURN_VALUE')
Jeremy Hylton40245602000-02-08 21:15:48 +0000497
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000498 # slice and subscript stuff
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000499
500 def visitSlice(self, node):
501 self.visit(node.expr)
502 slice = 0
503 if node.lower:
504 self.visit(node.lower)
505 slice = slice | 1
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000506 if node.upper:
507 self.visit(node.upper)
508 slice = slice | 2
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000509 if node.flags == 'OP_APPLY':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000510 self.emit('SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000511 elif node.flags == 'OP_ASSIGN':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000512 self.emit('STORE_SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000513 elif node.flags == 'OP_DELETE':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000514 self.emit('DELETE_SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000515 else:
Jeremy Hylton4f6bcd82000-02-15 23:45:26 +0000516 print "weird slice", node.flags
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000517 raise
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000518
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000519 def visitSubscript(self, node):
Jeremy Hylton40245602000-02-08 21:15:48 +0000520 self.visit(node.expr)
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000521 for sub in node.subs:
522 self.visit(sub)
523 if len(node.subs) > 1:
524 self.emit('BUILD_TUPLE', len(node.subs))
525 if node.flags == 'OP_APPLY':
526 self.emit('BINARY_SUBSCR')
527 elif node.flags == 'OP_ASSIGN':
528 self.emit('STORE_SUBSCR')
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000529 elif node.flags == 'OP_DELETE':
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000530 self.emit('DELETE_SUBSCR')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000531
Jeremy Hylton7fab23e2000-03-06 19:10:54 +0000532 # binary ops
533
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000534 def binaryOp(self, node, op):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000535 self.visit(node.left)
536 self.visit(node.right)
537 self.emit(op)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000538
539 def visitAdd(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000540 return self.binaryOp(node, 'BINARY_ADD')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000541
542 def visitSub(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000543 return self.binaryOp(node, 'BINARY_SUBTRACT')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000544
545 def visitMul(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000546 return self.binaryOp(node, 'BINARY_MULTIPLY')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000547
548 def visitDiv(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000549 return self.binaryOp(node, 'BINARY_DIVIDE')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000550
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000551 def visitMod(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000552 return self.binaryOp(node, 'BINARY_MODULO')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000553
Jeremy Hylton126960b2000-02-14 21:33:10 +0000554 def visitPower(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000555 return self.binaryOp(node, 'BINARY_POWER')
Jeremy Hylton126960b2000-02-14 21:33:10 +0000556
557 def visitLeftShift(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000558 return self.binaryOp(node, 'BINARY_LSHIFT')
Jeremy Hylton126960b2000-02-14 21:33:10 +0000559
560 def visitRightShift(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000561 return self.binaryOp(node, 'BINARY_RSHIFT')
Jeremy Hylton126960b2000-02-14 21:33:10 +0000562
Jeremy Hylton7fab23e2000-03-06 19:10:54 +0000563 # unary ops
564
565 def unaryOp(self, node, op):
566 self.visit(node.expr)
567 self.emit(op)
Jeremy Hylton7fab23e2000-03-06 19:10:54 +0000568
Jeremy Hylton126960b2000-02-14 21:33:10 +0000569 def visitInvert(self, node):
570 return self.unaryOp(node, 'UNARY_INVERT')
571
Jeremy Hylton40245602000-02-08 21:15:48 +0000572 def visitUnarySub(self, node):
573 return self.unaryOp(node, 'UNARY_NEGATIVE')
574
575 def visitUnaryAdd(self, node):
576 return self.unaryOp(node, 'UNARY_POSITIVE')
577
578 def visitUnaryInvert(self, node):
579 return self.unaryOp(node, 'UNARY_INVERT')
580
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000581 def visitNot(self, node):
582 return self.unaryOp(node, 'UNARY_NOT')
583
Jeremy Hylton40245602000-02-08 21:15:48 +0000584 def visitBackquote(self, node):
585 return self.unaryOp(node, 'UNARY_CONVERT')
586
Jeremy Hylton7fab23e2000-03-06 19:10:54 +0000587 # bit ops
588
Jeremy Hyltona5058122000-02-14 14:14:29 +0000589 def bitOp(self, nodes, op):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000590 self.visit(nodes[0])
591 for node in nodes[1:]:
592 self.visit(node)
593 self.emit(op)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000594
595 def visitBitand(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000596 return self.bitOp(node.nodes, 'BINARY_AND')
Jeremy Hyltona5058122000-02-14 14:14:29 +0000597
598 def visitBitor(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000599 return self.bitOp(node.nodes, 'BINARY_OR')
Jeremy Hyltona5058122000-02-14 14:14:29 +0000600
601 def visitBitxor(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000602 return self.bitOp(node.nodes, 'BINARY_XOR')
Jeremy Hyltona5058122000-02-14 14:14:29 +0000603
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000604 # object constructors
Jeremy Hylton40245602000-02-08 21:15:48 +0000605
Jeremy Hyltona5058122000-02-14 14:14:29 +0000606 def visitEllipsis(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000607 self.emit('LOAD_CONST', Ellipsis)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000608
Jeremy Hylton40245602000-02-08 21:15:48 +0000609 def visitTuple(self, node):
610 for elt in node.nodes:
611 self.visit(elt)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000612 self.emit('BUILD_TUPLE', len(node.nodes))
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000613
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000614 def visitList(self, node):
615 for elt in node.nodes:
616 self.visit(elt)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000617 self.emit('BUILD_LIST', len(node.nodes))
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000618
619 def visitSliceobj(self, node):
620 for child in node.nodes:
621 self.visit(child)
622 self.emit('BUILD_SLICE', len(node.nodes))
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000623
Jeremy Hyltona5058122000-02-14 14:14:29 +0000624 def visitDict(self, node):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000625 # XXX is this a good general strategy? could it be done
626 # separately from the general visitor
627 lineno = getattr(node, 'lineno', None)
628 if lineno:
629 self.emit('SET_LINENO', lineno)
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000630 self.emit('BUILD_MAP', 0)
631 for k, v in node.items:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000632 lineno2 = getattr(node, 'lineno', None)
633 if lineno != lineno2:
634 self.emit('SET_LINENO', lineno2)
635 lineno = lineno2
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000636 self.emit('DUP_TOP')
637 self.visit(v)
638 self.emit('ROT_TWO')
639 self.visit(k)
640 self.emit('STORE_SUBSCR')
Jeremy Hyltona5058122000-02-14 14:14:29 +0000641
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000642class ModuleCodeGenerator(CodeGenerator):
643 super_init = CodeGenerator.__init__
644
645 def __init__(self, filename):
646 # XXX <module> is ? in compile.c
647 self.graph = pyassem.PyFlowGraph("<module>", filename)
648 self.super_init(filename)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000649
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000650class FunctionCodeGenerator(CodeGenerator):
651 super_init = CodeGenerator.__init__
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000652
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000653 optimized = 1
654 lambdaCount = 0
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000655
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000656 def __init__(self, func, filename, isLambda=0):
657 if isLambda:
658 klass = FunctionCodeGenerator
659 name = "<lambda.%d>" % klass.lambdaCount
660 klass.lambdaCount = klass.lambdaCount + 1
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000661 else:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000662 name = func.name
663 args, hasTupleArg = generateArgList(func.argnames)
664 self.graph = pyassem.PyFlowGraph(name, filename, args,
665 optimized=1)
666 self.isLambda = isLambda
667 self.super_init(filename)
668
669 lnf = walk(func.code, LocalNameFinder(args), 0)
670 self.locals.push(lnf.getLocals())
671 if func.varargs:
672 self.graph.setFlag(CO_VARARGS)
673 if func.kwargs:
674 self.graph.setFlag(CO_VARKEYWORDS)
675 self.emit('SET_LINENO', func.lineno)
676 if hasTupleArg:
677 self.generateArgUnpack(func.argnames)
678
679 def finish(self):
680 self.graph.startExitBlock()
681 if not self.isLambda:
682 self.emit('LOAD_CONST', None)
683 self.emit('RETURN_VALUE')
684
685 def generateArgUnpack(self, args):
686 count = 0
687 for arg in args:
688 if type(arg) == types.TupleType:
689 self.emit('LOAD_FAST', '.nested%d' % count)
690 count = count + 1
691 self.unpackTuple(arg)
692
693 def unpackTuple(self, tup):
694 self.emit('UNPACK_TUPLE', len(tup))
695 for elt in tup:
696 if type(elt) == types.TupleType:
697 self.unpackTuple(elt)
698 else:
699 self.emit('STORE_FAST', elt)
700
701class ClassCodeGenerator(CodeGenerator):
702 super_init = CodeGenerator.__init__
703
704 def __init__(self, klass, filename):
705 self.graph = pyassem.PyFlowGraph(klass.name, filename,
706 optimized=0)
707 self.super_init(filename)
708 lnf = walk(klass.code, LocalNameFinder(), 0)
709 self.locals.push(lnf.getLocals())
710
711 def finish(self):
712 self.graph.startExitBlock()
713 self.emit('LOAD_LOCALS')
714 self.emit('RETURN_VALUE')
715
716
717def generateArgList(arglist):
718 """Generate an arg list marking TupleArgs"""
719 args = []
720 extra = []
721 count = 0
722 for elt in arglist:
723 if type(elt) == types.StringType:
724 args.append(elt)
725 elif type(elt) == types.TupleType:
726 args.append(TupleArg(count, elt))
727 count = count + 1
728 extra.extend(misc.flatten(elt))
729 else:
730 raise ValueError, "unexpect argument type:", elt
731 return args + extra, count
Jeremy Hyltona5058122000-02-14 14:14:29 +0000732
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000733class LocalNameFinder:
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000734 """Find local names in scope"""
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000735 def __init__(self, names=()):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000736 self.names = misc.Set()
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000737 self.globals = misc.Set()
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000738 for name in names:
739 self.names.add(name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000740
741 def getLocals(self):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000742 for elt in self.globals.elements():
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000743 if self.names.has_elt(elt):
744 self.names.remove(elt)
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000745 return self.names
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000746
Jeremy Hyltona5058122000-02-14 14:14:29 +0000747 def visitDict(self, node):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000748 pass
Jeremy Hyltona5058122000-02-14 14:14:29 +0000749
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000750 def visitGlobal(self, node):
751 for name in node.names:
752 self.globals.add(name)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000753
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000754 def visitFunction(self, node):
755 self.names.add(node.name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000756
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000757 def visitLambda(self, node):
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000758 pass
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000759
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000760 def visitImport(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000761 for name in node.names:
762 self.names.add(name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000763
764 def visitFrom(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000765 for name in node.names:
766 self.names.add(name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000767
Jeremy Hylton7fab23e2000-03-06 19:10:54 +0000768 def visitClass(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000769 self.names.add(node.name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000770
771 def visitAssName(self, node):
Jeremy Hylton873bdc12000-02-17 17:56:29 +0000772 self.names.add(node.name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000773
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000774def findOp(node):
775 """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
776 v = OpFinder()
777 walk(node, v, 0)
778 return v.op
779
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000780class OpFinder:
781 def __init__(self):
782 self.op = None
783 def visitAssName(self, node):
784 if self.op is None:
785 self.op = node.flags
786 elif self.op != node.flags:
787 raise ValueError, "mixed ops in stmt"
788
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000789if __name__ == "__main__":
790 import sys
Jeremy Hylton3ec7e2c2000-02-17 22:09:35 +0000791
Jeremy Hylton36cc6a22000-03-16 20:06:59 +0000792 for file in sys.argv[1:]:
793 compile(file)