Advancing Boo – Wer rastet der rostet, drum wird der Compiler gehostet

Genau wie seine großen Brüder und Schwestern bietet auch Boo die Möglichkeit den Compiler entsprechend den im Projekt vorgenommenen Einstellungen wie Ausgabeformat (Konsole, Bibliothek, Windows-Anwendung) Optimierungen und diversen anderen Bereichen anzupassen. Was uns C# allerdings verwährt ist sich selbst als Service bereitzustellen. Was vermutlich in C# 5.0 Einzug in den Mainstream hält, ist bereits jetzt Realität mit Mono oder schon seit Anbeginn in Boo. Boo bietet neben statischem Kompilat auch die Möglichkeit einer Skriptsprache wie IronPython und IronRuby, die es über die DLR zum Hosting geschafft haben. Alles was wir brauchen ist eine Texteingabe und eine Konfiguration.

Um den Transformationsprozess vom Text zum IL Code anzustoßen, benötigen wir … den BooCompiler. Damit können wir Boo in jeder anderen .NET Sprache hosten und nach unseren unbegrenzten Vorstellungen anpassen. Alles kann dem Compiler zum transformieren vorgelegt werden was vom Interface ICompilerInput bedient wird. Diesen Input finden wir im Namespace Boo.Lang.Compiler.IO:

public class FileInput : ICompilerInput
public class ReaderInput : ICompilerInput
public class StringInput : ReaderInput

Alles was wir tun müssen, ist den Compiler richtig zu parametrisieren. D.h. Eigenschaften die sonst in den Projekteinstellungen vorgenommen werden, entsprechend in unserem Code setzen, wie z.B. das Ausgabeformat, Referenzen auf andere Assemblies usw. usf. Hier ein kurzes Beispiel, dass uns den ganzen Prozess veranschaulicht.

BooCompiler compiler = new BooCompiler();
compiler.Parameters.OutputType = CompilerOutputType.ConsoleApplication;
compiler.Parameters.Ducky = false;
compiler.Parameters.GenerateInMemory = false;
compiler.Parameters.Pipeline = new CompileToMemory();
compiler.Parameters.OutputAssembly = "hello_boo_hosting.exe";
compiler.Parameters.Input.Add(new StringInput("hello.boo""a = 'Boo Compiler as a Service World!'\n print a"));

CompilerContext context = compiler.Run();

Damit haben wir es geschafft, ein einfaches Hallo Welt auf die Beine zu stellen.

Schauen wir uns das vorherige Snippet etwas genauer an, was für Neulinge unter umständen nicht gleich klar wird. Ducky bezieht sich auf das Verhalten des Compilers und bestimmt, ob Boo alle Objekte als IQuakFu implizit setzt und damit als Interpreter läuft. Hier sind wir im “dynamic” Modus und können alle Schweinerein nutzen, die uns dieses Konzept zur Verfügung stellt. Damit sparen wir uns die Typangabe as IQuakFu. In C# 4.0 wäre das Äquivalent, gäbe es so etwas:

myVar = "Hallo Welt!"
//anstatt
dynamic myVar = "Hallo Welt!"

Die Parameter kann man sich interaktiv über Code Completion, oder auch gut über den Reflector zu Gemüte ziehen. Deshalb lasse ich sie jetzt ersteinmal so stehen. Ich persöhnlich nutze für solche API Entdeckungsreisen gerne das LINQPad.

Kommen wir zur Compilerpipeline; ein 

IEnumerable<ICompilerStep>
.

Boo liefert schon von Haus aus vordefinierte Pipelines mit, die verschiedene Zwecke bedienen. Zu finden sind diese Pipelines sinngemäß und logischer Weise unter dem Namespace Boo.Lang.Compiler.Pipelines die wir durch Hinzufügen, Einfügen, Entfernen und Ersetzen nach unserem Gusto bearbeiten.

public CompilerPipeline Add(ICompilerStep step);
public CompilerPipeline Insert(int index, ICompilerStep step);
public CompilerPipeline InsertAfter(Type stepExactType, ICompilerStep step);
public CompilerPipeline InsertBefore(Type stepExactType, ICompilerStep step);
public CompilerPipeline Remove(Type stepExactType);
public CompilerPipeline RemoveAt(int index);
public CompilerPipeline Replace(Type stepExactType, ICompilerStep step);

Die Abarbeitung der Pipeline wird durch zweite Events signalisiert. Diese können wir nutzen um in einer IDE (sollten wir zufällig eine selbst bauen wollen) den Fortschritt anzuzeigen.

public event EventHandler<CompilerPipelineEventArgs> After;
public event CompilerStepEventHandler AfterStep;
public event EventHandler<CompilerPipelineEventArgs> Before;
public event CompilerStepEventHandler BeforeStep;

image

Wer mit der Pipeline etwas herumspielen will um zu sehen was passiert kann folgendes Snippet ausprobieren:

var events = new List<string>();
compiler.Parameters.Pipeline.BeforeStep += (s,e) => events.Add( "Before Step " + e.Step.ToString());
compiler.Parameters.Pipeline.AfterStep += (s,e) => events.Add( "After Step " + e.Step.ToString());

Dabei fällt mir gerade ein, dass man hier auch gut mit Event Streams ala #Rx herumspielen könnte.

Damit sollten wir erst einmal genug Informationen um die Instrumentierung und die CompilerComponent gelernt haben um Boo wo auch immer hosten zu können.

class CompilerComponent : ICompilerComponent, ICompilerStep

Im nächsten Beitrag werden ich dann die anderen von ICompilerComponent abgeleiteten Interfaces beleuchten.

DotNetKicks-DE Image
Published Dienstag, 19. Oktober 2010 21:39 von Rainer Schuster
Abgelegt unter: , , , ,

Kommentare

# Advancing Boo – Metaboolisch gut

Mittwoch, 20. Oktober 2010 00:40 von Rainer Schuster

Nicht nur die japanischen Metabolisten versuchten sich am urbanen Kontext eines großen Systems. Die Massengesellschafft

# BOO und dessen Kompiler-Pipeline

Montag, 25. Oktober 2010 19:27 von dotnet-kicks.de

Sie wurden gekickt (eine gute Sache) - Trackback von dotnet-kicks.de

Kommentar abgeben

(verpflichtend) 
(verpflichtend) 
(optional)
(verpflichtend)