2 // Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Rodrigo B. de Oliveira nor the names of its
14 // contributors may be used to endorse or promote products derived from this
15 // software without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 // By Doug Holton. More stuff added by David Piepgrass.
31 // For help, please see the help string below.
34 import System
.Xml
.Serialization
from System
.Xml
35 import Boo
.Lang
.Compiler
from Boo
.Lang
.Compiler
36 import Boo
.Lang
.Compiler
.IO
37 import Boo
.Lang
.Compiler
.Pipelines
38 import Boo
.Lang
.Compiler
.Ast
39 import Boo
.Lang
.Compiler
.Ast
.Visitors
40 import Boo
.Lang
.Compiler
.TypeSystem
41 import Boo
.Lang
.Compiler
.Steps
42 import System
.Reflection
44 [System
.Runtime
.CompilerServices
.CompilerGlobalScopeAttribute
]
47 This script visits the AST structure after each step in the compile
49 and converts it to XML or back to boo syntax. If there are visible
50 differences since the previous step, it saves the output to a file in a
52 folder named after the command-line arguments (name of source file plus
58 booi path/to/showcompilersteps.boo [-xml | (-ent | -exp | -nodes) [-short]
60 path/to/your/script.boo
62 -xml: generate XML representation of AST
63 -ent: show entity type names that are associated with AST nodes
65 -exp: show entity type names and expression types (node.ExpressionType)
66 -nodes: show entity type names and expression types, and for each typed
68 expression, also show the AST type (node.GetType())
69 -bind: show binding information contained in entities
70 -short: abbreviate the output so that lines hopefully fit on your
73 You can also use the "-r:assembly.dll" flag to add assembly references.
75 ShowSteps will generate a folder in the current directory named after
77 input file and the options you specified. It generates copies of the
79 after each compiler step, and puts them in that folder.
81 If you use -exp -nodes -bind, the output can get pretty long and
83 For example, a simple expression like "_x", that refers to a variable
85 the current class, eventually expands to a the following (all on one
88 <InternalField MemberReferenceExpression=double
89 Bind=Field:Ns.MyClass._x>
90 <InternalMethod SelfLiteralExpression=Foo.B
91 Bind=Method:Ns.MyClass.MyFn>
92 self</InternalMethod>._x
95 The -short command-line option will use an abbreviated syntax like
98 <ItlField MemberRefrExpr=double @F:Ns.MyClass._x>
99 <ItlMethod SelfLiteralExpr=Foo.B @M:Ns.MyClass.MyFn>
103 Here's how to understand it. First of all, of course, it's not really
105 it's just an XML-like notation. If you have a text editor that can do
107 syntax highlighting, use it. Second, notice that a reference to "self"
109 been added. Third, the outer tag (InternalField) describes the whole
110 expression, "self._x", whereas the inner tag (InternalMethod) describes
111 only the "self" part. The tags have the following syntax:
113 <E N=T Bind=S:P> where
115 N: Class of AST node. For example, "MemberReferenceExpression" refers
116 to the Boo.Lang.Compiler.Ast.MemberReferenceExpression class.
117 T: The value of node.ExpressionType.ToString(), e.g. int
118 E: Type of entity associated with the node, or "_" if the node has no
119 entity. For example, "InternalField" actually refers to the
120 Boo.Lang.Compiler.TypeSystem.InternalField class. It seems that an
121 entity's main purpose is to hold binding information.
122 S: The entity's EntityType (although I don't actually know what it's
124 If the EntityType is EntityType.Type, which is the most common
127 P: Binding Path. For example, X.Y.Z might represent a variable or
129 "Z" in class "Y" in namespace "X".
131 A tag is not printed at all if there is no entity nor data type
132 associated with a node. That's why you don't see very many tags during
133 the first compiler steps. The "N=T" part is printed only if the node is
134 an Expression and it has a a known data type; the Bind=S:P part is only
136 printed if binding information is available.
138 static format
= "boo" //or "xml" //format for output
139 static foldername
= "compilersteps" //folder where files are saved
140 static showents
= false //whether to print entity types
141 static showexp
= false //show expression types as well
142 static shownodetypes
= false
143 static shorten
= false
144 static showbindings
= false
146 static savefolder
as string
148 static laststep
as string
150 //basic boo printer visitor, but adds comments if a node is synthetic (generated
151 //by the compiler instead of the user).
152 class BooSyntheticPrinterVisitor(BooPrinterVisitor
):
153 def constructor(writer
as TextWriter
):
155 override def Visit(node
as Node
) as bool
:
156 if node
is not null and node
.IsSynthetic
:
157 WriteIndented("// synthetic")
162 class BooTypePrinterVisitor(BooPrinterVisitor
):
164 _shownodetypes
= false
166 _showbindings
= false
167 def constructor(writer
as TextWriter
, show_expressions
as bool
, shownodetypes
as bool
, shorten
as bool
, showbindings
as bool
):
169 _showexp
= show_expressions
170 _shownodetypes
= shownodetypes
172 _showbindings
= showbindings
174 override def Visit(node
as Node
) as bool
:
175 return true if node
is null
177 WriteIndented("// synthetic")
180 WriteIndented() // Automatically indent iff starting a new line
183 entity
= TypeSystemServices
.GetOptionalEntity(node
) // aka node.Entity
184 if entity
is not null:
185 tagname
= ShortName(entity
.GetType())
192 tagname
= InitialsOf(tagname
)
193 elif _showexp
or _showbindings
:
194 junk
= ExtraJunk(node
)
202 WriteIndented("</"+tagname
+">")
205 def ShortName(t
as object
):
207 Replace("Boo.Lang.Compiler.TypeSystem.",""). \
208 Replace("Boo.Lang.Compiler.Ast.","")
209 return t2
unless _shorten
211 Replace("Expression", "Expr"). \
212 Replace("Reference", "Refr"). \
213 Replace("Internal", "Itl").Replace("External", "Xtl")
215 def InitialsOf(s
as string
):
216 s2
= System
.Text
.StringBuilder()
218 if ch
>= char('A') and ch
<= char('Z'):
225 def ExtraJunk(node
as Node
):
226 s
= System
.Text
.StringBuilder()
228 exp
= node
as Expression
229 if exp
is not null and exp
.ExpressionType
is not null:
232 s
.Append(ShortName(node
.GetType()))
238 s
.Append(ShortName(exp
.ExpressionType
.ToString()))
241 entity
= TypeSystemServices
.GetOptionalEntity(node
) // aka node.Entity
242 if entity
is not null:
247 if entity
.EntityType
!= EntityType
.Type
:
249 s
.Append(InitialsOf(entity
.EntityType
.ToString()))
251 s
.Append(entity
.EntityType
.ToString())
253 s
.Append(entity
.FullName
)
256 def PrintAST([required
]result
as CompilerContext
, [required
]o
as TextWriter
):
257 astobject
= result
.CompileUnit
259 s
= XmlSerializer( astobject
.GetType() )
260 s
.Serialize( o
, astobject
)
263 print e
.GetType(), ":", e
.Message
265 def AfterStep(sender
, e
as CompilerStepEventArgs
):
267 stepname
= e
.Step
.ToString().Replace("Boo.Lang.Parser.","").Replace("Boo.Lang.Compiler.Steps.","")
269 tempfile
= Path
.GetTempFileName()
270 using temp
= StreamWriter(tempfile
):
272 PrintAST(e
.Context
, temp
)
275 printer
as BooPrinterVisitor
277 printer
= BooTypePrinterVisitor(temp
, showexp
, shownodetypes
, shorten
, showbindings
)
279 printer
= BooSyntheticPrinterVisitor(temp
)
280 printer
.Print(e
.Context
.CompileUnit
)
282 print e
.Message
+ "\n" + e
.StackTrace
284 using r
= StreamReader(tempfile
):
285 thisstep
= r
.ReadToEnd()
287 filename
= string
.Format("STEP{0:D2}-{1}.{2}", n
, stepname
, format
)
289 if thisstep
!= laststep
:
290 File
.Move(tempfile
, Path
.Combine(savefolder
, filename
))
292 print string
.Format("STEP{0:D2}-{1}: SAVED TO {2} FILE.", n
, stepname
, format
.ToUpper())
294 File
.Delete(tempfile
)
295 print string
.Format("STEP{0:D2}-{1}: NO CHANGE TO AST.", n
, stepname
)
297 def LoadAssembly(assemblyName
as string
) as Assembly
:
298 reference
as Assembly
299 if File
.Exists(Path
.GetFullPath(assemblyName
)):
300 reference
= Assembly
.LoadFrom(Path
.GetFullPath(assemblyName
))
301 if reference
is null:
302 reference
= Assembly
.LoadWithPartialName(assemblyName
)
303 if reference
is null:
304 raise ApplicationException(
305 ResourceManager
.Format("BooC.UnableToLoadAssembly",
309 ///////////////////////////////////////////////////
315 compiler
= BooCompiler()
317 compiler
.Parameters
.Pipeline
= Compile()
318 compiler
.Parameters
.Pipeline
.AfterStep
+= AfterStep
320 foldername_base
= foldername_extra
= ""
324 if arg
[0:3] == "-r:":
325 compiler
.Parameters
.References
.Add(LoadAssembly(arg
[3:]))
334 elif arg
== "-ducky":
335 compiler
.Parameters
.Ducky
= true
336 elif arg
== "-nodes":
340 elif arg
== "-short":
345 compiler
.Parameters
.Input
.Add(FileInput(arg
))
346 foldername_base
+= /^
(.*?
[\
/\\])*([^
\\\
/]+?
)(\
.[^
.\\\
/]*)?$
/.Match(arg
).Groups
[2]
348 foldername_extra
+= " " + arg
350 foldername
= foldername_base
+ foldername_extra
352 //delete old folder if running more than once:
353 if Directory
.Exists(foldername
):
354 Directory
.Delete(foldername
, true)
356 savedir
= Directory
.CreateDirectory(foldername
)
357 if savedir
is null or not Directory
.Exists(foldername
):
358 print "The directory '${foldername}' could not be created."
361 savefolder
= savedir
.FullName
365 print "See boo/src/Boo.Lang.Compiler/Steps/ for the source code for these steps."
367 result
= compiler
.Run()
368 if len(result
.Errors
) > 0:
369 print "\nThere were ${len(result.Errors)} errors compiling the boo file(s)"
370 print result
.Errors
.ToString(true)
372 print "\nSuccessful: See the files under: '${savefolder}'"
374 print e
.GetType(), ":", e
.Message