Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 9 Next »

Pipelines consist of a set of steps that the compiler passes the code through. The source code for all the steps is here.

The order of steps when you compile a script is like this:

  1. First the Boo Parser (and lexer): Boo.Lang.Parser.BooParsingStep.
    1. The rules the Boo parser uses are defined in this ANTLR grammar file
    2. The boo lexer turns the text script into a set of tokens, and the boo parser converts the tokens into an abstract syntax tree (AST). I'll show examples of this later on. Each step after the parser is basically just working on this AST and transforming it. At the end, the AST is used to produce raw .NET assembly code (IL). The steps that happen after the parser step:
  2. InitializeTypeSystemServices
  3. PreErrorChecking
  4. InitializeNameResolutionService
  5. IntroduceGlobalNamespaces
  6. TransformCallableDefinitions
  7. BindTypeDefinitions
  8. BindNamespaces
  9. BindBaseTypes
  10. BindAndApplyAttributes
  11. ExpandMacros
  12. IntroduceModuleClasses
  13. NormalizeStatementModifiers
  14. NormalizeTypeAndMemberDefinitions
  15. BindTypeDefinitions
  16. BindBaseTypes
  17. ResolveTypeReferences
  18. BindTypeMembers
  19. ProcessInheritedAbstractMembers
  20. ProcessMethodBodiesWithDuckTyping
  21. ProcessAssignmentsToValueTypeMembers
  22. ExpandProperties
  23. StricterErrorChecking
  24. RemoveDeadCode
  25. NormalizeIterationStatements
  26. ProcessSharedLocals
  27. ProcessClosures
  28. ProcessGenerators
  29. InjectCallableConversions
  30. ImplementICallableOnCallableDefinitions
  31. EmitAssembly
  32. and finally SaveAssembly or RunAssembly

Here is a script that spits out the AST after each step in the compile process, in xml or boo format. It doesn't show everything going on, because only the visible changes to the AST structure itself are shown. See the source code for each step and for the boo compiler for more details.

showsteps.boo
//By DougHolton
/*
This script visits the AST structure after each step in the compile process
and converts it to XML or back to boo syntax.
If there are visible differences since the previous step, it saves the output
to a file in a folder named "compilersteps".

How to run:

/path/to/booi.exe path/to/showsteps.boo [-xml] [-types] path/to/your/script.boo

You can also use the "-r:assembly.dll" flag to add assembly references.

It will generate a folder in the current directory named "compilersteps",
and put copies of the script as it looks after each compiler step in that folder.
*/

import System
import System.IO
import System.Xml.Serialization from System.Xml
import Boo.Lang.Compiler from Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Pipelines
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Ast.Visitors
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.Steps
import System.Reflection

[Module]
class Globals:
	static format = "boo" //or "xml" //format for output
	static foldername = "compilersteps" //folder where files are saved
	static showtypes = false  //whether to print typesystem information
	static showexp = false //show expression types as well
	//used internally:
	static savefolder as string
	static n = 0
	static laststep as string
	
class BooTypePrinterVisitor(BooPrinterVisitor):
	_showexp = false
	def constructor(writer as TextWriter, show_expressions as bool):
		super(writer)
		_showexp = show_expressions
		
	override def Visit(node as Node) as bool:
		tagname = ""
		if node is not null:
			entity = TypeSystemServices.GetOptionalEntity(node)
			if entity is not null:
				tagname = entity.GetType().ToString(). \
					Replace("Boo.Lang.Compiler.TypeSystem.","")
				s = "<"
				s += tagname
				
				if _showexp:
					exp = node as Expression
					if exp is not null and exp.ExpressionType is not null:
						s += " ExpType="+exp.ExpressionType.ToString()
						
				s += ">"
				Write(s)
		result = super(node)
		if tagname != "":
			Write("</"+tagname+">")
		return result
	
def PrintAST([required]result as CompilerContext, [required]o as TextWriter):
	astobject = result.CompileUnit
	try:
		s = XmlSerializer( astobject.GetType() )
	except e:
		print e.Message
		return
	try:
		s.Serialize( o, astobject )
	except e:
		print "\n", e.ToString()

def AfterStep(sender, e as CompilerStepEventArgs):
	++n
	stepname = e.Step.ToString().Replace("Boo.Lang.Parser.","").Replace("Boo.Lang.Compiler.Steps.","")
	
	tempfile = Path.GetTempFileName()
	using temp = StreamWriter(tempfile):
		if format == "xml":
			PrintAST(e.Context, temp)
		else:
			printer as BooPrinterVisitor
			if showtypes:
				printer = BooTypePrinterVisitor(temp, showexp)
			else:
				printer = BooPrinterVisitor(temp)
			printer.Print(e.Context.CompileUnit)
	
	using r = StreamReader(tempfile):
		thisstep = r.ReadToEnd()
		
	filename = string.Format("STEP{0:D2}-{1}.{2}", n, stepname, format)
	
	if thisstep != laststep:
		File.Move(tempfile, Path.Combine(savefolder, filename))
		laststep = thisstep
		print string.Format("STEP{0:D2}-{1}: SAVED TO {2} FILE.", n, stepname, format.ToUpper())
	else:
		File.Delete(tempfile)
		print string.Format("STEP{0:D2}-{1}: NO CHANGE TO AST.", n, stepname)
	
def LoadAssembly(assemblyName as string) as Assembly:
	reference as Assembly
	if File.Exists(Path.GetFullPath(assemblyName)):
		reference = Assembly.LoadFrom(Path.GetFullPath(assemblyName))
	if reference is null:
		reference = Assembly.LoadWithPartialName(assemblyName)
		if reference is null:
			raise ApplicationException(ResourceManager.Format("BooC.UnableToLoadAssembly", assemblyName))
	return reference

///////////////////////////////////////////////////

if len(argv) == 0:
	print "Please specify at least one boo file as a parameter"
	return

compiler = BooCompiler()

//delete old folder if running more than once:
if Directory.Exists(foldername):
	Directory.Delete(foldername, true)
	
savedir = Directory.CreateDirectory(foldername)
if savedir is null or not Directory.Exists(foldername):
	print "The directory '${foldername}' could not be created."
	return

savefolder = savedir.FullName

compiler.Parameters.Pipeline = Compile()
compiler.Parameters.Pipeline.AfterStep += AfterStep

for arg in argv:
	if arg[0:3] == "-r:":
		compiler.Parameters.References.Add(LoadAssembly(arg[3:]))
	elif arg == "-xml":
		format = "xml"
	elif arg == "-types":
		showtypes = true
	elif arg == "-exp":
		showtypes = true
		showexp = true
	elif arg == "-ducky":
		compiler.Parameters.Ducky = true
	else:
		compiler.Parameters.Input.Add(FileInput(arg))

try:
	print
	print "See boo/src/Boo.Lang.Compiler/Steps/ for the source code for these steps."
	print
	result = compiler.Run()
	if len(result.Errors) > 0:
		print "\nThere were ${len(result.Errors)} errors compiling the boo file(s)"
		print result.Errors.ToString(true)
	else:
		print "\nSuccessful: See the files under: '${savefolder}'"
except e:
	print e.GetType(), ":", e.Message
  • No labels