blob: 4f8d8247ce706558157f1a8a550d42b24ce42838 [file] [log] [blame]
Jeremy Hylton8b6323d2000-02-04 00:28:21 +00001"""Python bytecode generator
2
3Currently contains generic ASTVisitor code, a LocalNameFinder, and a
4CodeGenerator. Eventually, this will get split into the ASTVisitor as
5a generic tool and CodeGenerator as a specific tool.
6"""
7
8from p2c import transformer, ast
Jeremy Hyltona5058122000-02-14 14:14:29 +00009from pyassem import StackRef, PyAssembler
Jeremy Hylton8b6323d2000-02-04 00:28:21 +000010import dis
11import misc
Jeremy Hylton0fdffcf2000-02-04 19:37:35 +000012import marshal
13import new
14import string
Jeremy Hylton53187f32000-02-08 19:01:29 +000015import sys
16import os
17import stat
18import struct
Jeremy Hylton8b6323d2000-02-04 00:28:21 +000019
20def parse(path):
21 f = open(path)
22 src = f.read()
23 f.close()
24 t = transformer.Transformer()
25 return t.parsesuite(src)
26
Jeremy Hylton5e0ce532000-02-10 00:47:08 +000027def walk(tree, visitor, verbose=None, walker=None):
Jeremy Hylton5e0ce532000-02-10 00:47:08 +000028 if walker:
29 w = walker()
30 else:
31 w = ASTVisitor()
Jeremy Hylton40245602000-02-08 21:15:48 +000032 if verbose is not None:
33 w.VERBOSE = verbose
Jeremy Hylton8b6323d2000-02-04 00:28:21 +000034 w.preorder(tree, visitor)
35 return w.visitor
36
Jeremy Hylton5e0ce532000-02-10 00:47:08 +000037def dumpNode(node):
38 print node.__class__
39 for attr in dir(node):
40 if attr[0] != '_':
41 print "\t", "%-10.10s" % attr, getattr(node, attr)
42
Jeremy Hylton8b6323d2000-02-04 00:28:21 +000043class ASTVisitor:
44 """Performs a depth-first walk of the AST
45
46 The ASTVisitor will walk the AST, performing either a preorder or
47 postorder traversal depending on which method is called.
48
49 methods:
50 preorder(tree, visitor)
51 postorder(tree, visitor)
52 tree: an instance of ast.Node
53 visitor: an instance with visitXXX methods
54
55 The ASTVisitor is responsible for walking over the tree in the
56 correct order. For each node, it checks the visitor argument for
57 a method named 'visitNodeType' where NodeType is the name of the
58 node's class, e.g. Classdef. If the method exists, it is called
59 with the node as its sole argument.
60
61 The visitor method for a particular node type can control how
62 child nodes are visited during a preorder walk. (It can't control
63 the order during a postorder walk, because it is called _after_
64 the walk has occurred.) The ASTVisitor modifies the visitor
65 argument by adding a visit method to the visitor; this method can
66 be used to visit a particular child node. If the visitor method
67 returns a true value, the ASTVisitor will not traverse the child
68 nodes.
69
70 XXX The interface for controlling the preorder walk needs to be
71 re-considered. The current interface is convenient for visitors
72 that mostly let the ASTVisitor do everything. For something like
73 a code generator, where you want to walk to occur in a specific
74 order, it's a pain to add "return 1" to the end of each method.
75
76 XXX Perhaps I can use a postorder walk for the code generator?
77 """
78
Jeremy Hylton40245602000-02-08 21:15:48 +000079 VERBOSE = 0
Jeremy Hylton8b6323d2000-02-04 00:28:21 +000080
81 def __init__(self):
82 self.node = None
83
84 def preorder(self, tree, visitor):
85 """Do preorder walk of tree using visitor"""
86 self.visitor = visitor
87 visitor.visit = self._preorder
88 self._preorder(tree)
89
90 def _preorder(self, node):
91 stop = self.dispatch(node)
92 if stop:
93 return
94 for child in node.getChildren():
95 if isinstance(child, ast.Node):
96 self._preorder(child)
97
98 def postorder(self, tree, visitor):
99 """Do preorder walk of tree using visitor"""
100 self.visitor = visitor
101 visitor.visit = self._postorder
102 self._postorder(tree)
103
104 def _postorder(self, tree):
105 for child in node.getChildren():
106 if isinstance(child, ast.Node):
107 self._preorder(child)
108 self.dispatch(node)
109
110 def dispatch(self, node):
111 self.node = node
112 className = node.__class__.__name__
113 meth = getattr(self.visitor, 'visit' + className, None)
Jeremy Hylton40245602000-02-08 21:15:48 +0000114 if self.VERBOSE > 0:
115 if self.VERBOSE == 1:
116 if meth is None:
117 print "dispatch", className
118 else:
119 print "dispatch", className, (meth and meth.__name__ or '')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000120 if meth:
121 return meth(node)
122
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000123class ExampleASTVisitor(ASTVisitor):
Jeremy Hylton9e1cd682000-02-14 23:57:56 +0000124 """Prints examples of the nodes that aren't visited
125
126 This visitor-driver is only useful for development, when it's
127 helpful to develop a visitor incremently, and get feedback on what
128 you still have to do.
129 """
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000130 examples = {}
131
132 def dispatch(self, node):
133 self.node = node
134 className = node.__class__.__name__
135 meth = getattr(self.visitor, 'visit' + className, None)
136 if self.VERBOSE > 0:
137 if self.VERBOSE == 1:
138 if meth is None:
139 print "dispatch", className
140 else:
141 print "dispatch", className, (meth and meth.__name__ or '')
142 if meth:
143 return meth(node)
144 else:
145 klass = node.__class__
146 if self.VERBOSE < 2:
147 if self.examples.has_key(klass):
148 return
149 self.examples[klass] = klass
150 print
151 print klass
152 for attr in dir(node):
153 if attr[0] != '_':
154 print "\t", "%-12.12s" % attr, getattr(node, attr)
155 print
156
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000157class CodeGenerator:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000158 """TODO
159
160 EmptyNode
Jeremy Hyltona5058122000-02-14 14:14:29 +0000161 Sliceobj
162 Tryexcept
163 Tryfinally
164 """
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000165
Jeremy Hylton3050d512000-02-12 00:12:38 +0000166 OPTIMIZED = 1
167
Jeremy Hyltona5058122000-02-14 14:14:29 +0000168 # XXX should clean up initialization and generateXXX funcs
Jeremy Hylton3050d512000-02-12 00:12:38 +0000169 def __init__(self, filename="<?>"):
Jeremy Hylton53187f32000-02-08 19:01:29 +0000170 self.filename = filename
Jeremy Hyltona5058122000-02-14 14:14:29 +0000171 self.code = PyAssembler()
Jeremy Hylton53187f32000-02-08 19:01:29 +0000172 self.code.setFlags(0)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000173 self.locals = misc.Stack()
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000174 self.loops = misc.Stack()
Jeremy Hylton3050d512000-02-12 00:12:38 +0000175 self.namespace = 0
Jeremy Hylton53187f32000-02-08 19:01:29 +0000176 self.curStack = 0
177 self.maxStack = 0
178
Jeremy Hyltona5058122000-02-14 14:14:29 +0000179 def emit(self, *args):
180 # XXX could just use self.emit = self.code.emit
181 apply(self.code.emit, args)
182
Jeremy Hylton3050d512000-02-12 00:12:38 +0000183 def _generateFunctionOrLambdaCode(self, func):
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000184 self.name = func.name
185 self.filename = filename
186 args = func.argnames
Jeremy Hyltona5058122000-02-14 14:14:29 +0000187 self.code = PyAssembler(args=args, name=func.name,
Jeremy Hylton3050d512000-02-12 00:12:38 +0000188 filename=filename)
189 self.namespace = self.OPTIMIZED
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000190 if func.varargs:
191 self.code.setVarArgs()
192 if func.kwargs:
193 self.code.setKWArgs()
194 lnf = walk(func.code, LocalNameFinder(args), 0)
195 self.locals.push(lnf.getLocals())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000196 self.emit('SET_LINENO', func.lineno)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000197 walk(func.code, self)
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000198
Jeremy Hylton3050d512000-02-12 00:12:38 +0000199 def generateFunctionCode(self, func):
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000200 """Generate code for a function body"""
Jeremy Hylton3050d512000-02-12 00:12:38 +0000201 self._generateFunctionOrLambdaCode(func)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000202 self.emit('LOAD_CONST', None)
203 self.emit('RETURN_VALUE')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000204
Jeremy Hylton3050d512000-02-12 00:12:38 +0000205 def generateLambdaCode(self, func):
206 self._generateFunctionOrLambdaCode(func)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000207 self.emit('RETURN_VALUE')
Jeremy Hylton3050d512000-02-12 00:12:38 +0000208
209 def generateClassCode(self, klass):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000210 self.code = PyAssembler(name=klass.name,
Jeremy Hylton3050d512000-02-12 00:12:38 +0000211 filename=filename)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000212 self.emit('SET_LINENO', klass.lineno)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000213 lnf = walk(klass.code, LocalNameFinder(), 0)
214 self.locals.push(lnf.getLocals())
215 walk(klass.code, self)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000216 self.emit('LOAD_LOCALS')
217 self.emit('RETURN_VALUE')
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000218
Jeremy Hyltona5058122000-02-14 14:14:29 +0000219 def asConst(self):
220 """Create a Python code object."""
Jeremy Hylton3050d512000-02-12 00:12:38 +0000221 if self.namespace == self.OPTIMIZED:
222 self.code.setOptimized()
Jeremy Hyltona5058122000-02-14 14:14:29 +0000223 return self.code.makeCodeObject()
Jeremy Hylton53187f32000-02-08 19:01:29 +0000224
Jeremy Hylton40245602000-02-08 21:15:48 +0000225 def isLocalName(self, name):
226 return self.locals.top().has_elt(name)
227
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000228 def _nameOp(self, prefix, name):
229 if self.isLocalName(name):
Jeremy Hylton3050d512000-02-12 00:12:38 +0000230 if self.namespace == self.OPTIMIZED:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000231 self.emit(prefix + '_FAST', name)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000232 else:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000233 self.emit(prefix + '_NAME', name)
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000234 else:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000235 self.emit(prefix + '_GLOBAL', name)
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000236
237 def storeName(self, name):
238 self._nameOp('STORE', name)
239
240 def loadName(self, name):
241 self._nameOp('LOAD', name)
242
243 def delName(self, name):
244 self._nameOp('DELETE', name)
245
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000246 def visitNULL(self, node):
247 """Method exists only to stop warning in -v mode"""
248 pass
249
250 visitStmt = visitNULL
251 visitGlobal = visitNULL
252
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000253 def visitDiscard(self, node):
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000254 self.visit(node.expr)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000255 self.emit('POP_TOP')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000256 return 1
257
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000258 def visitPass(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000259 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000260
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000261 def visitModule(self, node):
Jeremy Hylton40245602000-02-08 21:15:48 +0000262 lnf = walk(node.node, LocalNameFinder(), 0)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000263 self.locals.push(lnf.getLocals())
Jeremy Hylton0fdffcf2000-02-04 19:37:35 +0000264 self.visit(node.node)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000265 self.emit('LOAD_CONST', None)
266 self.emit('RETURN_VALUE')
Jeremy Hylton0fdffcf2000-02-04 19:37:35 +0000267 return 1
268
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000269 def visitImport(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000270 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000271 for name in node.names:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000272 self.emit('IMPORT_NAME', name)
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000273 self.storeName(name)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000274
275 def visitFrom(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000276 self.emit('SET_LINENO', node.lineno)
277 self.emit('IMPORT_NAME', node.modname)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000278 for name in node.names:
Jeremy Hylton126960b2000-02-14 21:33:10 +0000279 if name == '*':
280 self.namespace = 0
Jeremy Hyltona5058122000-02-14 14:14:29 +0000281 self.emit('IMPORT_FROM', name)
282 self.emit('POP_TOP')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000283
Jeremy Hylton3050d512000-02-12 00:12:38 +0000284 def visitClassdef(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000285 self.emit('SET_LINENO', node.lineno)
286 self.emit('LOAD_CONST', node.name)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000287 for base in node.bases:
288 self.visit(base)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000289 self.emit('BUILD_TUPLE', len(node.bases))
Jeremy Hylton3050d512000-02-12 00:12:38 +0000290 classBody = CodeGenerator(self.filename)
291 classBody.generateClassCode(node)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000292 self.emit('LOAD_CONST', classBody)
293 self.emit('MAKE_FUNCTION', 0)
294 self.emit('CALL_FUNCTION', 0)
295 self.emit('BUILD_CLASS')
Jeremy Hylton3050d512000-02-12 00:12:38 +0000296 self.storeName(node.name)
297 return 1
298
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000299 def _visitFuncOrLambda(self, node, kind):
300 """Code common to Function and Lambda nodes"""
Jeremy Hylton3050d512000-02-12 00:12:38 +0000301 codeBody = CodeGenerator(self.filename)
302 getattr(codeBody, 'generate%sCode' % kind)(node)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000303 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000304 for default in node.defaults:
305 self.visit(default)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000306 self.emit('LOAD_CONST', codeBody)
307 self.emit('MAKE_FUNCTION', len(node.defaults))
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000308
309 def visitFunction(self, node):
310 self._visitFuncOrLambda(node, 'Function')
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000311 self.storeName(node.name)
Jeremy Hylton0fdffcf2000-02-04 19:37:35 +0000312 return 1
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000313
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000314 def visitLambda(self, node):
315 node.name = '<lambda>'
316 node.varargs = node.kwargs = None
317 self._visitFuncOrLambda(node, 'Lambda')
318 return 1
319
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000320 def visitCallFunc(self, node):
Jeremy Hylton3050d512000-02-12 00:12:38 +0000321 pos = 0
322 kw = 0
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000323 if hasattr(node, 'lineno'):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000324 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000325 self.visit(node.node)
326 for arg in node.args:
327 self.visit(arg)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000328 if isinstance(arg, ast.Keyword):
329 kw = kw + 1
330 else:
331 pos = pos + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000332 self.emit('CALL_FUNCTION', kw << 8 | pos)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000333 return 1
334
Jeremy Hylton3050d512000-02-12 00:12:38 +0000335 def visitKeyword(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000336 self.emit('LOAD_CONST', node.name)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000337 self.visit(node.expr)
338 return 1
339
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000340 def visitIf(self, node):
Jeremy Hylton40245602000-02-08 21:15:48 +0000341 after = StackRef()
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000342 for test, suite in node.tests:
Jeremy Hylton40245602000-02-08 21:15:48 +0000343 if hasattr(test, 'lineno'):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000344 self.emit('SET_LINENO', test.lineno)
Jeremy Hylton40245602000-02-08 21:15:48 +0000345 else:
346 print "warning", "no line number"
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000347 self.visit(test)
Jeremy Hylton40245602000-02-08 21:15:48 +0000348 dest = StackRef()
Jeremy Hyltona5058122000-02-14 14:14:29 +0000349 self.emit('JUMP_IF_FALSE', dest)
350 self.emit('POP_TOP')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000351 self.visit(suite)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000352 self.emit('JUMP_FORWARD', after)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000353 dest.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000354 self.emit('POP_TOP')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000355 if node.else_:
356 self.visit(node.else_)
357 after.bind(self.code.getCurInst())
358 return 1
359
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000360 def startLoop(self):
361 l = Loop()
362 self.loops.push(l)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000363 self.emit('SETUP_LOOP', l.extentAnchor)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000364 return l
365
366 def finishLoop(self):
367 l = self.loops.pop()
368 i = self.code.getCurInst()
369 l.extentAnchor.bind(self.code.getCurInst())
370
Jeremy Hylton40245602000-02-08 21:15:48 +0000371 def visitFor(self, node):
372 # three refs needed
Jeremy Hylton40245602000-02-08 21:15:48 +0000373 anchor = StackRef()
Jeremy Hylton40245602000-02-08 21:15:48 +0000374
Jeremy Hyltona5058122000-02-14 14:14:29 +0000375 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000376 l = self.startLoop()
Jeremy Hylton40245602000-02-08 21:15:48 +0000377 self.visit(node.list)
378 self.visit(ast.Const(0))
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000379 l.startAnchor.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000380 self.emit('SET_LINENO', node.lineno)
381 self.emit('FOR_LOOP', anchor)
Jeremy Hylton40245602000-02-08 21:15:48 +0000382 self.visit(node.assign)
383 self.visit(node.body)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000384 self.emit('JUMP_ABSOLUTE', l.startAnchor)
Jeremy Hylton40245602000-02-08 21:15:48 +0000385 anchor.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000386 self.emit('POP_BLOCK')
Jeremy Hylton40245602000-02-08 21:15:48 +0000387 if node.else_:
388 self.visit(node.else_)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000389 self.finishLoop()
Jeremy Hylton40245602000-02-08 21:15:48 +0000390 return 1
391
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000392 def visitWhile(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000393 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000394 l = self.startLoop()
395 if node.else_:
396 lElse = StackRef()
397 else:
398 lElse = l.breakAnchor
399 l.startAnchor.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000400 self.emit('SET_LINENO', node.test.lineno)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000401 self.visit(node.test)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000402 self.emit('JUMP_IF_FALSE', lElse)
403 self.emit('POP_TOP')
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000404 self.visit(node.body)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000405 self.emit('JUMP_ABSOLUTE', l.startAnchor)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000406 # note that lElse may be an alias for l.breakAnchor
407 lElse.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000408 self.emit('POP_TOP')
409 self.emit('POP_BLOCK')
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000410 if node.else_:
411 self.visit(node.else_)
412 self.finishLoop()
413 return 1
414
415 def visitBreak(self, node):
416 if not self.loops:
417 raise SyntaxError, "'break' outside loop"
Jeremy Hyltona5058122000-02-14 14:14:29 +0000418 self.emit('SET_LINENO', node.lineno)
419 self.emit('BREAK_LOOP')
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000420
421 def visitContinue(self, node):
422 if not self.loops:
423 raise SyntaxError, "'continue' outside loop"
424 l = self.loops.top()
Jeremy Hyltona5058122000-02-14 14:14:29 +0000425 self.emit('SET_LINENO', node.lineno)
426 self.emit('JUMP_ABSOLUTE', l.startAnchor)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000427
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000428 def visitCompare(self, node):
429 """Comment from compile.c follows:
430
431 The following code is generated for all but the last
432 comparison in a chain:
433
434 label: on stack: opcode: jump to:
435
436 a <code to load b>
437 a, b DUP_TOP
438 a, b, b ROT_THREE
439 b, a, b COMPARE_OP
440 b, 0-or-1 JUMP_IF_FALSE L1
441 b, 1 POP_TOP
442 b
443
444 We are now ready to repeat this sequence for the next
445 comparison in the chain.
446
447 For the last we generate:
448
449 b <code to load c>
450 b, c COMPARE_OP
451 0-or-1
452
453 If there were any jumps to L1 (i.e., there was more than one
454 comparison), we generate:
455
456 0-or-1 JUMP_FORWARD L2
457 L1: b, 0 ROT_TWO
458 0, b POP_TOP
459 0
460 L2: 0-or-1
461 """
462 self.visit(node.expr)
463 # if refs are never emitted, subsequent bind call has no effect
Jeremy Hylton40245602000-02-08 21:15:48 +0000464 l1 = StackRef()
465 l2 = StackRef()
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000466 for op, code in node.ops[:-1]:
467 # emit every comparison except the last
468 self.visit(code)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000469 self.emit('DUP_TOP')
470 self.emit('ROT_THREE')
471 self.emit('COMPARE_OP', op)
Jeremy Hylton40245602000-02-08 21:15:48 +0000472 # dupTop and compareOp cancel stack effect
Jeremy Hyltona5058122000-02-14 14:14:29 +0000473 self.emit('JUMP_IF_FALSE', l1)
474 self.emit('POP_TOP')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000475 if node.ops:
476 # emit the last comparison
477 op, code = node.ops[-1]
478 self.visit(code)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000479 self.emit('COMPARE_OP', op)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000480 if len(node.ops) > 1:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000481 self.emit('JUMP_FORWARD', l2)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000482 l1.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000483 self.emit('ROT_TWO')
484 self.emit('POP_TOP')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000485 l2.bind(self.code.getCurInst())
486 return 1
487
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000488 def visitGetattr(self, node):
489 self.visit(node.expr)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000490 self.emit('LOAD_ATTR', node.attrname)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000491 return 1
492
493 def visitSubscript(self, node):
494 self.visit(node.expr)
495 for sub in node.subs[:-1]:
496 self.visit(sub)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000497 self.emit('BINARY_SUBSCR')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000498 self.visit(node.subs[-1])
499 if node.flags == 'OP_APPLY':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000500 self.emit('BINARY_SUBSCR')
501 elif node.flags == 'OP_ASSIGN':
502 self.emit('STORE_SUBSCR')
503 elif node.flags == 'OP_DELETE':
504 self.emit('DELETE_SUBSCR')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000505
506 return 1
507
508 def visitSlice(self, node):
509 self.visit(node.expr)
510 slice = 0
511 if node.lower:
512 self.visit(node.lower)
513 slice = slice | 1
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000514 if node.upper:
515 self.visit(node.upper)
516 slice = slice | 2
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000517 if node.flags == 'OP_APPLY':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000518 self.emit('SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000519 elif node.flags == 'OP_ASSIGN':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000520 self.emit('STORE_SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000521 elif node.flags == 'OP_DELETE':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000522 self.emit('DELETE_SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000523 else:
524 print node.flags
525 raise
526 return 1
527
Jeremy Hylton40245602000-02-08 21:15:48 +0000528 def visitAssign(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000529 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton40245602000-02-08 21:15:48 +0000530 self.visit(node.expr)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000531 dups = len(node.nodes) - 1
532 for i in range(len(node.nodes)):
533 elt = node.nodes[i]
534 if i < dups:
535 self.emit('DUP_TOP')
Jeremy Hylton40245602000-02-08 21:15:48 +0000536 if isinstance(elt, ast.Node):
537 self.visit(elt)
538 return 1
539
540 def visitAssName(self, node):
541 if node.flags != 'OP_ASSIGN':
542 print "oops", node.flags
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000543 self.storeName(node.name)
Jeremy Hylton40245602000-02-08 21:15:48 +0000544
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000545 def visitAssAttr(self, node):
546 if node.flags != 'OP_ASSIGN':
547 print "warning: unexpected flags:", node.flags
548 print node
549 self.visit(node.expr)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000550 self.emit('STORE_ATTR', node.attrname)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000551 return 1
552
553 def visitAssTuple(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000554 self.emit('UNPACK_TUPLE', len(node.nodes))
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000555 for child in node.nodes:
556 self.visit(child)
557 return 1
558
559 visitAssList = visitAssTuple
560
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000561 def binaryOp(self, node, op):
562 self.visit(node.left)
563 self.visit(node.right)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000564 self.emit(op)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000565 return 1
566
Jeremy Hylton40245602000-02-08 21:15:48 +0000567 def unaryOp(self, node, op):
568 self.visit(node.expr)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000569 self.emit(op)
Jeremy Hylton40245602000-02-08 21:15:48 +0000570 return 1
571
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000572 def visitAdd(self, node):
573 return self.binaryOp(node, 'BINARY_ADD')
574
575 def visitSub(self, node):
576 return self.binaryOp(node, 'BINARY_SUBTRACT')
577
578 def visitMul(self, node):
579 return self.binaryOp(node, 'BINARY_MULTIPLY')
580
581 def visitDiv(self, node):
582 return self.binaryOp(node, 'BINARY_DIVIDE')
583
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000584 def visitMod(self, node):
585 return self.binaryOp(node, 'BINARY_MODULO')
586
Jeremy Hylton126960b2000-02-14 21:33:10 +0000587 def visitPower(self, node):
588 return self.binaryOp(node, 'BINARY_POWER')
589
590 def visitLeftShift(self, node):
591 return self.binaryOp(node, 'BINARY_LSHIFT')
592
593 def visitRightShift(self, node):
594 return self.binaryOp(node, 'BINARY_RSHIFT')
595
596 def visitInvert(self, node):
597 return self.unaryOp(node, 'UNARY_INVERT')
598
Jeremy Hylton40245602000-02-08 21:15:48 +0000599 def visitUnarySub(self, node):
600 return self.unaryOp(node, 'UNARY_NEGATIVE')
601
602 def visitUnaryAdd(self, node):
603 return self.unaryOp(node, 'UNARY_POSITIVE')
604
605 def visitUnaryInvert(self, node):
606 return self.unaryOp(node, 'UNARY_INVERT')
607
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000608 def visitNot(self, node):
609 return self.unaryOp(node, 'UNARY_NOT')
610
Jeremy Hylton40245602000-02-08 21:15:48 +0000611 def visitBackquote(self, node):
612 return self.unaryOp(node, 'UNARY_CONVERT')
613
Jeremy Hyltona5058122000-02-14 14:14:29 +0000614 def bitOp(self, nodes, op):
615 self.visit(nodes[0])
616 for node in nodes[1:]:
617 self.visit(node)
618 self.emit(op)
619 return 1
620
621 def visitBitand(self, node):
622 return self.bitOp(node.nodes, 'BINARY_AND')
623
624 def visitBitor(self, node):
625 return self.bitOp(node.nodes, 'BINARY_OR')
626
627 def visitBitxor(self, node):
628 return self.bitOp(node.nodes, 'BINARY_XOR')
629
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000630 def visitTest(self, node, jump):
631 end = StackRef()
632 for child in node.nodes[:-1]:
633 self.visit(child)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000634 self.emit(jump, end)
635 self.emit('POP_TOP')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000636 self.visit(node.nodes[-1])
637 end.bind(self.code.getCurInst())
638 return 1
639
Jeremy Hyltona5058122000-02-14 14:14:29 +0000640 def visitAssert(self, node):
641 # XXX __debug__ and AssertionError appear to be special cases
642 # -- they are always loaded as globals even if there are local
643 # names. I guess this is a sort of renaming op.
644 skip = StackRef()
645 self.emit('SET_LINENO', node.lineno)
646 self.emit('LOAD_GLOBAL', '__debug__')
647 self.emit('JUMP_IF_FALSE', skip)
648 self.emit('POP_TOP')
649 self.visit(node.test)
650 self.emit('JUMP_IF_TRUE', skip)
651 self.emit('LOAD_GLOBAL', 'AssertionError')
652 self.visit(node.fail)
653 self.emit('RAISE_VARARGS', 2)
654 skip.bind(self.code.getCurInst())
655 self.emit('POP_TOP')
656 return 1
657
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000658 def visitAnd(self, node):
659 return self.visitTest(node, 'JUMP_IF_FALSE')
660
661 def visitOr(self, node):
662 return self.visitTest(node, 'JUMP_IF_TRUE')
663
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000664 def visitName(self, node):
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000665 self.loadName(node.name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000666
667 def visitConst(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000668 self.emit('LOAD_CONST', node.value)
Jeremy Hylton40245602000-02-08 21:15:48 +0000669 return 1
670
Jeremy Hyltona5058122000-02-14 14:14:29 +0000671 def visitEllipsis(self, node):
672 self.emit('LOAD_CONST', Ellipsis)
673 return 1
674
Jeremy Hylton40245602000-02-08 21:15:48 +0000675 def visitTuple(self, node):
676 for elt in node.nodes:
677 self.visit(elt)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000678 self.emit('BUILD_TUPLE', len(node.nodes))
Jeremy Hylton40245602000-02-08 21:15:48 +0000679 return 1
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000680
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000681 def visitList(self, node):
682 for elt in node.nodes:
683 self.visit(elt)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000684 self.emit('BUILD_LIST', len(node.nodes))
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000685 return 1
686
Jeremy Hyltona5058122000-02-14 14:14:29 +0000687 def visitDict(self, node):
688 self.emit('BUILD_MAP', 0)
689 for k, v in node.items:
690 # XXX need to add set lineno when there aren't constants
691 self.emit('DUP_TOP')
692 self.visit(v)
693 self.emit('ROT_TWO')
694 self.visit(k)
695 self.emit('STORE_SUBSCR')
696 return 1
697
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000698 def visitReturn(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000699 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000700 self.visit(node.value)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000701 self.emit('RETURN_VALUE')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000702 return 1
703
704 def visitRaise(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000705 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000706 n = 0
707 if node.expr1:
708 self.visit(node.expr1)
709 n = n + 1
710 if node.expr2:
711 self.visit(node.expr2)
712 n = n + 1
713 if node.expr3:
714 self.visit(node.expr3)
715 n = n + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000716 self.emit('RAISE_VARARGS', n)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000717 return 1
718
719 def visitPrint(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000720 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000721 for child in node.nodes:
722 self.visit(child)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000723 self.emit('PRINT_ITEM')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000724 return 1
725
726 def visitPrintnl(self, node):
727 self.visitPrint(node)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000728 self.emit('PRINT_NEWLINE')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000729 return 1
Jeremy Hylton0fdffcf2000-02-04 19:37:35 +0000730
Jeremy Hyltona5058122000-02-14 14:14:29 +0000731 def visitExec(self, node):
732 self.visit(node.expr)
733 if node.locals is None:
734 self.emit('LOAD_CONST', None)
735 else:
736 self.visit(node.locals)
737 if node.globals is None:
738 self.emit('DUP_TOP')
739 else:
740 self.visit(node.globals)
741 self.emit('EXEC_STMT')
742
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000743class LocalNameFinder:
744 def __init__(self, names=()):
745 self.names = misc.Set()
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000746 self.globals = misc.Set()
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000747 for name in names:
748 self.names.add(name)
749
750 def getLocals(self):
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000751 for elt in self.globals.items():
752 if self.names.has_elt(elt):
753 self.names.remove(elt)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000754 return self.names
755
Jeremy Hyltona5058122000-02-14 14:14:29 +0000756 def visitDict(self, node):
757 return 1
758
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000759 def visitGlobal(self, node):
760 for name in node.names:
761 self.globals.add(name)
762 return 1
763
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000764 def visitFunction(self, node):
765 self.names.add(node.name)
766 return 1
767
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000768 def visitLambda(self, node):
769 return 1
770
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000771 def visitImport(self, node):
772 for name in node.names:
773 self.names.add(name)
774
775 def visitFrom(self, node):
776 for name in node.names:
777 self.names.add(name)
778
779 def visitClassdef(self, node):
780 self.names.add(node.name)
781 return 1
782
783 def visitAssName(self, node):
784 self.names.add(node.name)
785
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000786class Loop:
787 def __init__(self):
788 self.startAnchor = StackRef()
789 self.breakAnchor = StackRef()
790 self.extentAnchor = StackRef()
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000791
Jeremy Hylton53187f32000-02-08 19:01:29 +0000792class CompiledModule:
793 """Store the code object for a compiled module
794
795 XXX Not clear how the code objects will be stored. Seems possible
796 that a single code attribute is sufficient, because it will
797 contains references to all the need code objects. That might be
798 messy, though.
799 """
800 MAGIC = (20121 | (ord('\r')<<16) | (ord('\n')<<24))
801
802 def __init__(self, source, filename):
803 self.source = source
804 self.filename = filename
805
806 def compile(self):
807 t = transformer.Transformer()
808 self.ast = t.parsesuite(self.source)
809 cg = CodeGenerator(self.filename)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000810 walk(self.ast, cg, walker=ExampleASTVisitor)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000811 self.code = cg.asConst()
Jeremy Hylton53187f32000-02-08 19:01:29 +0000812
813 def dump(self, path):
814 """create a .pyc file"""
815 f = open(path, 'wb')
816 f.write(self._pyc_header())
817 marshal.dump(self.code, f)
818 f.close()
819
820 def _pyc_header(self):
821 # compile.c uses marshal to write a long directly, with
822 # calling the interface that would also generate a 1-byte code
823 # to indicate the type of the value. simplest way to get the
824 # same effect is to call marshal and then skip the code.
825 magic = marshal.dumps(self.MAGIC)[1:]
826 mtime = os.stat(self.filename)[stat.ST_MTIME]
827 mtime = struct.pack('i', mtime)
828 return magic + mtime
829
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000830if __name__ == "__main__":
Jeremy Hylton40245602000-02-08 21:15:48 +0000831 import getopt
832
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000833 opts, args = getopt.getopt(sys.argv[1:], 'vq')
Jeremy Hylton40245602000-02-08 21:15:48 +0000834 for k, v in opts:
835 if k == '-v':
836 ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000837 if k == '-q':
838 f = open('/dev/null', 'wb')
839 sys.stdout = f
Jeremy Hylton40245602000-02-08 21:15:48 +0000840 if args:
841 filename = args[0]
Jeremy Hylton53187f32000-02-08 19:01:29 +0000842 else:
843 filename = 'test.py'
844 buf = open(filename).read()
845 mod = CompiledModule(buf, filename)
846 mod.compile()
847 mod.dump(filename + 'c')