Ruby-Compiler für.NET Tilman Giese Holger Just Murat Knecht Mark Liebetrau Ruby-Compiler für.NET |...
-
Upload
luitger-gentsch -
Category
Documents
-
view
108 -
download
1
Transcript of Ruby-Compiler für.NET Tilman Giese Holger Just Murat Knecht Mark Liebetrau Ruby-Compiler für.NET |...
Ruby-Compiler für .NET
Tilman GieseHolger JustMurat KnechtMark Liebetrau
Ruby-Compiler für .NET | 12. Februar 2009
Übersicht
Ruby-Compiler für .NET | 12. Februar 2009
Ruby
■ Dynamische Sprachen
■ Die Sprache Ruby
Ruby-Compiler für .NET | 12. Februar 2009
Dynamische vs. Statische Sprachen
■ dynamische Semantik: Typüberprüfung und Namensauflösung werden erst zur Laufzeit durchgeführt
■ Laufzeitumgebung für alle dynamische Aspekte der Sprache
■ enge Verzahnung von Laufzeitumgebung und Klassenbibliothek
■ Für Ruby (aber auch andere Sprachen) gilt insbesondere:
□ Klassendefinitionen sind nicht abgeschlossen, sondern zu jedem Zeitpunkt an jeder Stelle des Programms änderbar
□ eval: dynamische Auswertung beliebigen Codes innerhalb eines beliebigen Kontextes
Ruby-Compiler für .NET | 12. Februar 2009
Die Sprache Ruby
■ Namensauflösung für Methoden und für Konstanten (= Modul- oder Klassennamen) erfolgt nach unterschiedlichen Prinzipien
□ Methoden: Vererbungs- und Mixin-Hierarchie
□ Konstanten: Hierarchie der lexikalischen Scopes
■ Dynamische Scopes: Erst zur Laufzeit stehen Scopes fest
class A; class B; end; end # innerer Scope: [A, A::B]class A::B; end # innerer Scope: [A::B]
class A; class << self; end; end # innerer Scope: [A, #<Class:A>]
def m(x, y); String; endclass m(42, 9)::A; class << self; end; end # innerer Scope: [#<Class:String::A>]
Ruby-Compiler für .NET | 12. Februar 2009
Ausschnitt: Klassenhierarchie
RubyObject
RubyBasicObject
RubyModule
RubyClass
RubyNumeric RubyString
RubyInteger
RubyFixnum
Ruby-Compiler für .NET | 12. Februar 2009
Ruby-Konzepte .NET-Konzepte (1)
■ Methodenaufruf
■ Beispiel
Ruby: m(5, 6) # implizit: self.m(5, 6)
class RubyObject { public RubyObject Invoke(String method, RubyObject[] args, System.Ruby.Block blk);}
C#: scope.Self().Invoke(″m″, new RubyObject[] { RubyFixnum.Get(5), RubyFixnum.Get(6) }, null);
Ruby-Compiler für .NET | 12. Februar 2009
Ruby-Konzepte .NET-Konzepte (2)
■ Methodendefinitionen
Ruby: class A; def my(a, b); end; end
C#: namespace __ruby { class __methods_A_0 {
[Ruby.Method("my")] public static RubyObject __my(RubyObject self, RubyObject[] args, Ruby.Block blk);
public static Ruby.Scope scope__my_0; } }
C#: scope.DefineMethod("my", typeof(__ruby.__methods_A_0).GetMethod("__my_0"));
Ruby-Compiler für .NET | 12. Februar 2009
Absurdes
■ Klassendefinition gibt etwas zurück ... und zwar nicht die Klasse
■ Lokale Variable verhalten sich ... anders
■ Modul- und Klassendefinitionen
class A; 5 + 5; end.to_f #=> 10.0
def m; 42; endputs m #=> 42 (Methodenaufruf)
if 1 == 2 then m = 6; endputs m #=> nil (lokale Variable)
ary = [ { ′4′ => Object } ]class ary.first[′4′]::MyClass; end
Ruby-Compiler für .NET | 12. Februar 2009
Klassenbibliothek
■ rudimentäre Klassenbibliothek selbst implementiert
■ einfach um neue Methoden und Klassen erweiterbar
/* * call-seq: * fix == other*/[Ruby.Method("==")]public RubyObject eq(RubyObject arg) {
if (this == arg) return RubyObject.__true; if (arg is RubyFixnum) return RubyObject.__false;
// some stuff omitted return RubyObject.__false;}
Ruby-Compiler für .NET | 12. Februar 2009
Plattform-Unabhängigkeit (1)
Ruby-Compiler für .NET | 12. Februar 2009
“An assembly is one of the fundamental programmingunits in Phoenix.” [PDOC]
Plattform-Unabhängigkeit (2)
■ OpCode
□ Phx.Common vs. Phx.Targets.Architectures.Msil
□ High-level vs. Low-level
□ „ In general it's best to use HIR opcodes if possible; you should only need to resort to the LIR opcodes for the ldfld/ldsfld cases that came up in the other thread.” [PF1]
□ Wir benutzen MSIL für:
◊ ldsfld, ldstr, ldtoken, newobj
□ Plattformunabhängigkeit von Phoenix?
Ruby-Compiler für .NET | 12. Februar 2009
API-Unarten
■ Hinzufügen einer Anweisung
□ Append(), Insert(), InsertAfter(), InsertBefore(), InsertBranchAndLabelAfter()
■ Zugriff auf Zieloperand
□ DestinationOperand: = DestinationOperand1
□ DestinationOperand2 …
□ DestinationOperands: Unterstützt Iteratorkonzept (foreach)
□ DestinationOperandList
◊ Nicht etwa eine Liste
◊ Erstes Element der Kette, nächstes mit Operand.Next
Ruby-Compiler für .NET | 12. Februar 2009
Ausführung einer Ruby EXE
■ main(): [RubyCoreLibrary]Runtime::Run()
■ Laufzeitumgebung initialisieren
□ Typsystem (Object, Class, …)
□ Wurzel der Scope-Hierarchie
□ Eingebaute Funktionalität
◊ Kernel Modul (puts, require)
◊ File Klasse
■ „Main() Methode“ von Ruby suchen und rufen
□ C# Reflection: __main.Run()
■ RubyExceptions abfangen und ausgeben
Ruby-Compiler für .NET | 12. Februar 2009
Instruktionen (1)
■ Ganz allgemein
□ Ziel := Operator ( Operanden )
■ Operator := Instruction + OpCode
■ Instruction: Technische Aufteilung der Operatoren
□ ValueInstruction: Evaluation Stack / Register
□ CallInstruction: Funktionsruf, d.h. Callstack
□ DataInstruction: ?
□ …
Ruby-Compiler für .NET | 12. Februar 2009
Operanden
■ Verschiedene Typen
□ Für SourceOperand und DestinationOperand
□ VariableOperand, MemoryOperand, ImmediateOperand, …
■ Optimierung?
□ Beispiel: ldstr „Kuchen“ -> call Console.WriteLine
□ VariableOperand + TemporaryVariable -> 2 lokale Variablen
□ VariableOperand + LocalVariable -> immerhin nur 1
Ruby-Compiler für .NET | 12. Februar 2009
Ein Resümee
■ Motivation für Phoenix
□ HIR bietet Unabhängigkeit zu Zielplattform
□ Backend austauschbar
■ Abstraktions-Level sind nicht sauber getrennt
□ Konsequenz ist nicht nur uneinheitliches Coding
■ Die versprochene Plattform-Unabhängigkeit fehlt.
Ruby-Compiler für .NET | 12. Februar 2009
Quellen
■ [PDOC] Phoenix Documentation, Microsoft Phoenix SDK June 2008
■ [PF1] „Error load float32“, Phoenix Forum, http://social.msdn.microsoft.com/Forums/en-US/phoenix/thread/b72a2f6d-c3bf-488b-b27a-6cc14b9006aa/ (zuletzt abgerufen am 11.02.09)
Ruby-Compiler für .NET | 12. Februar 2009
Dynamic Language Runtime
■ Erlaubt die Implementierung von dynamischen Sprachen auf Basis der .NET CLR
■ „pluggable language backends“
□ unterschiedliche dynamische Sprachen wie Python oder Ruby können einfach in ein .NET-Programm „geladen“ werden
□ Durch gemeinsames Typsystem ist Interaktion zwischen den Sprachen sowie der Host-Applikation möglich
■ Mögliche Anwendungsfälle
□ Verwendung von Bibliotheken dynamischer Sprachen in .NET
□ Scripting von Applikationen
Features der DLR
■ Generische Features aller dynamischen Sprachen werden von der DLR selbst implementiert
□ Gemeinsames Typsystem
□ Namensauflösung von Methoden und Variablen
□ Schleifen, Verzweigungen, …
□ Ausnahmebehandlung
□ Basisoperatoren
□ Methodenaufrufe
□ Scopes
□ Codeblöcke (für Funktionen, Methoden, Lambdas, …)
■ Implementierte Sprachen parsen ihren Code und erzeugen einen AST aus DLR-Expressions
Implementierung
■ Unabhängig von der Eingabesprache…
… wird (naiv) der gleiche AST generiert
MethodInfo writeline = typeof(Console).getMethod("WriteLine", Type.EmptyTypes);
Statements.Add( Expression.Call( writeline, Expression.Constant("Hello World") ));
puts "Hello World" # Ruby
print "Hello World" # Python
Einbettung in den rubyc
■ Neuer Einstiegspunkt für den DLR Host: RubyLanguageContext
□ Beschreibt Spracheigenschaften
□ Diverse Einstiegspunkte für die DLR
1. Aufrufen des Parsers und Generieren des generischen ASTs
□ Unverändert zu „normalem“ Compiler
2. Ablaufen des AST und Generieren des DLR-AST
□ Der Ablaufstruktur des Compilers wird gefolgt
□ Es werden Objekte, Scopes, Module und Klassen aus der Ruby-Standardbibliothek erzeugt und verwendet
Fazit DLR
■ Vorhandene Infrastruktur des Compilers und der Standardbibliothek wird weiterverwendet
□ Interoperabilität mit anderen DLR-Sprachen ist dadurch eingeschränkt
□ „Echte“ DLR-Implementierung müsste Vieles erneut implementieren
■ Insgesamt wesentlich weniger Implementierungsaufwand als bei Phoenix
DEMOHello World!