55a generic tool and CodeGenerator as a specific tool.
66"""
77
8- from p2c import transformer , ast
8+ from compiler import parseFile , ast , visitor , walk , parse
99from pyassem import StackRef , PyAssembler , TupleArg
1010import dis
1111import misc
1818import struct
1919import types
2020
21- def parse (path ):
22- f = open (path )
23- src = f .read ()
24- f .close ()
25- t = transformer .Transformer ()
26- return t .parsesuite (src )
27-
28- def walk (tree , visitor , verbose = None , walker = None ):
29- if walker :
30- w = walker ()
31- else :
32- w = ASTVisitor ()
33- if verbose is not None :
34- w .VERBOSE = verbose
35- w .preorder (tree , visitor )
36- return w .visitor
37-
38- def dumpNode (node ):
39- print node .__class__
40- for attr in dir (node ):
41- if attr [0 ] != '_' :
42- print "\t " , "%-10.10s" % attr , getattr (node , attr )
43-
44- class ASTVisitor :
45- """Performs a depth-first walk of the AST
46-
47- The ASTVisitor will walk the AST, performing either a preorder or
48- postorder traversal depending on which method is called.
49-
50- methods:
51- preorder(tree, visitor)
52- postorder(tree, visitor)
53- tree: an instance of ast.Node
54- visitor: an instance with visitXXX methods
55-
56- The ASTVisitor is responsible for walking over the tree in the
57- correct order. For each node, it checks the visitor argument for
58- a method named 'visitNodeType' where NodeType is the name of the
59- node's class, e.g. Classdef. If the method exists, it is called
60- with the node as its sole argument.
61-
62- The visitor method for a particular node type can control how
63- child nodes are visited during a preorder walk. (It can't control
64- the order during a postorder walk, because it is called _after_
65- the walk has occurred.) The ASTVisitor modifies the visitor
66- argument by adding a visit method to the visitor; this method can
67- be used to visit a particular child node. If the visitor method
68- returns a true value, the ASTVisitor will not traverse the child
69- nodes.
70-
71- XXX The interface for controlling the preorder walk needs to be
72- re-considered. The current interface is convenient for visitors
73- that mostly let the ASTVisitor do everything. For something like
74- a code generator, where you want to walk to occur in a specific
75- order, it's a pain to add "return 1" to the end of each method.
76-
77- XXX Perhaps I can use a postorder walk for the code generator?
78- """
79-
80- VERBOSE = 0
81-
82- def __init__ (self ):
83- self .node = None
84-
85- def preorder (self , tree , visitor ):
86- """Do preorder walk of tree using visitor"""
87- self .visitor = visitor
88- visitor .visit = self ._preorder
89- self ._preorder (tree )
90-
91- def _preorder (self , node ):
92- stop = self .dispatch (node )
93- if stop :
94- return
95- for child in node .getChildren ():
96- if isinstance (child , ast .Node ):
97- self ._preorder (child )
98-
99- def postorder (self , tree , visitor ):
100- """Do preorder walk of tree using visitor"""
101- self .visitor = visitor
102- visitor .visit = self ._postorder
103- self ._postorder (tree )
104-
105- def _postorder (self , tree ):
106- for child in node .getChildren ():
107- if isinstance (child , ast .Node ):
108- self ._preorder (child )
109- self .dispatch (node )
110-
111- def dispatch (self , node ):
112- self .node = node
113- className = node .__class__ .__name__
114- meth = getattr (self .visitor , 'visit' + className , None )
115- if self .VERBOSE > 0 :
116- if self .VERBOSE == 1 :
117- if meth is None :
118- print "dispatch" , className
119- else :
120- print "dispatch" , className , (meth and meth .__name__ or '' )
121- if meth :
122- return meth (node )
123-
124- class ExampleASTVisitor (ASTVisitor ):
125- """Prints examples of the nodes that aren't visited
126-
127- This visitor-driver is only useful for development, when it's
128- helpful to develop a visitor incremently, and get feedback on what
129- you still have to do.
130- """
131- examples = {}
132-
133- def dispatch (self , node ):
134- self .node = node
135- className = node .__class__ .__name__
136- meth = getattr (self .visitor , 'visit' + className , None )
137- if self .VERBOSE > 0 :
138- if self .VERBOSE == 1 :
139- if meth is None :
140- print "dispatch" , className
141- else :
142- print "dispatch" , className , (meth and meth .__name__ or '' )
143- if meth :
144- return meth (node )
145- else :
146- klass = node .__class__
147- if self .VERBOSE < 2 :
148- if self .examples .has_key (klass ):
149- return
150- self .examples [klass ] = klass
151- print
152- print klass
153- for attr in dir (node ):
154- if attr [0 ] != '_' :
155- print "\t " , "%-12.12s" % attr , getattr (node , attr )
156- print
157-
15821class CodeGenerator :
15922 """Generate bytecode for the Python VM"""
16023
@@ -311,7 +174,7 @@ def visitFrom(self, node):
311174 self .emit ('IMPORT_FROM' , name )
312175 self .emit ('POP_TOP' )
313176
314- def visitClassdef (self , node ):
177+ def visitClass (self , node ):
315178 self .emit ('SET_LINENO' , node .lineno )
316179 self .emit ('LOAD_CONST' , node .name )
317180 for base in node .bases :
@@ -660,17 +523,14 @@ def visitAssTuple(self, node):
660523
661524 visitAssList = visitAssTuple
662525
526+ # binary ops
527+
663528 def binaryOp (self , node , op ):
664529 self .visit (node .left )
665530 self .visit (node .right )
666531 self .emit (op )
667532 return 1
668533
669- def unaryOp (self , node , op ):
670- self .visit (node .expr )
671- self .emit (op )
672- return 1
673-
674534 def visitAdd (self , node ):
675535 return self .binaryOp (node , 'BINARY_ADD' )
676536
@@ -695,6 +555,13 @@ def visitLeftShift(self, node):
695555 def visitRightShift (self , node ):
696556 return self .binaryOp (node , 'BINARY_RSHIFT' )
697557
558+ # unary ops
559+
560+ def unaryOp (self , node , op ):
561+ self .visit (node .expr )
562+ self .emit (op )
563+ return 1
564+
698565 def visitInvert (self , node ):
699566 return self .unaryOp (node , 'UNARY_INVERT' )
700567
@@ -713,6 +580,8 @@ def visitNot(self, node):
713580 def visitBackquote (self , node ):
714581 return self .unaryOp (node , 'UNARY_CONVERT' )
715582
583+ # bit ops
584+
716585 def bitOp (self , nodes , op ):
717586 self .visit (nodes [0 ])
718587 for node in nodes [1 :]:
@@ -729,16 +598,6 @@ def visitBitor(self, node):
729598 def visitBitxor (self , node ):
730599 return self .bitOp (node .nodes , 'BINARY_XOR' )
731600
732- def visitTest (self , node , jump ):
733- end = StackRef ()
734- for child in node .nodes [:- 1 ]:
735- self .visit (child )
736- self .emit (jump , end )
737- self .emit ('POP_TOP' )
738- self .visit (node .nodes [- 1 ])
739- end .bind (self .code .getCurInst ())
740- return 1
741-
742601 def visitAssert (self , node ):
743602 # XXX __debug__ and AssertionError appear to be special cases
744603 # -- they are always loaded as globals even if there are local
@@ -757,6 +616,16 @@ def visitAssert(self, node):
757616 self .emit ('POP_TOP' )
758617 return 1
759618
619+ def visitTest (self , node , jump ):
620+ end = StackRef ()
621+ for child in node .nodes [:- 1 ]:
622+ self .visit (child )
623+ self .emit (jump , end )
624+ self .emit ('POP_TOP' )
625+ self .visit (node .nodes [- 1 ])
626+ end .bind (self .code .getCurInst ())
627+ return 1
628+
760629 def visitAnd (self , node ):
761630 return self .visitTest (node , 'JUMP_IF_FALSE' )
762631
@@ -879,7 +748,7 @@ def visitFrom(self, node):
879748 for name in node .names :
880749 self .names .add (name )
881750
882- def visitClassdef (self , node ):
751+ def visitClass (self , node ):
883752 self .names .add (node .name )
884753 return 1
885754
@@ -921,8 +790,7 @@ def __init__(self, source, filename):
921790 self .filename = filename
922791
923792 def compile (self ):
924- t = transformer .Transformer ()
925- self .ast = t .parsesuite (self .source )
793+ self .ast = parse (self .source )
926794 cg = CodeGenerator (self .filename )
927795 walk (self .ast , cg )
928796 self .code = cg .asConst ()
@@ -950,22 +818,3 @@ def compile(filename):
950818 mod .compile ()
951819 mod .dump (filename + 'c' )
952820
953- if __name__ == "__main__" :
954- import getopt
955-
956- VERBOSE = 0
957- opts , args = getopt .getopt (sys .argv [1 :], 'vq' )
958- for k , v in opts :
959- if k == '-v' :
960- VERBOSE = 1
961- ASTVisitor .VERBOSE = ASTVisitor .VERBOSE + 1
962- if k == '-q' :
963- f = open ('/dev/null' , 'wb' )
964- sys .stdout = f
965- if not args :
966- print "no files to compile"
967- else :
968- for filename in args :
969- if VERBOSE :
970- print filename
971- compile (filename )
0 commit comments