[Python-checkins] CVS: /python/nondist/src/Compiler/compiler pycodegen.py,1.17,1.18
Jeremy Hylton
jhylton@cnri.reston.va.us
Mon, 6 Mar 2000 14:10:57 -0500
Update of /projects/cvsroot//python/nondist/src/Compiler/compiler
In directory goon.cnri.reston.va.us:/home/jhylton/python/nondist/src/Compiler/compiler
Modified Files:
pycodegen.py
Log Message:
rename compile.py to pycodegen.py
fix imports
remove parse functions and visitor code
track name change: Classdef to Class
add some comments and tweak order of visitXXX methods
get rid of if __name__ == "__main__ section
Index: pycodegen.py
===================================================================
RCS file: /projects/cvsroot//python/nondist/src/Compiler/compiler/pycodegen.py,v
retrieving revision 1.17
retrieving revision 1.18
diff -C2 -r1.17 -r1.18
*** pycodegen.py 2000/02/17 22:09:35 1.17
--- pycodegen.py 2000/03/06 19:10:54 1.18
***************
*** 6,10 ****
"""
! from p2c import transformer, ast
from pyassem import StackRef, PyAssembler, TupleArg
import dis
--- 6,10 ----
"""
! from compiler import parseFile, ast, visitor, walk, parse
from pyassem import StackRef, PyAssembler, TupleArg
import dis
***************
*** 19,159 ****
import types
- def parse(path):
- f = open(path)
- src = f.read()
- f.close()
- t = transformer.Transformer()
- return t.parsesuite(src)
-
- def walk(tree, visitor, verbose=None, walker=None):
- if walker:
- w = walker()
- else:
- w = ASTVisitor()
- if verbose is not None:
- w.VERBOSE = verbose
- w.preorder(tree, visitor)
- return w.visitor
-
- def dumpNode(node):
- print node.__class__
- for attr in dir(node):
- if attr[0] != '_':
- print "\t", "%-10.10s" % attr, getattr(node, attr)
-
- 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?
- """
-
- VERBOSE = 0
-
- def __init__(self):
- self.node = None
-
- 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)
- 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)
-
- class ExampleASTVisitor(ASTVisitor):
- """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.
- """
- 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
-
class CodeGenerator:
"""Generate bytecode for the Python VM"""
--- 19,22 ----
***************
*** 312,316 ****
self.emit('POP_TOP')
! def visitClassdef(self, node):
self.emit('SET_LINENO', node.lineno)
self.emit('LOAD_CONST', node.name)
--- 175,179 ----
self.emit('POP_TOP')
! def visitClass(self, node):
self.emit('SET_LINENO', node.lineno)
self.emit('LOAD_CONST', node.name)
***************
*** 661,664 ****
--- 524,529 ----
visitAssList = visitAssTuple
+ # binary ops
+
def binaryOp(self, node, op):
self.visit(node.left)
***************
*** 667,675 ****
return 1
- def unaryOp(self, node, op):
- self.visit(node.expr)
- self.emit(op)
- return 1
-
def visitAdd(self, node):
return self.binaryOp(node, 'BINARY_ADD')
--- 532,535 ----
***************
*** 696,699 ****
--- 556,566 ----
return self.binaryOp(node, 'BINARY_RSHIFT')
+ # unary ops
+
+ def unaryOp(self, node, op):
+ self.visit(node.expr)
+ self.emit(op)
+ return 1
+
def visitInvert(self, node):
return self.unaryOp(node, 'UNARY_INVERT')
***************
*** 714,717 ****
--- 581,586 ----
return self.unaryOp(node, 'UNARY_CONVERT')
+ # bit ops
+
def bitOp(self, nodes, op):
self.visit(nodes[0])
***************
*** 730,743 ****
return self.bitOp(node.nodes, 'BINARY_XOR')
- def visitTest(self, node, jump):
- end = StackRef()
- for child in node.nodes[:-1]:
- self.visit(child)
- self.emit(jump, end)
- self.emit('POP_TOP')
- self.visit(node.nodes[-1])
- end.bind(self.code.getCurInst())
- return 1
-
def visitAssert(self, node):
# XXX __debug__ and AssertionError appear to be special cases
--- 599,602 ----
***************
*** 758,761 ****
--- 617,630 ----
return 1
+ def visitTest(self, node, jump):
+ end = StackRef()
+ for child in node.nodes[:-1]:
+ self.visit(child)
+ self.emit(jump, end)
+ self.emit('POP_TOP')
+ self.visit(node.nodes[-1])
+ end.bind(self.code.getCurInst())
+ return 1
+
def visitAnd(self, node):
return self.visitTest(node, 'JUMP_IF_FALSE')
***************
*** 880,884 ****
self.names.add(name)
! def visitClassdef(self, node):
self.names.add(node.name)
return 1
--- 749,753 ----
self.names.add(name)
! def visitClass(self, node):
self.names.add(node.name)
return 1
***************
*** 922,927 ****
def compile(self):
! t = transformer.Transformer()
! self.ast = t.parsesuite(self.source)
cg = CodeGenerator(self.filename)
walk(self.ast, cg)
--- 791,795 ----
def compile(self):
! self.ast = parse(self.source)
cg = CodeGenerator(self.filename)
walk(self.ast, cg)
***************
*** 951,971 ****
mod.dump(filename + 'c')
- if __name__ == "__main__":
- import getopt
-
- VERBOSE = 0
- opts, args = getopt.getopt(sys.argv[1:], 'vq')
- for k, v in opts:
- if k == '-v':
- VERBOSE = 1
- ASTVisitor.VERBOSE = ASTVisitor.VERBOSE + 1
- if k == '-q':
- f = open('/dev/null', 'wb')
- sys.stdout = f
- if not args:
- print "no files to compile"
- else:
- for filename in args:
- if VERBOSE:
- print filename
- compile(filename)
--- 819,820 ----