blob: ac933487c36ffaf7c6db8871bc873c7d9847a4e3 [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):
124 """Prints examples of the nodes that aren't visited"""
125 examples = {}
126
127 def dispatch(self, node):
128 self.node = node
129 className = node.__class__.__name__
130 meth = getattr(self.visitor, 'visit' + className, None)
131 if self.VERBOSE > 0:
132 if self.VERBOSE == 1:
133 if meth is None:
134 print "dispatch", className
135 else:
136 print "dispatch", className, (meth and meth.__name__ or '')
137 if meth:
138 return meth(node)
139 else:
140 klass = node.__class__
141 if self.VERBOSE < 2:
142 if self.examples.has_key(klass):
143 return
144 self.examples[klass] = klass
145 print
146 print klass
147 for attr in dir(node):
148 if attr[0] != '_':
149 print "\t", "%-12.12s" % attr, getattr(node, attr)
150 print
151
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000152class CodeGenerator:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000153 """TODO
154
155 EmptyNode
156 Exec
157 Invert
158 LeftShift
159 Power
160 RightShift
161 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 Hyltona5058122000-02-14 14:14:29 +0000279 self.emit('IMPORT_FROM', name)
280 self.emit('POP_TOP')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000281
Jeremy Hylton3050d512000-02-12 00:12:38 +0000282 def visitClassdef(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000283 self.emit('SET_LINENO', node.lineno)
284 self.emit('LOAD_CONST', node.name)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000285 for base in node.bases:
286 self.visit(base)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000287 self.emit('BUILD_TUPLE', len(node.bases))
Jeremy Hylton3050d512000-02-12 00:12:38 +0000288 classBody = CodeGenerator(self.filename)
289 classBody.generateClassCode(node)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000290 self.emit('LOAD_CONST', classBody)
291 self.emit('MAKE_FUNCTION', 0)
292 self.emit('CALL_FUNCTION', 0)
293 self.emit('BUILD_CLASS')
Jeremy Hylton3050d512000-02-12 00:12:38 +0000294 self.storeName(node.name)
295 return 1
296
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000297 def _visitFuncOrLambda(self, node, kind):
298 """Code common to Function and Lambda nodes"""
Jeremy Hylton3050d512000-02-12 00:12:38 +0000299 codeBody = CodeGenerator(self.filename)
300 getattr(codeBody, 'generate%sCode' % kind)(node)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000301 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000302 for default in node.defaults:
303 self.visit(default)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000304 self.emit('LOAD_CONST', codeBody)
305 self.emit('MAKE_FUNCTION', len(node.defaults))
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000306
307 def visitFunction(self, node):
308 self._visitFuncOrLambda(node, 'Function')
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000309 self.storeName(node.name)
Jeremy Hylton0fdffcf2000-02-04 19:37:35 +0000310 return 1
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000311
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000312 def visitLambda(self, node):
313 node.name = '<lambda>'
314 node.varargs = node.kwargs = None
315 self._visitFuncOrLambda(node, 'Lambda')
316 return 1
317
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000318 def visitCallFunc(self, node):
Jeremy Hylton3050d512000-02-12 00:12:38 +0000319 pos = 0
320 kw = 0
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000321 if hasattr(node, 'lineno'):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000322 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000323 self.visit(node.node)
324 for arg in node.args:
325 self.visit(arg)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000326 if isinstance(arg, ast.Keyword):
327 kw = kw + 1
328 else:
329 pos = pos + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000330 self.emit('CALL_FUNCTION', kw << 8 | pos)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000331 return 1
332
Jeremy Hylton3050d512000-02-12 00:12:38 +0000333 def visitKeyword(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000334 self.emit('LOAD_CONST', node.name)
Jeremy Hylton3050d512000-02-12 00:12:38 +0000335 self.visit(node.expr)
336 return 1
337
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000338 def visitIf(self, node):
Jeremy Hylton40245602000-02-08 21:15:48 +0000339 after = StackRef()
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000340 for test, suite in node.tests:
Jeremy Hylton40245602000-02-08 21:15:48 +0000341 if hasattr(test, 'lineno'):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000342 self.emit('SET_LINENO', test.lineno)
Jeremy Hylton40245602000-02-08 21:15:48 +0000343 else:
344 print "warning", "no line number"
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000345 self.visit(test)
Jeremy Hylton40245602000-02-08 21:15:48 +0000346 dest = StackRef()
Jeremy Hyltona5058122000-02-14 14:14:29 +0000347 self.emit('JUMP_IF_FALSE', dest)
348 self.emit('POP_TOP')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000349 self.visit(suite)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000350 self.emit('JUMP_FORWARD', after)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000351 dest.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000352 self.emit('POP_TOP')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000353 if node.else_:
354 self.visit(node.else_)
355 after.bind(self.code.getCurInst())
356 return 1
357
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000358 def startLoop(self):
359 l = Loop()
360 self.loops.push(l)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000361 self.emit('SETUP_LOOP', l.extentAnchor)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000362 return l
363
364 def finishLoop(self):
365 l = self.loops.pop()
366 i = self.code.getCurInst()
367 l.extentAnchor.bind(self.code.getCurInst())
368
Jeremy Hylton40245602000-02-08 21:15:48 +0000369 def visitFor(self, node):
370 # three refs needed
Jeremy Hylton40245602000-02-08 21:15:48 +0000371 anchor = StackRef()
Jeremy Hylton40245602000-02-08 21:15:48 +0000372
Jeremy Hyltona5058122000-02-14 14:14:29 +0000373 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000374 l = self.startLoop()
Jeremy Hylton40245602000-02-08 21:15:48 +0000375 self.visit(node.list)
376 self.visit(ast.Const(0))
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000377 l.startAnchor.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000378 self.emit('SET_LINENO', node.lineno)
379 self.emit('FOR_LOOP', anchor)
Jeremy Hylton40245602000-02-08 21:15:48 +0000380 self.visit(node.assign)
381 self.visit(node.body)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000382 self.emit('JUMP_ABSOLUTE', l.startAnchor)
Jeremy Hylton40245602000-02-08 21:15:48 +0000383 anchor.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000384 self.emit('POP_BLOCK')
Jeremy Hylton40245602000-02-08 21:15:48 +0000385 if node.else_:
386 self.visit(node.else_)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000387 self.finishLoop()
Jeremy Hylton40245602000-02-08 21:15:48 +0000388 return 1
389
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000390 def visitWhile(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000391 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000392 l = self.startLoop()
393 if node.else_:
394 lElse = StackRef()
395 else:
396 lElse = l.breakAnchor
397 l.startAnchor.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000398 self.emit('SET_LINENO', node.test.lineno)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000399 self.visit(node.test)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000400 self.emit('JUMP_IF_FALSE', lElse)
401 self.emit('POP_TOP')
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000402 self.visit(node.body)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000403 self.emit('JUMP_ABSOLUTE', l.startAnchor)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000404 # note that lElse may be an alias for l.breakAnchor
405 lElse.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000406 self.emit('POP_TOP')
407 self.emit('POP_BLOCK')
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000408 if node.else_:
409 self.visit(node.else_)
410 self.finishLoop()
411 return 1
412
413 def visitBreak(self, node):
414 if not self.loops:
415 raise SyntaxError, "'break' outside loop"
Jeremy Hyltona5058122000-02-14 14:14:29 +0000416 self.emit('SET_LINENO', node.lineno)
417 self.emit('BREAK_LOOP')
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000418
419 def visitContinue(self, node):
420 if not self.loops:
421 raise SyntaxError, "'continue' outside loop"
422 l = self.loops.top()
Jeremy Hyltona5058122000-02-14 14:14:29 +0000423 self.emit('SET_LINENO', node.lineno)
424 self.emit('JUMP_ABSOLUTE', l.startAnchor)
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000425
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000426 def visitCompare(self, node):
427 """Comment from compile.c follows:
428
429 The following code is generated for all but the last
430 comparison in a chain:
431
432 label: on stack: opcode: jump to:
433
434 a <code to load b>
435 a, b DUP_TOP
436 a, b, b ROT_THREE
437 b, a, b COMPARE_OP
438 b, 0-or-1 JUMP_IF_FALSE L1
439 b, 1 POP_TOP
440 b
441
442 We are now ready to repeat this sequence for the next
443 comparison in the chain.
444
445 For the last we generate:
446
447 b <code to load c>
448 b, c COMPARE_OP
449 0-or-1
450
451 If there were any jumps to L1 (i.e., there was more than one
452 comparison), we generate:
453
454 0-or-1 JUMP_FORWARD L2
455 L1: b, 0 ROT_TWO
456 0, b POP_TOP
457 0
458 L2: 0-or-1
459 """
460 self.visit(node.expr)
461 # if refs are never emitted, subsequent bind call has no effect
Jeremy Hylton40245602000-02-08 21:15:48 +0000462 l1 = StackRef()
463 l2 = StackRef()
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000464 for op, code in node.ops[:-1]:
465 # emit every comparison except the last
466 self.visit(code)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000467 self.emit('DUP_TOP')
468 self.emit('ROT_THREE')
469 self.emit('COMPARE_OP', op)
Jeremy Hylton40245602000-02-08 21:15:48 +0000470 # dupTop and compareOp cancel stack effect
Jeremy Hyltona5058122000-02-14 14:14:29 +0000471 self.emit('JUMP_IF_FALSE', l1)
472 self.emit('POP_TOP')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000473 if node.ops:
474 # emit the last comparison
475 op, code = node.ops[-1]
476 self.visit(code)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000477 self.emit('COMPARE_OP', op)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000478 if len(node.ops) > 1:
Jeremy Hyltona5058122000-02-14 14:14:29 +0000479 self.emit('JUMP_FORWARD', l2)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000480 l1.bind(self.code.getCurInst())
Jeremy Hyltona5058122000-02-14 14:14:29 +0000481 self.emit('ROT_TWO')
482 self.emit('POP_TOP')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000483 l2.bind(self.code.getCurInst())
484 return 1
485
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000486 def visitGetattr(self, node):
487 self.visit(node.expr)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000488 self.emit('LOAD_ATTR', node.attrname)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000489 return 1
490
491 def visitSubscript(self, node):
492 self.visit(node.expr)
493 for sub in node.subs[:-1]:
494 self.visit(sub)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000495 self.emit('BINARY_SUBSCR')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000496 self.visit(node.subs[-1])
497 if node.flags == 'OP_APPLY':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000498 self.emit('BINARY_SUBSCR')
499 elif node.flags == 'OP_ASSIGN':
500 self.emit('STORE_SUBSCR')
501 elif node.flags == 'OP_DELETE':
502 self.emit('DELETE_SUBSCR')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000503
504 return 1
505
506 def visitSlice(self, node):
507 self.visit(node.expr)
508 slice = 0
509 if node.lower:
510 self.visit(node.lower)
511 slice = slice | 1
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000512 if node.upper:
513 self.visit(node.upper)
514 slice = slice | 2
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000515 if node.flags == 'OP_APPLY':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000516 self.emit('SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000517 elif node.flags == 'OP_ASSIGN':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000518 self.emit('STORE_SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000519 elif node.flags == 'OP_DELETE':
Jeremy Hyltona5058122000-02-14 14:14:29 +0000520 self.emit('DELETE_SLICE+%d' % slice)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000521 else:
522 print node.flags
523 raise
524 return 1
525
Jeremy Hylton40245602000-02-08 21:15:48 +0000526 def visitAssign(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000527 print "ASSIGN", node.expr
528 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton40245602000-02-08 21:15:48 +0000529 self.visit(node.expr)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000530 dups = len(node.nodes) - 1
531 for i in range(len(node.nodes)):
532 elt = node.nodes[i]
533 if i < dups:
534 self.emit('DUP_TOP')
Jeremy Hylton40245602000-02-08 21:15:48 +0000535 if isinstance(elt, ast.Node):
536 self.visit(elt)
537 return 1
538
539 def visitAssName(self, node):
540 if node.flags != 'OP_ASSIGN':
541 print "oops", node.flags
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000542 self.storeName(node.name)
Jeremy Hylton40245602000-02-08 21:15:48 +0000543
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000544 def visitAssAttr(self, node):
545 if node.flags != 'OP_ASSIGN':
546 print "warning: unexpected flags:", node.flags
547 print node
548 self.visit(node.expr)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000549 self.emit('STORE_ATTR', node.attrname)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000550 return 1
551
552 def visitAssTuple(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000553 self.emit('UNPACK_TUPLE', len(node.nodes))
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000554 for child in node.nodes:
555 self.visit(child)
556 return 1
557
558 visitAssList = visitAssTuple
559
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000560 def binaryOp(self, node, op):
561 self.visit(node.left)
562 self.visit(node.right)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000563 self.emit(op)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000564 return 1
565
Jeremy Hylton40245602000-02-08 21:15:48 +0000566 def unaryOp(self, node, op):
567 self.visit(node.expr)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000568 self.emit(op)
Jeremy Hylton40245602000-02-08 21:15:48 +0000569 return 1
570
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000571 def visitAdd(self, node):
572 return self.binaryOp(node, 'BINARY_ADD')
573
574 def visitSub(self, node):
575 return self.binaryOp(node, 'BINARY_SUBTRACT')
576
577 def visitMul(self, node):
578 return self.binaryOp(node, 'BINARY_MULTIPLY')
579
580 def visitDiv(self, node):
581 return self.binaryOp(node, 'BINARY_DIVIDE')
582
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000583 def visitMod(self, node):
584 return self.binaryOp(node, 'BINARY_MODULO')
585
Jeremy Hylton40245602000-02-08 21:15:48 +0000586 def visitUnarySub(self, node):
587 return self.unaryOp(node, 'UNARY_NEGATIVE')
588
589 def visitUnaryAdd(self, node):
590 return self.unaryOp(node, 'UNARY_POSITIVE')
591
592 def visitUnaryInvert(self, node):
593 return self.unaryOp(node, 'UNARY_INVERT')
594
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000595 def visitNot(self, node):
596 return self.unaryOp(node, 'UNARY_NOT')
597
Jeremy Hylton40245602000-02-08 21:15:48 +0000598 def visitBackquote(self, node):
599 return self.unaryOp(node, 'UNARY_CONVERT')
600
Jeremy Hyltona5058122000-02-14 14:14:29 +0000601 def bitOp(self, nodes, op):
602 self.visit(nodes[0])
603 for node in nodes[1:]:
604 self.visit(node)
605 self.emit(op)
606 return 1
607
608 def visitBitand(self, node):
609 return self.bitOp(node.nodes, 'BINARY_AND')
610
611 def visitBitor(self, node):
612 return self.bitOp(node.nodes, 'BINARY_OR')
613
614 def visitBitxor(self, node):
615 return self.bitOp(node.nodes, 'BINARY_XOR')
616
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000617 def visitTest(self, node, jump):
618 end = StackRef()
619 for child in node.nodes[:-1]:
620 self.visit(child)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000621 self.emit(jump, end)
622 self.emit('POP_TOP')
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000623 self.visit(node.nodes[-1])
624 end.bind(self.code.getCurInst())
625 return 1
626
Jeremy Hyltona5058122000-02-14 14:14:29 +0000627 def visitAssert(self, node):
628 # XXX __debug__ and AssertionError appear to be special cases
629 # -- they are always loaded as globals even if there are local
630 # names. I guess this is a sort of renaming op.
631 skip = StackRef()
632 self.emit('SET_LINENO', node.lineno)
633 self.emit('LOAD_GLOBAL', '__debug__')
634 self.emit('JUMP_IF_FALSE', skip)
635 self.emit('POP_TOP')
636 self.visit(node.test)
637 self.emit('JUMP_IF_TRUE', skip)
638 self.emit('LOAD_GLOBAL', 'AssertionError')
639 self.visit(node.fail)
640 self.emit('RAISE_VARARGS', 2)
641 skip.bind(self.code.getCurInst())
642 self.emit('POP_TOP')
643 return 1
644
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000645 def visitAnd(self, node):
646 return self.visitTest(node, 'JUMP_IF_FALSE')
647
648 def visitOr(self, node):
649 return self.visitTest(node, 'JUMP_IF_TRUE')
650
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000651 def visitName(self, node):
Jeremy Hylton3e0910c2000-02-10 17:20:39 +0000652 self.loadName(node.name)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000653
654 def visitConst(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000655 self.emit('LOAD_CONST', node.value)
Jeremy Hylton40245602000-02-08 21:15:48 +0000656 return 1
657
Jeremy Hyltona5058122000-02-14 14:14:29 +0000658 def visitEllipsis(self, node):
659 self.emit('LOAD_CONST', Ellipsis)
660 return 1
661
Jeremy Hylton40245602000-02-08 21:15:48 +0000662 def visitTuple(self, node):
663 for elt in node.nodes:
664 self.visit(elt)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000665 self.emit('BUILD_TUPLE', len(node.nodes))
Jeremy Hylton40245602000-02-08 21:15:48 +0000666 return 1
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000667
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000668 def visitList(self, node):
669 for elt in node.nodes:
670 self.visit(elt)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000671 self.emit('BUILD_LIST', len(node.nodes))
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000672 return 1
673
Jeremy Hyltona5058122000-02-14 14:14:29 +0000674 def visitDict(self, node):
675 self.emit('BUILD_MAP', 0)
676 for k, v in node.items:
677 # XXX need to add set lineno when there aren't constants
678 self.emit('DUP_TOP')
679 self.visit(v)
680 self.emit('ROT_TWO')
681 self.visit(k)
682 self.emit('STORE_SUBSCR')
683 return 1
684
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000685 def visitReturn(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000686 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000687 self.visit(node.value)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000688 self.emit('RETURN_VALUE')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000689 return 1
690
691 def visitRaise(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000692 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000693 n = 0
694 if node.expr1:
695 self.visit(node.expr1)
696 n = n + 1
697 if node.expr2:
698 self.visit(node.expr2)
699 n = n + 1
700 if node.expr3:
701 self.visit(node.expr3)
702 n = n + 1
Jeremy Hyltona5058122000-02-14 14:14:29 +0000703 self.emit('RAISE_VARARGS', n)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000704 return 1
705
706 def visitPrint(self, node):
Jeremy Hyltona5058122000-02-14 14:14:29 +0000707 self.emit('SET_LINENO', node.lineno)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000708 for child in node.nodes:
709 self.visit(child)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000710 self.emit('PRINT_ITEM')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000711 return 1
712
713 def visitPrintnl(self, node):
714 self.visitPrint(node)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000715 self.emit('PRINT_NEWLINE')
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000716 return 1
Jeremy Hylton0fdffcf2000-02-04 19:37:35 +0000717
Jeremy Hyltona5058122000-02-14 14:14:29 +0000718 def visitExec(self, node):
719 self.visit(node.expr)
720 if node.locals is None:
721 self.emit('LOAD_CONST', None)
722 else:
723 self.visit(node.locals)
724 if node.globals is None:
725 self.emit('DUP_TOP')
726 else:
727 self.visit(node.globals)
728 self.emit('EXEC_STMT')
729
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000730class LocalNameFinder:
731 def __init__(self, names=()):
732 self.names = misc.Set()
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000733 self.globals = misc.Set()
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000734 for name in names:
735 self.names.add(name)
736
737 def getLocals(self):
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000738 for elt in self.globals.items():
739 if self.names.has_elt(elt):
740 self.names.remove(elt)
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000741 return self.names
742
Jeremy Hyltona5058122000-02-14 14:14:29 +0000743 def visitDict(self, node):
744 return 1
745
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000746 def visitGlobal(self, node):
747 for name in node.names:
748 self.globals.add(name)
749 return 1
750
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000751 def visitFunction(self, node):
752 self.names.add(node.name)
753 return 1
754
Jeremy Hylton76d01b82000-02-11 20:27:07 +0000755 def visitLambda(self, node):
756 return 1
757
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000758 def visitImport(self, node):
759 for name in node.names:
760 self.names.add(name)
761
762 def visitFrom(self, node):
763 for name in node.names:
764 self.names.add(name)
765
766 def visitClassdef(self, node):
767 self.names.add(node.name)
768 return 1
769
770 def visitAssName(self, node):
771 self.names.add(node.name)
772
Jeremy Hylton4eb504c2000-02-10 20:55:50 +0000773class Loop:
774 def __init__(self):
775 self.startAnchor = StackRef()
776 self.breakAnchor = StackRef()
777 self.extentAnchor = StackRef()
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000778
Jeremy Hylton53187f32000-02-08 19:01:29 +0000779class CompiledModule:
780 """Store the code object for a compiled module
781
782 XXX Not clear how the code objects will be stored. Seems possible
783 that a single code attribute is sufficient, because it will
784 contains references to all the need code objects. That might be
785 messy, though.
786 """
787 MAGIC = (20121 | (ord('\r')<<16) | (ord('\n')<<24))
788
789 def __init__(self, source, filename):
790 self.source = source
791 self.filename = filename
792
793 def compile(self):
794 t = transformer.Transformer()
795 self.ast = t.parsesuite(self.source)
796 cg = CodeGenerator(self.filename)
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000797 walk(self.ast, cg, walker=ExampleASTVisitor)
Jeremy Hyltona5058122000-02-14 14:14:29 +0000798 self.code = cg.asConst()
Jeremy Hylton53187f32000-02-08 19:01:29 +0000799
800 def dump(self, path):
801 """create a .pyc file"""
802 f = open(path, 'wb')
803 f.write(self._pyc_header())
804 marshal.dump(self.code, f)
805 f.close()
806
807 def _pyc_header(self):
808 # compile.c uses marshal to write a long directly, with
809 # calling the interface that would also generate a 1-byte code
810 # to indicate the type of the value. simplest way to get the
811 # same effect is to call marshal and then skip the code.
812 magic = marshal.dumps(self.MAGIC)[1:]
813 mtime = os.stat(self.filename)[stat.ST_MTIME]
814 mtime = struct.pack('i', mtime)
815 return magic + mtime
816
Jeremy Hylton8b6323d2000-02-04 00:28:21 +0000817if __name__ == "__main__":
Jeremy Hylton40245602000-02-08 21:15:48 +0000818 import getopt
819
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000820 opts, args = getopt.getopt(sys.argv[1:], 'vq')
Jeremy Hylton40245602000-02-08 21:15:48 +0000821 for k, v in opts:
822 if k == '-v':
823 ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
824 print k
Jeremy Hylton5e0ce532000-02-10 00:47:08 +0000825 if k == '-q':
826 f = open('/dev/null', 'wb')
827 sys.stdout = f
Jeremy Hylton40245602000-02-08 21:15:48 +0000828 if args:
829 filename = args[0]
Jeremy Hylton53187f32000-02-08 19:01:29 +0000830 else:
831 filename = 'test.py'
832 buf = open(filename).read()
833 mod = CompiledModule(buf, filename)
834 mod.compile()
835 mod.dump(filename + 'c')