2000-02-04 00:28:21 +00:00
|
|
|
"""Python bytecode generator
|
|
|
|
|
|
|
|
Currently contains generic ASTVisitor code, a LocalNameFinder, and a
|
|
|
|
CodeGenerator. Eventually, this will get split into the ASTVisitor as
|
|
|
|
a generic tool and CodeGenerator as a specific tool.
|
|
|
|
"""
|
|
|
|
|
|
|
|
from p2c import transformer, ast
|
2000-02-14 14:14:29 +00:00
|
|
|
from pyassem import StackRef, PyAssembler
|
2000-02-04 00:28:21 +00:00
|
|
|
import dis
|
|
|
|
import misc
|
2000-02-04 19:37:35 +00:00
|
|
|
import marshal
|
|
|
|
import new
|
|
|
|
import string
|
2000-02-08 19:01:29 +00:00
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import stat
|
|
|
|
import struct
|
2000-02-16 00:55:44 +00:00
|
|
|
import types
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def parse(path):
|
|
|
|
f = open(path)
|
|
|
|
src = f.read()
|
|
|
|
f.close()
|
|
|
|
t = transformer.Transformer()
|
|
|
|
return t.parsesuite(src)
|
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def walk(tree, visitor, verbose=None, walker=None):
|
|
|
|
if walker:
|
|
|
|
w = walker()
|
|
|
|
else:
|
|
|
|
w = ASTVisitor()
|
2000-02-08 21:15:48 +00:00
|
|
|
if verbose is not None:
|
|
|
|
w.VERBOSE = verbose
|
2000-02-04 00:28:21 +00:00
|
|
|
w.preorder(tree, visitor)
|
|
|
|
return w.visitor
|
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def dumpNode(node):
|
|
|
|
print node.__class__
|
|
|
|
for attr in dir(node):
|
|
|
|
if attr[0] != '_':
|
|
|
|
print "\t", "%-10.10s" % attr, getattr(node, attr)
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
class ASTVisitor:
|
|
|
|
"""Performs a depth-first walk of the AST
|
|
|
|
|
|
|
|
The ASTVisitor will walk the AST, performing either a preorder or
|
|
|
|
postorder traversal depending on which method is called.
|
|
|
|
|
|
|
|
methods:
|
|
|
|
preorder(tree, visitor)
|
|
|
|
postorder(tree, visitor)
|
|
|
|
tree: an instance of ast.Node
|
|
|
|
visitor: an instance with visitXXX methods
|
|
|
|
|
|
|
|
The ASTVisitor is responsible for walking over the tree in the
|
|
|
|
correct order. For each node, it checks the visitor argument for
|
|
|
|
a method named 'visitNodeType' where NodeType is the name of the
|
|
|
|
node's class, e.g. Classdef. If the method exists, it is called
|
|
|
|
with the node as its sole argument.
|
|
|
|
|
|
|
|
The visitor method for a particular node type can control how
|
|
|
|
child nodes are visited during a preorder walk. (It can't control
|
|
|
|
the order during a postorder walk, because it is called _after_
|
|
|
|
the walk has occurred.) The ASTVisitor modifies the visitor
|
|
|
|
argument by adding a visit method to the visitor; this method can
|
|
|
|
be used to visit a particular child node. If the visitor method
|
|
|
|
returns a true value, the ASTVisitor will not traverse the child
|
|
|
|
nodes.
|
|
|
|
|
|
|
|
XXX The interface for controlling the preorder walk needs to be
|
|
|
|
re-considered. The current interface is convenient for visitors
|
|
|
|
that mostly let the ASTVisitor do everything. For something like
|
|
|
|
a code generator, where you want to walk to occur in a specific
|
|
|
|
order, it's a pain to add "return 1" to the end of each method.
|
|
|
|
|
|
|
|
XXX Perhaps I can use a postorder walk for the code generator?
|
|
|
|
"""
|
|
|
|
|
2000-02-08 21:15:48 +00:00
|
|
|
VERBOSE = 0
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def __init__(self):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.node = None
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def preorder(self, tree, visitor):
|
|
|
|
"""Do preorder walk of tree using visitor"""
|
|
|
|
self.visitor = visitor
|
|
|
|
visitor.visit = self._preorder
|
|
|
|
self._preorder(tree)
|
|
|
|
|
|
|
|
def _preorder(self, node):
|
|
|
|
stop = self.dispatch(node)
|
|
|
|
if stop:
|
|
|
|
return
|
|
|
|
for child in node.getChildren():
|
|
|
|
if isinstance(child, ast.Node):
|
|
|
|
self._preorder(child)
|
|
|
|
|
|
|
|
def postorder(self, tree, visitor):
|
|
|
|
"""Do preorder walk of tree using visitor"""
|
|
|
|
self.visitor = visitor
|
|
|
|
visitor.visit = self._postorder
|
|
|
|
self._postorder(tree)
|
|
|
|
|
|
|
|
def _postorder(self, tree):
|
|
|
|
for child in node.getChildren():
|
|
|
|
if isinstance(child, ast.Node):
|
|
|
|
self._preorder(child)
|
|
|
|
self.dispatch(node)
|
|
|
|
|
|
|
|
def dispatch(self, node):
|
|
|
|
self.node = node
|
|
|
|
className = node.__class__.__name__
|
|
|
|
meth = getattr(self.visitor, 'visit' + className, None)
|
2000-02-08 21:15:48 +00:00
|
|
|
if self.VERBOSE > 0:
|
|
|
|
if self.VERBOSE == 1:
|
|
|
|
if meth is None:
|
|
|
|
print "dispatch", className
|
|
|
|
else:
|
|
|
|
print "dispatch", className, (meth and meth.__name__ or '')
|
2000-02-04 00:28:21 +00:00
|
|
|
if meth:
|
|
|
|
return meth(node)
|
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
class ExampleASTVisitor(ASTVisitor):
|
2000-02-14 23:57:56 +00:00
|
|
|
"""Prints examples of the nodes that aren't visited
|
|
|
|
|
|
|
|
This visitor-driver is only useful for development, when it's
|
|
|
|
helpful to develop a visitor incremently, and get feedback on what
|
|
|
|
you still have to do.
|
|
|
|
"""
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
examples = {}
|
|
|
|
|
|
|
|
def dispatch(self, node):
|
|
|
|
self.node = node
|
|
|
|
className = node.__class__.__name__
|
|
|
|
meth = getattr(self.visitor, 'visit' + className, None)
|
|
|
|
if self.VERBOSE > 0:
|
|
|
|
if self.VERBOSE == 1:
|
|
|
|
if meth is None:
|
|
|
|
print "dispatch", className
|
|
|
|
else:
|
|
|
|
print "dispatch", className, (meth and meth.__name__ or '')
|
|
|
|
if meth:
|
|
|
|
return meth(node)
|
|
|
|
else:
|
|
|
|
klass = node.__class__
|
|
|
|
if self.VERBOSE < 2:
|
|
|
|
if self.examples.has_key(klass):
|
|
|
|
return
|
|
|
|
self.examples[klass] = klass
|
|
|
|
print
|
|
|
|
print klass
|
|
|
|
for attr in dir(node):
|
|
|
|
if attr[0] != '_':
|
|
|
|
print "\t", "%-12.12s" % attr, getattr(node, attr)
|
|
|
|
print
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
class CodeGenerator:
|
2000-02-15 23:45:26 +00:00
|
|
|
"""Generate bytecode for the Python VM"""
|
2000-02-10 17:20:39 +00:00
|
|
|
|
2000-02-12 00:12:38 +00:00
|
|
|
OPTIMIZED = 1
|
|
|
|
|
2000-02-14 14:14:29 +00:00
|
|
|
# XXX should clean up initialization and generateXXX funcs
|
2000-02-12 00:12:38 +00:00
|
|
|
def __init__(self, filename="<?>"):
|
2000-02-08 19:01:29 +00:00
|
|
|
self.filename = filename
|
2000-02-17 17:56:29 +00:00
|
|
|
self.code = PyAssembler()
|
2000-02-08 19:01:29 +00:00
|
|
|
self.code.setFlags(0)
|
2000-02-17 17:56:29 +00:00
|
|
|
self.locals = misc.Stack()
|
2000-02-10 20:55:50 +00:00
|
|
|
self.loops = misc.Stack()
|
2000-02-12 00:12:38 +00:00
|
|
|
self.namespace = 0
|
2000-02-08 19:01:29 +00:00
|
|
|
self.curStack = 0
|
|
|
|
self.maxStack = 0
|
|
|
|
|
2000-02-14 14:14:29 +00:00
|
|
|
def emit(self, *args):
|
2000-02-17 17:56:29 +00:00
|
|
|
# XXX could just use self.emit = self.code.emit
|
|
|
|
apply(self.code.emit, args)
|
2000-02-14 14:14:29 +00:00
|
|
|
|
2000-02-12 00:12:38 +00:00
|
|
|
def _generateFunctionOrLambdaCode(self, func):
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
self.name = func.name
|
2000-02-17 17:56:29 +00:00
|
|
|
|
2000-02-16 00:55:44 +00:00
|
|
|
# keep a lookout for 'def foo((x,y)):'
|
|
|
|
args, hasTupleArg = self.generateArglist(func.argnames)
|
|
|
|
|
2000-02-17 17:56:29 +00:00
|
|
|
self.code = PyAssembler(args=args, name=func.name,
|
|
|
|
filename=self.filename)
|
2000-02-12 00:12:38 +00:00
|
|
|
self.namespace = self.OPTIMIZED
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
if func.varargs:
|
|
|
|
self.code.setVarArgs()
|
|
|
|
if func.kwargs:
|
|
|
|
self.code.setKWArgs()
|
|
|
|
lnf = walk(func.code, LocalNameFinder(args), 0)
|
|
|
|
self.locals.push(lnf.getLocals())
|
2000-02-17 17:56:29 +00:00
|
|
|
self.emit('SET_LINENO', func.lineno)
|
|
|
|
if hasTupleArg:
|
2000-02-16 00:55:44 +00:00
|
|
|
self.generateArgUnpack(func.argnames)
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
walk(func.code, self)
|
2000-02-11 20:27:07 +00:00
|
|
|
|
2000-02-16 00:55:44 +00:00
|
|
|
def generateArglist(self, arglist):
|
|
|
|
args = []
|
|
|
|
extra = []
|
|
|
|
count = 0
|
|
|
|
for elt in arglist:
|
|
|
|
if type(elt) == types.StringType:
|
|
|
|
args.append(elt)
|
|
|
|
elif type(elt) == types.TupleType:
|
|
|
|
args.append(".nested%d" % count)
|
|
|
|
count = count + 1
|
|
|
|
extra.extend(misc.flatten(elt))
|
|
|
|
else:
|
|
|
|
raise ValueError, "unexpect argument type:", elt
|
|
|
|
return args + extra, count
|
|
|
|
|
|
|
|
def generateArgUnpack(self, args):
|
|
|
|
count = 0
|
|
|
|
for arg in args:
|
|
|
|
if type(arg) == types.TupleType:
|
|
|
|
self.emit('LOAD_FAST', '.nested%d' % count)
|
|
|
|
count = count + 1
|
|
|
|
self.unpackTuple(arg)
|
|
|
|
|
|
|
|
def unpackTuple(self, tup):
|
|
|
|
self.emit('UNPACK_TUPLE', len(tup))
|
|
|
|
for elt in tup:
|
|
|
|
if type(elt) == types.TupleType:
|
|
|
|
self.unpackTuple(elt)
|
|
|
|
else:
|
|
|
|
self.emit('STORE_FAST', elt)
|
|
|
|
|
2000-02-12 00:12:38 +00:00
|
|
|
def generateFunctionCode(self, func):
|
2000-02-11 20:27:07 +00:00
|
|
|
"""Generate code for a function body"""
|
2000-02-12 00:12:38 +00:00
|
|
|
self._generateFunctionOrLambdaCode(func)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('LOAD_CONST', None)
|
|
|
|
self.emit('RETURN_VALUE')
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
|
2000-02-12 00:12:38 +00:00
|
|
|
def generateLambdaCode(self, func):
|
|
|
|
self._generateFunctionOrLambdaCode(func)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('RETURN_VALUE')
|
2000-02-12 00:12:38 +00:00
|
|
|
|
|
|
|
def generateClassCode(self, klass):
|
2000-02-14 14:14:29 +00:00
|
|
|
self.code = PyAssembler(name=klass.name,
|
2000-02-17 17:56:29 +00:00
|
|
|
filename=self.filename)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', klass.lineno)
|
2000-02-12 00:12:38 +00:00
|
|
|
lnf = walk(klass.code, LocalNameFinder(), 0)
|
|
|
|
self.locals.push(lnf.getLocals())
|
|
|
|
walk(klass.code, self)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('LOAD_LOCALS')
|
|
|
|
self.emit('RETURN_VALUE')
|
2000-02-11 20:27:07 +00:00
|
|
|
|
2000-02-14 14:14:29 +00:00
|
|
|
def asConst(self):
|
|
|
|
"""Create a Python code object."""
|
2000-02-12 00:12:38 +00:00
|
|
|
if self.namespace == self.OPTIMIZED:
|
|
|
|
self.code.setOptimized()
|
2000-02-14 14:14:29 +00:00
|
|
|
return self.code.makeCodeObject()
|
2000-02-08 19:01:29 +00:00
|
|
|
|
2000-02-08 21:15:48 +00:00
|
|
|
def isLocalName(self, name):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.locals.top().has_elt(name)
|
2000-02-08 21:15:48 +00:00
|
|
|
|
2000-02-10 17:20:39 +00:00
|
|
|
def _nameOp(self, prefix, name):
|
|
|
|
if self.isLocalName(name):
|
2000-02-12 00:12:38 +00:00
|
|
|
if self.namespace == self.OPTIMIZED:
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit(prefix + '_FAST', name)
|
2000-02-12 00:12:38 +00:00
|
|
|
else:
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit(prefix + '_NAME', name)
|
2000-02-10 17:20:39 +00:00
|
|
|
else:
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit(prefix + '_GLOBAL', name)
|
2000-02-10 17:20:39 +00:00
|
|
|
|
|
|
|
def storeName(self, name):
|
|
|
|
self._nameOp('STORE', name)
|
|
|
|
|
|
|
|
def loadName(self, name):
|
|
|
|
self._nameOp('LOAD', name)
|
|
|
|
|
|
|
|
def delName(self, name):
|
|
|
|
self._nameOp('DELETE', name)
|
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def visitNULL(self, node):
|
|
|
|
"""Method exists only to stop warning in -v mode"""
|
|
|
|
pass
|
|
|
|
|
|
|
|
visitStmt = visitNULL
|
|
|
|
visitGlobal = visitNULL
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
def visitDiscard(self, node):
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
self.visit(node.expr)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('POP_TOP')
|
2000-02-04 00:28:21 +00:00
|
|
|
return 1
|
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def visitPass(self, node):
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
def visitModule(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
lnf = walk(node.node, LocalNameFinder(), 0)
|
|
|
|
self.locals.push(lnf.getLocals())
|
2000-02-04 19:37:35 +00:00
|
|
|
self.visit(node.node)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('LOAD_CONST', None)
|
|
|
|
self.emit('RETURN_VALUE')
|
2000-02-04 19:37:35 +00:00
|
|
|
return 1
|
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def visitImport(self, node):
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
for name in node.names:
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('IMPORT_NAME', name)
|
2000-02-10 17:20:39 +00:00
|
|
|
self.storeName(name)
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
|
|
|
|
def visitFrom(self, node):
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
|
|
|
self.emit('IMPORT_NAME', node.modname)
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
for name in node.names:
|
2000-02-14 21:33:10 +00:00
|
|
|
if name == '*':
|
|
|
|
self.namespace = 0
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('IMPORT_FROM', name)
|
|
|
|
self.emit('POP_TOP')
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
|
2000-02-12 00:12:38 +00:00
|
|
|
def visitClassdef(self, node):
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
|
|
|
self.emit('LOAD_CONST', node.name)
|
2000-02-12 00:12:38 +00:00
|
|
|
for base in node.bases:
|
|
|
|
self.visit(base)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('BUILD_TUPLE', len(node.bases))
|
2000-02-12 00:12:38 +00:00
|
|
|
classBody = CodeGenerator(self.filename)
|
|
|
|
classBody.generateClassCode(node)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('LOAD_CONST', classBody)
|
|
|
|
self.emit('MAKE_FUNCTION', 0)
|
|
|
|
self.emit('CALL_FUNCTION', 0)
|
|
|
|
self.emit('BUILD_CLASS')
|
2000-02-12 00:12:38 +00:00
|
|
|
self.storeName(node.name)
|
|
|
|
return 1
|
|
|
|
|
2000-02-11 20:27:07 +00:00
|
|
|
def _visitFuncOrLambda(self, node, kind):
|
|
|
|
"""Code common to Function and Lambda nodes"""
|
2000-02-12 00:12:38 +00:00
|
|
|
codeBody = CodeGenerator(self.filename)
|
|
|
|
getattr(codeBody, 'generate%sCode' % kind)(node)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
for default in node.defaults:
|
|
|
|
self.visit(default)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('LOAD_CONST', codeBody)
|
|
|
|
self.emit('MAKE_FUNCTION', len(node.defaults))
|
2000-02-11 20:27:07 +00:00
|
|
|
|
|
|
|
def visitFunction(self, node):
|
|
|
|
self._visitFuncOrLambda(node, 'Function')
|
2000-02-10 17:20:39 +00:00
|
|
|
self.storeName(node.name)
|
2000-02-04 19:37:35 +00:00
|
|
|
return 1
|
2000-02-04 00:28:21 +00:00
|
|
|
|
2000-02-11 20:27:07 +00:00
|
|
|
def visitLambda(self, node):
|
|
|
|
node.name = '<lambda>'
|
|
|
|
node.varargs = node.kwargs = None
|
|
|
|
self._visitFuncOrLambda(node, 'Lambda')
|
|
|
|
return 1
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
def visitCallFunc(self, node):
|
2000-02-12 00:12:38 +00:00
|
|
|
pos = 0
|
|
|
|
kw = 0
|
2000-02-10 20:55:50 +00:00
|
|
|
if hasattr(node, 'lineno'):
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
2000-02-17 17:56:29 +00:00
|
|
|
self.visit(node.node)
|
|
|
|
for arg in node.args:
|
|
|
|
self.visit(arg)
|
2000-02-12 00:12:38 +00:00
|
|
|
if isinstance(arg, ast.Keyword):
|
|
|
|
kw = kw + 1
|
|
|
|
else:
|
|
|
|
pos = pos + 1
|
2000-02-17 17:56:29 +00:00
|
|
|
self.emit('CALL_FUNCTION', kw << 8 | pos)
|
|
|
|
return 1
|
2000-02-04 00:28:21 +00:00
|
|
|
|
2000-02-12 00:12:38 +00:00
|
|
|
def visitKeyword(self, node):
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('LOAD_CONST', node.name)
|
2000-02-12 00:12:38 +00:00
|
|
|
self.visit(node.expr)
|
|
|
|
return 1
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
def visitIf(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
after = StackRef()
|
|
|
|
for test, suite in node.tests:
|
2000-02-08 21:15:48 +00:00
|
|
|
if hasattr(test, 'lineno'):
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', test.lineno)
|
2000-02-08 21:15:48 +00:00
|
|
|
else:
|
|
|
|
print "warning", "no line number"
|
2000-02-17 17:56:29 +00:00
|
|
|
self.visit(test)
|
|
|
|
dest = StackRef()
|
|
|
|
self.emit('JUMP_IF_FALSE', dest)
|
|
|
|
self.emit('POP_TOP')
|
|
|
|
self.visit(suite)
|
|
|
|
self.emit('JUMP_FORWARD', after)
|
|
|
|
dest.bind(self.code.getCurInst())
|
|
|
|
self.emit('POP_TOP')
|
|
|
|
if node.else_:
|
|
|
|
self.visit(node.else_)
|
|
|
|
after.bind(self.code.getCurInst())
|
|
|
|
return 1
|
2000-02-04 00:28:21 +00:00
|
|
|
|
2000-02-10 20:55:50 +00:00
|
|
|
def startLoop(self):
|
|
|
|
l = Loop()
|
|
|
|
self.loops.push(l)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SETUP_LOOP', l.extentAnchor)
|
2000-02-10 20:55:50 +00:00
|
|
|
return l
|
|
|
|
|
|
|
|
def finishLoop(self):
|
|
|
|
l = self.loops.pop()
|
|
|
|
i = self.code.getCurInst()
|
|
|
|
l.extentAnchor.bind(self.code.getCurInst())
|
|
|
|
|
2000-02-08 21:15:48 +00:00
|
|
|
def visitFor(self, node):
|
|
|
|
# three refs needed
|
|
|
|
anchor = StackRef()
|
|
|
|
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
2000-02-10 20:55:50 +00:00
|
|
|
l = self.startLoop()
|
2000-02-08 21:15:48 +00:00
|
|
|
self.visit(node.list)
|
|
|
|
self.visit(ast.Const(0))
|
2000-02-10 20:55:50 +00:00
|
|
|
l.startAnchor.bind(self.code.getCurInst())
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
|
|
|
self.emit('FOR_LOOP', anchor)
|
2000-02-08 21:15:48 +00:00
|
|
|
self.visit(node.assign)
|
|
|
|
self.visit(node.body)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('JUMP_ABSOLUTE', l.startAnchor)
|
2000-02-08 21:15:48 +00:00
|
|
|
anchor.bind(self.code.getCurInst())
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('POP_BLOCK')
|
2000-02-08 21:15:48 +00:00
|
|
|
if node.else_:
|
|
|
|
self.visit(node.else_)
|
2000-02-10 20:55:50 +00:00
|
|
|
self.finishLoop()
|
2000-02-08 21:15:48 +00:00
|
|
|
return 1
|
|
|
|
|
2000-02-10 20:55:50 +00:00
|
|
|
def visitWhile(self, node):
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
2000-02-10 20:55:50 +00:00
|
|
|
l = self.startLoop()
|
|
|
|
if node.else_:
|
|
|
|
lElse = StackRef()
|
|
|
|
else:
|
|
|
|
lElse = l.breakAnchor
|
|
|
|
l.startAnchor.bind(self.code.getCurInst())
|
2000-02-16 00:55:44 +00:00
|
|
|
if hasattr(node.test, 'lineno'):
|
|
|
|
self.emit('SET_LINENO', node.test.lineno)
|
2000-02-10 20:55:50 +00:00
|
|
|
self.visit(node.test)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('JUMP_IF_FALSE', lElse)
|
|
|
|
self.emit('POP_TOP')
|
2000-02-10 20:55:50 +00:00
|
|
|
self.visit(node.body)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('JUMP_ABSOLUTE', l.startAnchor)
|
2000-02-10 20:55:50 +00:00
|
|
|
# note that lElse may be an alias for l.breakAnchor
|
|
|
|
lElse.bind(self.code.getCurInst())
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('POP_TOP')
|
|
|
|
self.emit('POP_BLOCK')
|
2000-02-10 20:55:50 +00:00
|
|
|
if node.else_:
|
|
|
|
self.visit(node.else_)
|
|
|
|
self.finishLoop()
|
|
|
|
return 1
|
|
|
|
|
|
|
|
def visitBreak(self, node):
|
|
|
|
if not self.loops:
|
|
|
|
raise SyntaxError, "'break' outside loop"
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
|
|
|
self.emit('BREAK_LOOP')
|
2000-02-10 20:55:50 +00:00
|
|
|
|
|
|
|
def visitContinue(self, node):
|
|
|
|
if not self.loops:
|
|
|
|
raise SyntaxError, "'continue' outside loop"
|
|
|
|
l = self.loops.top()
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
|
|
|
self.emit('JUMP_ABSOLUTE', l.startAnchor)
|
2000-02-10 20:55:50 +00:00
|
|
|
|
2000-02-15 23:45:26 +00:00
|
|
|
def visitTryExcept(self, node):
|
|
|
|
# XXX need to figure out exactly what is on the stack when an
|
|
|
|
# exception is raised and the first handler is checked
|
|
|
|
handlers = StackRef()
|
|
|
|
end = StackRef()
|
|
|
|
if node.else_:
|
|
|
|
lElse = StackRef()
|
|
|
|
else:
|
|
|
|
lElse = end
|
|
|
|
self.emit('SET_LINENO', node.lineno)
|
|
|
|
self.emit('SETUP_EXCEPT', handlers)
|
|
|
|
self.visit(node.body)
|
|
|
|
self.emit('POP_BLOCK')
|
|
|
|
self.emit('JUMP_FORWARD', lElse)
|
|
|
|
handlers.bind(self.code.getCurInst())
|
|
|
|
|
|
|
|
last = len(node.handlers) - 1
|
|
|
|
for i in range(len(node.handlers)):
|
|
|
|
expr, target, body = node.handlers[i]
|
|
|
|
if hasattr(expr, 'lineno'):
|
|
|
|
self.emit('SET_LINENO', expr.lineno)
|
|
|
|
if expr:
|
|
|
|
self.emit('DUP_TOP')
|
|
|
|
self.visit(expr)
|
|
|
|
self.emit('COMPARE_OP', "exception match")
|
|
|
|
next = StackRef()
|
|
|
|
self.emit('JUMP_IF_FALSE', next)
|
|
|
|
self.emit('POP_TOP')
|
|
|
|
self.emit('POP_TOP')
|
|
|
|
if target:
|
|
|
|
self.visit(target)
|
|
|
|
else:
|
|
|
|
self.emit('POP_TOP')
|
|
|
|
self.emit('POP_TOP')
|
|
|
|
self.visit(body)
|
|
|
|
self.emit('JUMP_FORWARD', end)
|
2000-02-16 00:55:44 +00:00
|
|
|
if expr:
|
|
|
|
next.bind(self.code.getCurInst())
|
2000-02-15 23:45:26 +00:00
|
|
|
self.emit('POP_TOP')
|
|
|
|
self.emit('END_FINALLY')
|
|
|
|
if node.else_:
|
|
|
|
lElse.bind(self.code.getCurInst())
|
|
|
|
self.visit(node.else_)
|
|
|
|
end.bind(self.code.getCurInst())
|
|
|
|
return 1
|
|
|
|
|
|
|
|
def visitTryFinally(self, node):
|
|
|
|
final = StackRef()
|
|
|
|
self.emit('SET_LINENO', node.lineno)
|
|
|
|
self.emit('SETUP_FINALLY', final)
|
|
|
|
self.visit(node.body)
|
|
|
|
self.emit('POP_BLOCK')
|
|
|
|
self.emit('LOAD_CONST', None)
|
|
|
|
final.bind(self.code.getCurInst())
|
|
|
|
self.visit(node.final)
|
|
|
|
self.emit('END_FINALLY')
|
|
|
|
return 1
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
def visitCompare(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
"""Comment from compile.c follows:
|
|
|
|
|
|
|
|
The following code is generated for all but the last
|
|
|
|
comparison in a chain:
|
|
|
|
|
|
|
|
label: on stack: opcode: jump to:
|
|
|
|
|
|
|
|
a <code to load b>
|
|
|
|
a, b DUP_TOP
|
|
|
|
a, b, b ROT_THREE
|
|
|
|
b, a, b COMPARE_OP
|
|
|
|
b, 0-or-1 JUMP_IF_FALSE L1
|
|
|
|
b, 1 POP_TOP
|
|
|
|
b
|
|
|
|
|
|
|
|
We are now ready to repeat this sequence for the next
|
|
|
|
comparison in the chain.
|
|
|
|
|
|
|
|
For the last we generate:
|
|
|
|
|
|
|
|
b <code to load c>
|
|
|
|
b, c COMPARE_OP
|
|
|
|
0-or-1
|
|
|
|
|
|
|
|
If there were any jumps to L1 (i.e., there was more than one
|
|
|
|
comparison), we generate:
|
|
|
|
|
|
|
|
0-or-1 JUMP_FORWARD L2
|
|
|
|
L1: b, 0 ROT_TWO
|
|
|
|
0, b POP_TOP
|
|
|
|
0
|
|
|
|
L2: 0-or-1
|
|
|
|
"""
|
|
|
|
self.visit(node.expr)
|
|
|
|
# if refs are never emitted, subsequent bind call has no effect
|
|
|
|
l1 = StackRef()
|
|
|
|
l2 = StackRef()
|
|
|
|
for op, code in node.ops[:-1]:
|
|
|
|
# emit every comparison except the last
|
|
|
|
self.visit(code)
|
|
|
|
self.emit('DUP_TOP')
|
|
|
|
self.emit('ROT_THREE')
|
|
|
|
self.emit('COMPARE_OP', op)
|
2000-02-08 21:15:48 +00:00
|
|
|
# dupTop and compareOp cancel stack effect
|
2000-02-17 17:56:29 +00:00
|
|
|
self.emit('JUMP_IF_FALSE', l1)
|
|
|
|
self.emit('POP_TOP')
|
|
|
|
if node.ops:
|
|
|
|
# emit the last comparison
|
|
|
|
op, code = node.ops[-1]
|
|
|
|
self.visit(code)
|
|
|
|
self.emit('COMPARE_OP', op)
|
|
|
|
if len(node.ops) > 1:
|
|
|
|
self.emit('JUMP_FORWARD', l2)
|
|
|
|
l1.bind(self.code.getCurInst())
|
|
|
|
self.emit('ROT_TWO')
|
|
|
|
self.emit('POP_TOP')
|
|
|
|
l2.bind(self.code.getCurInst())
|
|
|
|
return 1
|
2000-02-04 00:28:21 +00:00
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def visitGetattr(self, node):
|
|
|
|
self.visit(node.expr)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('LOAD_ATTR', node.attrname)
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
return 1
|
|
|
|
|
|
|
|
def visitSubscript(self, node):
|
|
|
|
self.visit(node.expr)
|
2000-02-15 23:45:26 +00:00
|
|
|
for sub in node.subs:
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
self.visit(sub)
|
2000-02-15 23:45:26 +00:00
|
|
|
if len(node.subs) > 1:
|
|
|
|
self.emit('BUILD_TUPLE', len(node.subs))
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
if node.flags == 'OP_APPLY':
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('BINARY_SUBSCR')
|
|
|
|
elif node.flags == 'OP_ASSIGN':
|
|
|
|
self.emit('STORE_SUBSCR')
|
2000-02-17 17:56:29 +00:00
|
|
|
elif node.flags == 'OP_DELETE':
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('DELETE_SUBSCR')
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
return 1
|
|
|
|
|
|
|
|
def visitSlice(self, node):
|
|
|
|
self.visit(node.expr)
|
|
|
|
slice = 0
|
|
|
|
if node.lower:
|
|
|
|
self.visit(node.lower)
|
|
|
|
slice = slice | 1
|
|
|
|
if node.upper:
|
|
|
|
self.visit(node.upper)
|
|
|
|
slice = slice | 2
|
|
|
|
if node.flags == 'OP_APPLY':
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SLICE+%d' % slice)
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
elif node.flags == 'OP_ASSIGN':
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('STORE_SLICE+%d' % slice)
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
elif node.flags == 'OP_DELETE':
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('DELETE_SLICE+%d' % slice)
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
else:
|
2000-02-15 23:45:26 +00:00
|
|
|
print "weird slice", node.flags
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
raise
|
|
|
|
return 1
|
|
|
|
|
2000-02-15 23:45:26 +00:00
|
|
|
def visitSliceobj(self, node):
|
|
|
|
for child in node.nodes:
|
|
|
|
print child
|
|
|
|
self.visit(child)
|
|
|
|
self.emit('BUILD_SLICE', len(node.nodes))
|
|
|
|
return 1
|
|
|
|
|
2000-02-08 21:15:48 +00:00
|
|
|
def visitAssign(self, node):
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
2000-02-08 21:15:48 +00:00
|
|
|
self.visit(node.expr)
|
2000-02-17 17:56:29 +00:00
|
|
|
dups = len(node.nodes) - 1
|
2000-02-14 14:14:29 +00:00
|
|
|
for i in range(len(node.nodes)):
|
2000-02-17 17:56:29 +00:00
|
|
|
elt = node.nodes[i]
|
|
|
|
if i < dups:
|
|
|
|
self.emit('DUP_TOP')
|
2000-02-08 21:15:48 +00:00
|
|
|
if isinstance(elt, ast.Node):
|
|
|
|
self.visit(elt)
|
|
|
|
return 1
|
|
|
|
|
|
|
|
def visitAssName(self, node):
|
2000-02-16 00:55:44 +00:00
|
|
|
# XXX handle OP_DELETE
|
2000-02-08 21:15:48 +00:00
|
|
|
if node.flags != 'OP_ASSIGN':
|
|
|
|
print "oops", node.flags
|
2000-02-10 17:20:39 +00:00
|
|
|
self.storeName(node.name)
|
2000-02-08 21:15:48 +00:00
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def visitAssAttr(self, node):
|
2000-02-16 00:55:44 +00:00
|
|
|
self.visit(node.expr)
|
|
|
|
if node.flags == 'OP_ASSIGN':
|
|
|
|
self.emit('STORE_ATTR', node.attrname)
|
|
|
|
elif node.flags == 'OP_DELETE':
|
|
|
|
self.emit('DELETE_ATTR', node.attrname)
|
|
|
|
else:
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
print "warning: unexpected flags:", node.flags
|
|
|
|
print node
|
|
|
|
return 1
|
|
|
|
|
|
|
|
def visitAssTuple(self, node):
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('UNPACK_TUPLE', len(node.nodes))
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
for child in node.nodes:
|
|
|
|
self.visit(child)
|
|
|
|
return 1
|
|
|
|
|
|
|
|
visitAssList = visitAssTuple
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
def binaryOp(self, node, op):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.visit(node.left)
|
|
|
|
self.visit(node.right)
|
|
|
|
self.emit(op)
|
|
|
|
return 1
|
2000-02-04 00:28:21 +00:00
|
|
|
|
2000-02-08 21:15:48 +00:00
|
|
|
def unaryOp(self, node, op):
|
|
|
|
self.visit(node.expr)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit(op)
|
2000-02-08 21:15:48 +00:00
|
|
|
return 1
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
def visitAdd(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.binaryOp(node, 'BINARY_ADD')
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def visitSub(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.binaryOp(node, 'BINARY_SUBTRACT')
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def visitMul(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.binaryOp(node, 'BINARY_MULTIPLY')
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def visitDiv(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.binaryOp(node, 'BINARY_DIVIDE')
|
2000-02-04 00:28:21 +00:00
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def visitMod(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.binaryOp(node, 'BINARY_MODULO')
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
|
2000-02-14 21:33:10 +00:00
|
|
|
def visitPower(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.binaryOp(node, 'BINARY_POWER')
|
2000-02-14 21:33:10 +00:00
|
|
|
|
|
|
|
def visitLeftShift(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.binaryOp(node, 'BINARY_LSHIFT')
|
2000-02-14 21:33:10 +00:00
|
|
|
|
|
|
|
def visitRightShift(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.binaryOp(node, 'BINARY_RSHIFT')
|
2000-02-14 21:33:10 +00:00
|
|
|
|
|
|
|
def visitInvert(self, node):
|
|
|
|
return self.unaryOp(node, 'UNARY_INVERT')
|
|
|
|
|
2000-02-08 21:15:48 +00:00
|
|
|
def visitUnarySub(self, node):
|
|
|
|
return self.unaryOp(node, 'UNARY_NEGATIVE')
|
|
|
|
|
|
|
|
def visitUnaryAdd(self, node):
|
|
|
|
return self.unaryOp(node, 'UNARY_POSITIVE')
|
|
|
|
|
|
|
|
def visitUnaryInvert(self, node):
|
|
|
|
return self.unaryOp(node, 'UNARY_INVERT')
|
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def visitNot(self, node):
|
|
|
|
return self.unaryOp(node, 'UNARY_NOT')
|
|
|
|
|
2000-02-08 21:15:48 +00:00
|
|
|
def visitBackquote(self, node):
|
|
|
|
return self.unaryOp(node, 'UNARY_CONVERT')
|
|
|
|
|
2000-02-14 14:14:29 +00:00
|
|
|
def bitOp(self, nodes, op):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.visit(nodes[0])
|
|
|
|
for node in nodes[1:]:
|
|
|
|
self.visit(node)
|
|
|
|
self.emit(op)
|
|
|
|
return 1
|
2000-02-14 14:14:29 +00:00
|
|
|
|
|
|
|
def visitBitand(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.bitOp(node.nodes, 'BINARY_AND')
|
2000-02-14 14:14:29 +00:00
|
|
|
|
|
|
|
def visitBitor(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.bitOp(node.nodes, 'BINARY_OR')
|
2000-02-14 14:14:29 +00:00
|
|
|
|
|
|
|
def visitBitxor(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.bitOp(node.nodes, 'BINARY_XOR')
|
2000-02-14 14:14:29 +00:00
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def visitTest(self, node, jump):
|
|
|
|
end = StackRef()
|
|
|
|
for child in node.nodes[:-1]:
|
|
|
|
self.visit(child)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit(jump, end)
|
|
|
|
self.emit('POP_TOP')
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
self.visit(node.nodes[-1])
|
|
|
|
end.bind(self.code.getCurInst())
|
|
|
|
return 1
|
|
|
|
|
2000-02-14 14:14:29 +00:00
|
|
|
def visitAssert(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
# XXX __debug__ and AssertionError appear to be special cases
|
|
|
|
# -- they are always loaded as globals even if there are local
|
|
|
|
# names. I guess this is a sort of renaming op.
|
|
|
|
skip = StackRef()
|
|
|
|
self.emit('SET_LINENO', node.lineno)
|
|
|
|
self.emit('LOAD_GLOBAL', '__debug__')
|
|
|
|
self.emit('JUMP_IF_FALSE', skip)
|
|
|
|
self.emit('POP_TOP')
|
|
|
|
self.visit(node.test)
|
|
|
|
self.emit('JUMP_IF_TRUE', skip)
|
|
|
|
self.emit('LOAD_GLOBAL', 'AssertionError')
|
|
|
|
self.visit(node.fail)
|
|
|
|
self.emit('RAISE_VARARGS', 2)
|
|
|
|
skip.bind(self.code.getCurInst())
|
|
|
|
self.emit('POP_TOP')
|
|
|
|
return 1
|
2000-02-14 14:14:29 +00:00
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def visitAnd(self, node):
|
|
|
|
return self.visitTest(node, 'JUMP_IF_FALSE')
|
|
|
|
|
|
|
|
def visitOr(self, node):
|
|
|
|
return self.visitTest(node, 'JUMP_IF_TRUE')
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
def visitName(self, node):
|
2000-02-10 17:20:39 +00:00
|
|
|
self.loadName(node.name)
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def visitConst(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.emit('LOAD_CONST', node.value)
|
2000-02-08 21:15:48 +00:00
|
|
|
return 1
|
|
|
|
|
2000-02-14 14:14:29 +00:00
|
|
|
def visitEllipsis(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.emit('LOAD_CONST', Ellipsis)
|
|
|
|
return 1
|
2000-02-14 14:14:29 +00:00
|
|
|
|
2000-02-08 21:15:48 +00:00
|
|
|
def visitTuple(self, node):
|
|
|
|
for elt in node.nodes:
|
|
|
|
self.visit(elt)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('BUILD_TUPLE', len(node.nodes))
|
2000-02-08 21:15:48 +00:00
|
|
|
return 1
|
2000-02-04 00:28:21 +00:00
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def visitList(self, node):
|
|
|
|
for elt in node.nodes:
|
|
|
|
self.visit(elt)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.emit('BUILD_LIST', len(node.nodes))
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
return 1
|
|
|
|
|
2000-02-14 14:14:29 +00:00
|
|
|
def visitDict(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.emit('BUILD_MAP', 0)
|
|
|
|
for k, v in node.items:
|
|
|
|
# XXX need to add set lineno when there aren't constants
|
|
|
|
self.emit('DUP_TOP')
|
|
|
|
self.visit(v)
|
|
|
|
self.emit('ROT_TWO')
|
|
|
|
self.visit(k)
|
|
|
|
self.emit('STORE_SUBSCR')
|
|
|
|
return 1
|
2000-02-14 14:14:29 +00:00
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
def visitReturn(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
|
|
|
self.visit(node.value)
|
|
|
|
self.emit('RETURN_VALUE')
|
|
|
|
return 1
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def visitRaise(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
|
|
|
n = 0
|
|
|
|
if node.expr1:
|
|
|
|
self.visit(node.expr1)
|
|
|
|
n = n + 1
|
|
|
|
if node.expr2:
|
|
|
|
self.visit(node.expr2)
|
|
|
|
n = n + 1
|
|
|
|
if node.expr3:
|
|
|
|
self.visit(node.expr3)
|
|
|
|
n = n + 1
|
|
|
|
self.emit('RAISE_VARARGS', n)
|
|
|
|
return 1
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def visitPrint(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.emit('SET_LINENO', node.lineno)
|
|
|
|
for child in node.nodes:
|
|
|
|
self.visit(child)
|
|
|
|
self.emit('PRINT_ITEM')
|
|
|
|
return 1
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def visitPrintnl(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.visitPrint(node)
|
|
|
|
self.emit('PRINT_NEWLINE')
|
|
|
|
return 1
|
2000-02-04 19:37:35 +00:00
|
|
|
|
2000-02-14 14:14:29 +00:00
|
|
|
def visitExec(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.visit(node.expr)
|
|
|
|
if node.locals is None:
|
|
|
|
self.emit('LOAD_CONST', None)
|
|
|
|
else:
|
|
|
|
self.visit(node.locals)
|
|
|
|
if node.globals is None:
|
|
|
|
self.emit('DUP_TOP')
|
|
|
|
else:
|
|
|
|
self.visit(node.globals)
|
|
|
|
self.emit('EXEC_STMT')
|
2000-02-14 14:14:29 +00:00
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
class LocalNameFinder:
|
|
|
|
def __init__(self, names=()):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.names = misc.Set()
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
self.globals = misc.Set()
|
2000-02-17 17:56:29 +00:00
|
|
|
for name in names:
|
|
|
|
self.names.add(name)
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def getLocals(self):
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
for elt in self.globals.items():
|
|
|
|
if self.names.has_elt(elt):
|
|
|
|
self.names.remove(elt)
|
2000-02-17 17:56:29 +00:00
|
|
|
return self.names
|
2000-02-04 00:28:21 +00:00
|
|
|
|
2000-02-14 14:14:29 +00:00
|
|
|
def visitDict(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
return 1
|
2000-02-14 14:14:29 +00:00
|
|
|
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
def visitGlobal(self, node):
|
|
|
|
for name in node.names:
|
|
|
|
self.globals.add(name)
|
|
|
|
return 1
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
def visitFunction(self, node):
|
|
|
|
self.names.add(node.name)
|
2000-02-17 17:56:29 +00:00
|
|
|
return 1
|
2000-02-04 00:28:21 +00:00
|
|
|
|
2000-02-11 20:27:07 +00:00
|
|
|
def visitLambda(self, node):
|
|
|
|
return 1
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
def visitImport(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
for name in node.names:
|
|
|
|
self.names.add(name)
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def visitFrom(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
for name in node.names:
|
|
|
|
self.names.add(name)
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def visitClassdef(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.names.add(node.name)
|
|
|
|
return 1
|
2000-02-04 00:28:21 +00:00
|
|
|
|
|
|
|
def visitAssName(self, node):
|
2000-02-17 17:56:29 +00:00
|
|
|
self.names.add(node.name)
|
2000-02-04 00:28:21 +00:00
|
|
|
|
2000-02-10 20:55:50 +00:00
|
|
|
class Loop:
|
|
|
|
def __init__(self):
|
|
|
|
self.startAnchor = StackRef()
|
|
|
|
self.breakAnchor = StackRef()
|
|
|
|
self.extentAnchor = StackRef()
|
2000-02-04 00:28:21 +00:00
|
|
|
|
2000-02-08 19:01:29 +00:00
|
|
|
class CompiledModule:
|
|
|
|
"""Store the code object for a compiled module
|
|
|
|
|
|
|
|
XXX Not clear how the code objects will be stored. Seems possible
|
|
|
|
that a single code attribute is sufficient, because it will
|
|
|
|
contains references to all the need code objects. That might be
|
|
|
|
messy, though.
|
|
|
|
"""
|
|
|
|
MAGIC = (20121 | (ord('\r')<<16) | (ord('\n')<<24))
|
|
|
|
|
|
|
|
def __init__(self, source, filename):
|
|
|
|
self.source = source
|
|
|
|
self.filename = filename
|
|
|
|
|
|
|
|
def compile(self):
|
|
|
|
t = transformer.Transformer()
|
|
|
|
self.ast = t.parsesuite(self.source)
|
|
|
|
cg = CodeGenerator(self.filename)
|
2000-02-16 00:55:44 +00:00
|
|
|
walk(self.ast, cg)
|
2000-02-14 14:14:29 +00:00
|
|
|
self.code = cg.asConst()
|
2000-02-08 19:01:29 +00:00
|
|
|
|
|
|
|
def dump(self, path):
|
|
|
|
"""create a .pyc file"""
|
|
|
|
f = open(path, 'wb')
|
|
|
|
f.write(self._pyc_header())
|
|
|
|
marshal.dump(self.code, f)
|
|
|
|
f.close()
|
|
|
|
|
|
|
|
def _pyc_header(self):
|
|
|
|
# compile.c uses marshal to write a long directly, with
|
|
|
|
# calling the interface that would also generate a 1-byte code
|
|
|
|
# to indicate the type of the value. simplest way to get the
|
|
|
|
# same effect is to call marshal and then skip the code.
|
|
|
|
magic = marshal.dumps(self.MAGIC)[1:]
|
|
|
|
mtime = os.stat(self.filename)[stat.ST_MTIME]
|
|
|
|
mtime = struct.pack('i', mtime)
|
|
|
|
return magic + mtime
|
2000-02-17 17:56:29 +00:00
|
|
|
|
|
|
|
def compile(filename):
|
|
|
|
buf = open(filename).read()
|
|
|
|
mod = CompiledModule(buf, filename)
|
|
|
|
mod.compile()
|
|
|
|
mod.dump(filename + 'c')
|
|
|
|
|
2000-02-04 00:28:21 +00:00
|
|
|
if __name__ == "__main__":
|
2000-02-08 21:15:48 +00:00
|
|
|
import getopt
|
|
|
|
|
2000-02-16 00:55:44 +00:00
|
|
|
VERBOSE = 0
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
opts, args = getopt.getopt(sys.argv[1:], 'vq')
|
2000-02-08 21:15:48 +00:00
|
|
|
for k, v in opts:
|
|
|
|
if k == '-v':
|
2000-02-16 00:55:44 +00:00
|
|
|
VERBOSE = 1
|
2000-02-08 21:15:48 +00:00
|
|
|
ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
|
add ExampleASTVisitor:
* prints out examples of nodes that are handled by visitor. simply a
development convenience
remove NestedCodeGenerator -- it was bogus after all
replace with generateFunctionCode, a method to call to generate code
for a function instead of a top-level module
fix impl of visitDiscard (most pop stack)
emit lineno for pass
handle the following new node types: Import, From, Getattr, Subscript,
Slice, AssAttr, AssTuple, Mod, Not, And, Or, List
LocalNameFinder: remove names declared as globals for locals
PythonVMCode: pass arg names to constructor, force varnames to contain
them all (even if they aren't referenced)
add -q option on command line to disable stdout
2000-02-10 00:47:08 +00:00
|
|
|
if k == '-q':
|
|
|
|
f = open('/dev/null', 'wb')
|
|
|
|
sys.stdout = f
|
2000-02-16 00:55:44 +00:00
|
|
|
if not args:
|
|
|
|
print "no files to compile"
|
2000-02-08 19:01:29 +00:00
|
|
|
else:
|
2000-02-16 00:55:44 +00:00
|
|
|
for filename in args:
|
|
|
|
if VERBOSE:
|
|
|
|
print filename
|
2000-02-17 17:56:29 +00:00
|
|
|
compile(filename)
|