private Operand GetOperandValue(string token, Token tokenForExceptionInfo) { Operand operand = null; if (_currentMethod != null && _currentFormalArgumentList.Contains(token)) { operand = _g.Arg(token); } else if (_localVariablesTable.ContainsKey(token)) { operand = _localVariablesTable[token]; } else if (!token.Equals(GrammarHelper.This)) { try { operand = _g.This().Field(token); } catch (Exception ex) { throw new CodeGenerationException(MessagesHelper.NotFoundVariableEx, tokenForExceptionInfo != null ? tokenForExceptionInfo.ToStringInfo() : token, ex); } } else { operand = _g.This(); } return(operand); }
// example based on the MSDN Operator Overloading Sample (complex.cs) public static void GenComplex(AssemblyGen ag) { var st = ag.StaticFactory; var exp = ag.ExpressionFactory; ITypeMapper m = ag.TypeMapper; TypeGen Complex = ag.Public.Struct("Complex"); { FieldGen real = Complex.Public.Field(typeof(int), "real"); FieldGen imaginary = Complex.Public.Field(typeof(int), "imaginary"); CodeGen g = Complex.Public.Constructor() .Parameter(typeof(int), "real") .Parameter(typeof(int), "imaginary") ; { g.Assign(real, g.Arg("real")); g.Assign(imaginary, g.Arg("imaginary")); } // Declare which operator to overload (+), the types // that can be added (two Complex objects), and the // return type (Complex): g = Complex.Operator(Operator.Add, Complex, Complex, "c1", Complex, "c2"); { var c1 = g.Arg("c1"); var c2 = g.Arg("c2"); g.Return(exp.New(Complex, c1.Field("real") + c2.Field("real"), c1.Field("imaginary") + c2.Field("imaginary"))); } // Override the ToString method to display an complex number in the suitable format: g = Complex.Public.Override.Method(typeof(string), "ToString"); { g.Return(st.Invoke(typeof(string), "Format", "{0} + {1}i", real, imaginary)); } g = Complex.Public.Static.Method(typeof(void), "Main"); { var num1 = g.Local(exp.New(Complex, 2, 3)); var num2 = g.Local(exp.New(Complex, 3, 4)); // Add two Complex objects (num1 and num2) through the // overloaded plus operator: var sum = g.Local(num1 + num2); // Print the numbers and the sum using the overriden ToString method: g.WriteLine("First complex number: {0}", num1); g.WriteLine("Second complex number: {0}", num2); g.WriteLine("The sum of the two numbers: {0}", sum); } } }
// example based on the MSDN Delegates Sample (compose.cs) public static void GenCompose(AssemblyGen ag) { var st = ag.StaticFactory; var exp = ag.ExpressionFactory; TypeGen myDelegate = ag.Delegate(typeof(void), "MyDelegate").Parameter(typeof(string), "string"); TypeGen myClass = ag.Class("MyClass"); { CodeGen g = myClass.Public.Static.Method(typeof(void), "Hello").Parameter(typeof(string), "s"); { g.WriteLine(" Hello, {0}!", g.Arg("s")); } g = myClass.Public.Static.Method(typeof(void), "Goodbye").Parameter(typeof(string), "s"); { g.WriteLine(" Goodbye, {0}!", g.Arg("s")); } g = myClass.Public.Static.Method(typeof(void), "Main"); { ContextualOperand a = g.Local(), b = g.Local(), c = g.Local(), d = g.Local(); // Create the delegate object a that references // the method Hello: ITypeMapper typeMapper = ag.TypeMapper; g.Assign(a, exp.NewDelegate(myDelegate, myClass, "Hello")); // Create the delegate object b that references // the method Goodbye: ITypeMapper typeMapper1 = ag.TypeMapper; g.Assign(b, exp.NewDelegate(myDelegate, myClass, "Goodbye")); // The two delegates, a and b, are composed to form c, // which calls both methods in order: g.Assign(c, a + b); // Remove a from the composed delegate, leaving d, // which calls only the method Goodbye: g.Assign(d, c - a); g.WriteLine("Invoking delegate a:"); g.InvokeDelegate(a, "A"); g.WriteLine("Invoking delegate b:"); g.InvokeDelegate(b, "B"); g.WriteLine("Invoking delegate c:"); g.InvokeDelegate(c, "C"); g.WriteLine("Invoking delegate d:"); g.InvokeDelegate(d, "D"); } } }
// example based on the MSDN Structs Sample (struct2.cs) public static void GenStruct2(AssemblyGen ag) { var st = ag.StaticFactory; var exp = ag.ExpressionFactory; TypeGen TheClass = ag.Class("TheClass"); { TheClass.Public.Field(typeof(int), "x"); } TypeGen TheStruct = ag.Struct("TheStruct"); { TheStruct.Public.Field(typeof(int), "x"); } TypeGen TestClass = ag.Class("TestClass"); { CodeGen g = TestClass.Public.Static.Method(typeof(void), "structtaker").Parameter(TheStruct, "s"); { ITypeMapper typeMapper = ag.TypeMapper; g.Assign(g.Arg("s").Field("x"), 5); } g = TestClass.Public.Static.Method(typeof(void), "classtaker").Parameter(TheClass, "c"); { ITypeMapper typeMapper = ag.TypeMapper; g.Assign(g.Arg("c").Field("x"), 5); } g = TestClass.Public.Static.Method(typeof(void), "Main"); { var a = g.Local(TheStruct); g.InitObj(a); ITypeMapper typeMapper4 = ag.TypeMapper; var b = g.Local(exp.New(TheClass)); ITypeMapper typeMapper = ag.TypeMapper; g.Assign(a.Field("x"), 1); ITypeMapper typeMapper2 = ag.TypeMapper; g.Assign(b.Field("x"), 1); g.Invoke(TestClass, "structtaker", a); g.Invoke(TestClass, "classtaker", b); ITypeMapper typeMapper3 = ag.TypeMapper; g.WriteLine("a.x = {0}", a.Field("x")); ITypeMapper typeMapper1 = ag.TypeMapper; g.WriteLine("b.x = {0}", b.Field("x")); } } }
public static void GenCmdLine2(AssemblyGen ag) { ITypeMapper m = ag.TypeMapper; var st = ag.StaticFactory; var exp = ag.ExpressionFactory; ContextualOperand x; TypeGen commandLine3 = ag.Public.Class("CommandLine3"); { CodeGen g = commandLine3.Public.Method(typeof(void), "Main3").Parameter(typeof(string[]), "args"); { var args = g.Arg("args"); g.WriteLine("Number of command line 3 parameters = {0}", args.Property("Length")); var s = g.ForEach(typeof(string), args); { g.WriteLine(s); } g.End(); g.WriteLine(g.This().Invoke("GetType").Property("BaseType").Property("Name")); var inst = st.Field(typeof(CmdLineTestClass), "Default"); g.WriteLine(inst.Invoke("GetValue")); } commandLine3.Public.CommonConstructor(); } TypeGen commandLine2 = ag.Public.Class("CommandLine2"); { CodeGen g = commandLine2.Public.Static.Method(typeof(void), "Main").Parameter(typeof(string[]), "args"); { //g.Invoke(CommandLine3, "Main3", g.Arg("args")); var cl = g.Local(exp.New(commandLine3)); g.WriteLine(0); g.Invoke(cl, "Main3", g.Arg("args")); var args = g.Arg("args"); g.WriteLine("Number of command line parameters = {0}", args.Property("Length")); var s = g.ForEach(typeof(string), args); { g.WriteLine(s); } g.End(); } } }
public void Execute() { DynamicMethodGen dmg = DynamicMethodGen.Static(typeof(TryCatchReachibilityBug)).Method(typeof(string), new TypeMapper()) .Parameter(typeof(string), "name") .Parameter(typeof(string), "other"); CodeGen g = dmg.GetCode(); { g.Try(); { var name = g.Local(typeof(string), g.Arg("name")); g.WriteLine("Hello " + name + "!"); } g.CatchAll(); { g.WriteLine("Error"); g.Return("a"); } g.End(); var l = g.Local(); g.Eval(l.Assign(dmg.StaticFactory.Invoke(typeof(TryCatchReachibilityBug), nameof(CallMe), g.Arg("other"), 2))); g.Return(l); } dmg.GetCompletedDynamicMethod(true); }
// example based on the MSDN Delegates Sample (compose.cs) public static void GenCompose(AssemblyGen ag) { TypeGen MyDelegate = ag.DelegateVoid("MyDelegate").Parameter <string>("string"); TypeGen MyClass = ag.Class("MyClass"); { CodeGen g = MyClass.Public.Static.Void("Hello").Parameter <string>("s"); { g.WriteLine(" Hello, {0}!", g.Arg("s")); } g = MyClass.Public.Static.Void("Goodbye").Parameter <string>("s"); { g.WriteLine(" Goodbye, {0}!", g.Arg("s")); } g = MyClass.Public.Static.Void("Main"); { Operand a = g.Local(), b = g.Local(), c = g.Local(), d = g.Local(); // Create the delegate object a that references // the method Hello: g.Assign(a, Exp.NewDelegate(MyDelegate, MyClass, "Hello")); // Create the delegate object b that references // the method Goodbye: g.Assign(b, Exp.NewDelegate(MyDelegate, MyClass, "Goodbye")); // The two delegates, a and b, are composed to form c, // which calls both methods in order: g.Assign(c, a + b); // Remove a from the composed delegate, leaving d, // which calls only the method Goodbye: g.Assign(d, c - a); g.WriteLine("Invoking delegate a:"); g.InvokeDelegate(a, "A"); g.WriteLine("Invoking delegate b:"); g.InvokeDelegate(b, "B"); g.WriteLine("Invoking delegate c:"); g.InvokeDelegate(c, "C"); g.WriteLine("Invoking delegate d:"); g.InvokeDelegate(d, "D"); } } }
// example based on the MSDN Structs Sample (struct2.cs) public static void GenStruct2(AssemblyGen ag) { TypeGen TheClass = ag.Class("TheClass"); { TheClass.Public.Field <int>("x"); } TypeGen TheStruct = ag.Struct("TheStruct"); { TheStruct.Public.Field <int>("x"); } TypeGen TestClass = ag.Class("TestClass"); { CodeGen g = TestClass.Public.Static.Void("structtaker").Parameter(TheStruct, "s"); { g.Assign(g.Arg("s").Field("x"), 5); } g = TestClass.Public.Static.Void("classtaker").Parameter(TheClass, "c"); { g.Assign(g.Arg("c").Field("x"), 5); } g = TestClass.Public.Static.Void("Main"); { Operand a = g.Local(TheStruct); g.InitObj(a); Operand b = g.Local(Exp.New(TheClass)); g.Assign(a.Field("x"), 1); g.Assign(b.Field("x"), 1); g.Invoke(TestClass, "structtaker", a); g.Invoke(TestClass, "classtaker", b); g.WriteLine("a.x = {0}", a.Field("x")); g.WriteLine("b.x = {0}", b.Field("x")); } } }
public void CreateComWrapper(string filePath, string dllPath, string p1, string p2) { AssemblyGen ag = new AssemblyGen(filePath); Assembly asm = Assembly.LoadFrom(dllPath); ag.Attribute(asm.GetType("WaveTech.Scutex.Model.LicenseAttribute"), p1, p2); ag.Attribute(typeof(System.Runtime.InteropServices.ComVisibleAttribute), true); ag.Attribute(typeof(System.Reflection.AssemblyVersionAttribute), "1.0.0.0"); ag.Attribute(typeof(System.Reflection.AssemblyFileVersionAttribute), "1.0.0.0"); ag.Attribute(typeof(System.Runtime.InteropServices.GuidAttribute), "DC7DE67E-EA7A-4D26-89FF-FECEF2937268"); ag.Namespace("ScutexLicensingCCW"); TypeGen ComWrapper = ag.Public.Class(_stringDataGeneratorProvider.GenerateRandomString(10, 50, false, false)).Attribute(typeof(System.Runtime.InteropServices.ClassInterfaceAttribute), System.Runtime.InteropServices.ClassInterfaceType.AutoDual); { CodeGen g1 = ComWrapper.Public.Constructor(); CodeGen g2 = ComWrapper.Public.Method(typeof(int), "Validate").Parameter(typeof(int), "interactionMode"); { Operand licensingManager = g2.Local(Exp.New(asm.GetType("WaveTech.Scutex.Licensing.LicensingManager"), g2.This())); Operand scutexLicensing = g2.Local(asm.GetType("WaveTech.Scutex.Model.ScutexLicense")); Operand value = g2.Local(asm.GetType("WaveTech.Scutex.Model.InteractionModes")); g2.Assign(value, g2.Arg("interactionMode").Cast(asm.GetType("WaveTech.Scutex.Model.InteractionModes"))); g2.Assign(scutexLicensing, licensingManager.Invoke("Validate", value)); g2.Return(0); } CodeGen g3 = ComWrapper.Public.Method(typeof(int), "Register").Parameter(typeof(string), "licenseKey"); { Operand licensingManager = g3.Local(Exp.New(asm.GetType("WaveTech.Scutex.Licensing.LicensingManager"), g3.This())); Operand scutexLicensing = g3.Local(asm.GetType("WaveTech.Scutex.Model.ScutexLicense")); g3.Assign(scutexLicensing, licensingManager.Invoke("Register", g3.Arg("licenseKey"))); g3.Return(0); } } ag.Save(); asm = null; }
public static void GenCmdLine2(AssemblyGen ag) { TypeGen CommandLine2 = ag.Public.Class("CommandLine2"); { CodeGen g = CommandLine2.Public.Static.Method(typeof(void), "Main").Parameter(typeof(string[]), "args"); { Operand args = g.Arg("args"); g.WriteLine("Number of command line parameters = {0}", args.Property("Length")); Operand s = g.ForEach(typeof(string), args); { g.WriteLine(s); } g.End(); } } }
public static void GenHello3(AssemblyGen ag) { TypeGen Hello3 = ag.Public.Class("Hello3"); { CodeGen g = Hello3.Public.Static.Method(typeof(void), "Main").Parameter(typeof(string[]), "args"); { Operand args = g.Arg("args"); g.WriteLine("Hello, World!"); g.WriteLine("You entered the following {0} command line arguments:", args.ArrayLength()); Operand i = g.Local(); g.For(i.Assign(0), i < args.ArrayLength(), i.Increment()); { g.WriteLine("{0}", args[i]); } g.End(); } } }
public void Execute() { ConsoleTester.ClearAndStartCapturing(); DynamicMethodGen dmg = DynamicMethodGen.Static(typeof(DynamicMethodTest)).Method(typeof(string), new TypeMapper()) .Parameter(typeof(string), "name") .Parameter(typeof(string), "other"); CodeGen g = dmg.GetCode(); { g.Try(); { var name = g.Local(typeof(string), g.Arg("name")); g.WriteLine("Hello " + name + "!"); } g.CatchAll(); { g.WriteLine("Error"); } g.End(); g.Return(dmg.StaticFactory.Invoke(typeof(DynamicMethodTest), nameof(CallMe), g.Arg("other"), 2)); } DynamicMethod dm = dmg.GetCompletedDynamicMethod(true); // reflection-style invocation Assert.That(dm.Invoke(null, new object[] { "Dynamic Method", "first1" }), Is.EqualTo("test240")); // delegate invocation Func <string, string, string> hello = (Func <string, string, string>)dm.CreateDelegate(typeof(Func <string, string, string>)); Assert.That(hello("Delegate", "first1"), Is.EqualTo("test240")); ConsoleTester.AssertAndClear(@"Hello Dynamic Method! Hello Delegate! "); }
// example based on the MSDN Events Sample (events1.cs) public static void GenEvents1(AssemblyGen ag) { TypeGen ChangedEventHandler, ListWithChangedEvent; using (ag.Namespace("MyCollections")) { // A delegate type for hooking up change notifications. ChangedEventHandler = ag.Delegate(typeof(void), "ChangedEventHandler").Parameter(typeof(object), "sender").Parameter(typeof(EventArgs), "e"); // A class that works just like ArrayList, but sends event // notifications whenever the list changes. ListWithChangedEvent = ag.Public.Class("ListWithChangedEvent", typeof(ArrayList)); { // An event that clients can use to be notified whenever the // elements of the list change. EventGen Changed = ListWithChangedEvent.Public.Event(ChangedEventHandler, "Changed"); // Invoke the Changed event; called whenever list changes CodeGen g = ListWithChangedEvent.Protected.Virtual.Method(typeof(void), "OnChanged").Parameter(typeof(EventArgs), "e"); { g.If(Changed != null); { g.InvokeDelegate(Changed, g.This(), g.Arg("e")); } g.End(); } // Override some of the methods that can change the list; // invoke event after each g = ListWithChangedEvent.Public.Override.Method(typeof(int), "Add").Parameter(typeof(object), "value"); { Operand i = g.Local(g.Base().Invoke("Add", g.Arg("value"))); g.Invoke(g.This(), "OnChanged", Static.Field(typeof(EventArgs), "Empty")); g.Return(i); } g = ListWithChangedEvent.Public.Override.Method(typeof(void), "Clear"); { g.Invoke(g.Base(), "Clear"); g.Invoke(g.This(), "OnChanged", Static.Field(typeof(EventArgs), "Empty")); } g = ListWithChangedEvent.Public.Override.Indexer(typeof(object)).Index(typeof(int), "index").Setter(); { g.Assign(g.Base()[g.Arg("index")], g.PropertyValue()); g.Invoke(g.This(), "OnChanged", Static.Field(typeof(EventArgs), "Empty")); } } } using (ag.Namespace("TestEvents")) { TypeGen EventListener = ag.Class("EventListener"); { FieldGen List = EventListener.Field(ListWithChangedEvent, "List"); // This will be called whenever the list changes. CodeGen g = EventListener.Private.Method(typeof(void), "ListChanged").Parameter(typeof(object), "sender").Parameter(typeof(EventArgs), "eventArgs"); { g.WriteLine("This is called when the event fires."); } g = EventListener.Public.Constructor().Parameter(ListWithChangedEvent, "list"); { g.Assign(List, g.Arg("list")); // Add "ListChanged" to the Changed event on "List". g.SubscribeEvent(List, "Changed", Exp.NewDelegate(ChangedEventHandler, g.This(), "ListChanged")); } g = EventListener.Public.Method(typeof(void), "Detach"); { // Detach the event and delete the list g.UnsubscribeEvent(List, "Changed", Exp.NewDelegate(ChangedEventHandler, g.This(), "ListChanged")); g.Assign(List, null); } } TypeGen Test = ag.Class("Test"); { // Test the ListWithChangedEvent class. CodeGen g = Test.Public.Static.Method(typeof(void), "Main"); { // Create a new list. Operand list = g.Local(Exp.New(ListWithChangedEvent)); // Create a class that listens to the list's change event. Operand listener = g.Local(Exp.New(EventListener, list)); // Add and remove items from the list. g.Invoke(list, "Add", "item 1"); g.Invoke(list, "Clear"); g.Invoke(listener, "Detach"); } } } }
// example based on the MSDN Collection Classes Sample (tokens2.cs) public static void GenTokens2(AssemblyGen ag) { TypeGen Tokens = ag.Public.Class("Tokens", typeof(object), typeof(IEnumerable)); { FieldGen elements = Tokens.Private.Field(typeof(string[]), "elements"); CodeGen g = Tokens.Constructor() .Parameter(typeof(string), "source") .Parameter(typeof(char[]), "delimiters") ; { g.Assign(elements, g.Arg("source").Invoke("Split", g.Arg("delimiters"))); } // Inner class implements IEnumerator interface: TypeGen TokenEnumerator = Tokens.Public.Class("TokenEnumerator", typeof(object), typeof(IEnumerator)); { FieldGen position = TokenEnumerator.Field(typeof(int), "position", -1); FieldGen t = TokenEnumerator.Field(Tokens, "t"); g = TokenEnumerator.Public.Constructor().Parameter(Tokens, "tokens"); { g.Assign(t, g.Arg("tokens")); } g = TokenEnumerator.Public.Method(typeof(bool), "MoveNext"); { g.If(position < t.Field("elements").ArrayLength() - 1); { g.Increment(position); g.Return(true); } g.Else(); { g.Return(false); } g.End(); } g = TokenEnumerator.Public.Method(typeof(void), "Reset"); { g.Assign(position, -1); } // non-IEnumerator version: type-safe g = TokenEnumerator.Public.Property(typeof(string), "Current").Getter(); { g.Return(t.Field("elements")[position]); } // IEnumerator version: returns object g = TokenEnumerator.Public.PropertyImplementation(typeof(IEnumerator), typeof(object), "Current").Getter(); { g.Return(t.Field("elements")[position]); } } // IEnumerable Interface Implementation: // non-IEnumerable version g = Tokens.Public.Method(TokenEnumerator, "GetEnumerator"); { g.Return(Exp.New(TokenEnumerator, g.This())); } // IEnumerable version g = Tokens.Public.MethodImplementation(typeof(IEnumerable), typeof(IEnumerator), "GetEnumerator"); { g.Return(Exp.New(TokenEnumerator, g.This()).Cast(typeof(IEnumerator))); } // Test Tokens, TokenEnumerator g = Tokens.Static.Method(typeof(void), "Main"); { Operand f = g.Local(Exp.New(Tokens, "This is a well-done program.", Exp.NewInitializedArray(typeof(char), ' ', '-'))); Operand item = g.ForEach(typeof(string), f); // try changing string to int { g.WriteLine(item); } g.End(); } } }
// example based on the MSDN Explicit Interface Implementation Sample (explicit.cs) public static void GenExplicit2(AssemblyGen ag) { var st = ag.StaticFactory; var exp = ag.ExpressionFactory; ITypeMapper m = ag.TypeMapper; // Declare the English units interface: TypeGen IEnglishDimensions = ag.Interface("IEnglishDimensions"); { IEnglishDimensions.Method(typeof(float), "Length"); IEnglishDimensions.Method(typeof(float), "Width"); } // Declare the metric units interface: TypeGen IMetricDimensions = ag.Interface("IMetricDimensions"); { IMetricDimensions.Method(typeof(float), "Length"); IMetricDimensions.Method(typeof(float), "Width"); } // Declare the "Box" class that implements the two interfaces: // IEnglishDimensions and IMetricDimensions: TypeGen Box = ag.Class("Box", typeof(object), IEnglishDimensions, IMetricDimensions); { FieldGen lengthInches = Box.Field(typeof(float), "lengthInches"); FieldGen widthInches = Box.Field(typeof(float), "widthInches"); CodeGen g = Box.Public.Constructor() .Parameter(typeof(float), "length") .Parameter(typeof(float), "width") ; { g.Assign(lengthInches, g.Arg("length")); g.Assign(widthInches, g.Arg("width")); } // Explicitly implement the members of IEnglishDimensions: g = Box.MethodImplementation(IEnglishDimensions, typeof(float), "Length"); { g.Return(lengthInches); } g = Box.MethodImplementation(IEnglishDimensions, typeof(float), "Width"); { g.Return(widthInches); } // Explicitly implement the members of IMetricDimensions: g = Box.MethodImplementation(IMetricDimensions, typeof(float), "Length"); { g.Return(lengthInches * 2.54f); } g = Box.MethodImplementation(IMetricDimensions, typeof(float), "Width"); { g.Return(widthInches * 2.54f); } g = Box.Public.Static.Method(typeof(void), "Main"); { // Declare a class instance "myBox": var myBox = g.Local(exp.New(Box, 30.0f, 20.0f)); // Declare an instance of the English units interface: var eDimensions = g.Local(myBox.Cast(IEnglishDimensions)); // Declare an instance of the metric units interface: var mDimensions = g.Local(myBox.Cast(IMetricDimensions)); // Print dimensions in English units: g.WriteLine("Length(in): {0}", eDimensions.Invoke("Length")); g.WriteLine("Width (in): {0}", eDimensions.Invoke("Width")); // Print dimensions in metric units: g.WriteLine("Length(cm): {0}", mDimensions.Invoke("Length")); g.WriteLine("Width (cm): {0}", mDimensions.Invoke("Width")); } } }
// example based on the MSDN User-Defined Conversions Sample (conversion.cs) public static void GenConversion(AssemblyGen ag) { var st = ag.StaticFactory; var exp = ag.ExpressionFactory; TypeGen RomanNumeral = ag.Struct("RomanNumeral"); { FieldGen value = RomanNumeral.Private.Field(typeof(int), "value"); CodeGen g = RomanNumeral.Public.Constructor().Parameter(typeof(int), "value"); { g.Assign(value, g.Arg("value")); } // Declare a conversion from an int to a RomanNumeral. Note the // the use of the operator keyword. This is a conversion // operator named RomanNumeral: g = RomanNumeral.Public.ImplicitConversionFrom(typeof(int)); { // Note that because RomanNumeral is declared as a struct, // calling new on the struct merely calls the constructor // rather than allocating an object on the heap: g.Return(exp.New(RomanNumeral, g.Arg("value"))); } // Declare an explicit conversion from a RomanNumeral to an int: g = RomanNumeral.Public.ExplicitConversionTo(typeof(int), "roman"); { ITypeMapper typeMapper = ag.TypeMapper; g.Return(g.Arg("roman").Field("value")); } // Declare an implicit conversion from a RomanNumeral to // a string: g = RomanNumeral.Public.ImplicitConversionTo(typeof(string)); { g.Return("Conversion not yet implemented"); } } TypeGen Test = ag.Class("Test"); { CodeGen g = Test.Public.Static.Method(typeof(void), "Main"); { var numeral = g.Local(RomanNumeral); g.Assign(numeral, 10); // Call the explicit conversion from numeral to int. Because it is // an explicit conversion, a cast must be used: g.WriteLine(numeral.Cast(typeof(int))); // Call the implicit conversion to string. Because there is no // cast, the implicit conversion to string is the only // conversion that is considered: g.WriteLine(numeral); // Call the explicit conversion from numeral to int and // then the explicit conversion from int to short: var s = g.Local(numeral.Cast(typeof(short))); g.WriteLine(s); } } }
// example based on the MSDN User-Defined Conversions Sample (structconversion.cs) public static void GenStructConversion(AssemblyGen ag) { var st = ag.StaticFactory; var exp = ag.ExpressionFactory; TypeGen BinaryNumeral = ag.Struct("BinaryNumeral"); { FieldGen value = BinaryNumeral.Private.Field(typeof(int), "value"); CodeGen g = BinaryNumeral.Public.Constructor().Parameter(typeof(int), "value"); { g.Assign(value, g.Arg("value")); } g = BinaryNumeral.Public.ImplicitConversionFrom(typeof(int)); { g.Return(exp.New(BinaryNumeral, g.Arg("value"))); } g = BinaryNumeral.Public.ImplicitConversionTo(typeof(string)); { g.Return("Conversion not yet implemented"); } g = BinaryNumeral.Public.ExplicitConversionTo(typeof(int), "binary"); { ITypeMapper typeMapper = ag.TypeMapper; g.Return(g.Arg("binary").Field("value")); } } TypeGen RomanNumeral = ag.Struct("RomanNumeral"); { FieldGen value = RomanNumeral.Private.Field(typeof(int), "value"); CodeGen g = RomanNumeral.Public.Constructor().Parameter(typeof(int), "value"); { g.Assign(value, g.Arg("value")); } g = RomanNumeral.Public.ImplicitConversionFrom(typeof(int)); { g.Return(exp.New(RomanNumeral, g.Arg("value"))); } g = RomanNumeral.Public.ImplicitConversionFrom(BinaryNumeral, "binary"); { g.Return(exp.New(RomanNumeral, g.Arg("binary").Cast(typeof(int)))); } g = RomanNumeral.Public.ExplicitConversionTo(typeof(int), "roman"); { ITypeMapper typeMapper = ag.TypeMapper; g.Return(g.Arg("roman").Field("value")); } g = RomanNumeral.Public.ImplicitConversionTo(typeof(string)); { g.Return("Conversion not yet implemented"); } } TypeGen Test = ag.Class("Test"); { CodeGen g = Test.Public.Static.Method(typeof(void), "Main"); { var roman = g.Local(RomanNumeral); g.Assign(roman, 10); var binary = g.Local(BinaryNumeral); // Perform a conversion from a RomanNumeral to a // BinaryNumeral: g.Assign(binary, roman.Cast(typeof(int)).Cast(BinaryNumeral)); // Performs a conversion from a BinaryNumeral to a RomanNumeral. // No cast is required: g.Assign(roman, binary); g.WriteLine(binary.Cast(typeof(int))); g.WriteLine(binary); } } }
public static void GenIndexer(AssemblyGen ag) { // Class to provide access to a large file // as if it were a byte array. TypeGen FileByteArray = ag.Public.Class("FileByteArray"); { FieldGen stream = FileByteArray.Field <Stream>("stream"); // Holds the underlying stream // used to access the file. // Create a new FileByteArray encapsulating a particular file. CodeGen g = FileByteArray.Public.Constructor().Parameter <string>("fileName"); { g.Assign(stream, Exp.New <FileStream>(g.Arg("fileName"), FileMode.Open)); } // Close the stream. This should be the last thing done // when you are finished. g = FileByteArray.Public.Void("Close"); { g.Invoke(stream, "Close"); g.Assign(stream, null); } // Indexer to provide read/write access to the file. PropertyGen Item = FileByteArray.Public.Indexer <byte>().Index <long>("index"); // long is a 64-bit integer { // Read one byte at offset index and return it. g = Item.Getter(); { Operand buffer = g.Local(Exp.NewArray <byte>(1)); g.Invoke(stream, "Seek", g.Arg("index"), SeekOrigin.Begin); g.Invoke(stream, "Read", buffer, 0, 1); g.Return(buffer[0]); } // Write one byte at offset index and return it. g = Item.Setter(); { Operand buffer = g.Local(Exp.NewInitializedArray <byte>(g.PropertyValue())); g.Invoke(stream, "Seek", g.Arg("index"), SeekOrigin.Begin); g.Invoke(stream, "Write", buffer, 0, 1); } } // Get the total length of the file. FileByteArray.Public.Property <long>("Length").Getter().GetCode() .Return(stream.Invoke("Seek", 0, SeekOrigin.End)); } // Demonstrate the FileByteArray class. // Reverses the bytes in a file. TypeGen Reverse = ag.Public.Class("Reverse"); { CodeGen g = Reverse.Public.Static.Void("Main").Parameter <string[]>("args"); { Operand args = g.Arg("args"); // Check for arguments. g.If(args.ArrayLength() != 1); { g.WriteLine("Usage : Indexer <filename>"); g.Return(); } g.End(); // Check for file existence g.If(!Static.Invoke(typeof(File), "Exists", args[0])); { g.WriteLine("File " + args[0] + " not found."); g.Return(); } g.End(); Operand file = g.Local(Exp.New(FileByteArray, args[0])); Operand len = g.Local(file.Property("Length")); // Swap bytes in the file to reverse it. Operand i = g.Local <long>(); g.For(i.Assign(0), i < len / 2, i.Increment()); { Operand t = g.Local(); // Note that indexing the "file" variable invokes the // indexer on the FileByteStream class, which reads // and writes the bytes in the file. g.Assign(t, file[i]); g.Assign(file[i], file[len - i - 1]); g.Assign(file[len - i - 1], t); } g.End(); g.Invoke(file, "Close"); } } }
// example based on the MSDN Properties Sample (abstractshape.cs, shapes.cs, shapetest.cs) public static void GenShapeTest(AssemblyGen ag) { // abstractshape.cs TypeGen Shape = ag.Public.Abstract.Class("Shape"); { FieldGen myId = Shape.Private.Field(typeof(string), "myId"); PropertyGen Id = Shape.Public.SimpleProperty(myId, "Id"); CodeGen g = Shape.Public.Constructor().Parameter(typeof(string), "s"); { g.Assign(Id, g.Arg("s")); // calling the set accessor of the Id property } // Area is a read-only property - only a get accessor is needed: PropertyGen Area = Shape.Public.Abstract.Property(typeof(double), "Area"); Area.Getter(); g = Shape.Public.Override.Method(typeof(string), "ToString"); { g.Return(Id + " Area = " + Static.Invoke(typeof(string), "Format", "{0:F2}", Area)); } } // shapes.cs TypeGen Square = ag.Public.Class("Square", Shape); { FieldGen mySide = Square.Private.Field(typeof(int), "mySide"); CodeGen g = Square.Public.Constructor().Parameter(typeof(int), "side").Parameter(typeof(string), "id"); { g.InvokeBase(g.Arg("id")); g.Assign(mySide, g.Arg("side")); } PropertyGen Area = Square.Public.Override.Property(typeof(double), "Area"); g = Area.Getter(); { // Given the side, return the area of a square: g.Return(mySide * mySide); } } TypeGen Circle = ag.Public.Class("Circle", Shape); { FieldGen myRadius = Circle.Private.Field(typeof(int), "myRadius"); CodeGen g = Circle.Public.Constructor().Parameter(typeof(int), "radius").Parameter(typeof(string), "id"); { g.InvokeBase(g.Arg("id")); g.Assign(myRadius, g.Arg("radius")); } PropertyGen Area = Circle.Public.Override.Property(typeof(double), "Area"); g = Area.Getter(); { // Given the radius, return the area of a circle: g.Return(myRadius * myRadius * Math.PI); } } TypeGen Rectangle = ag.Public.Class("Rectangle", Shape); { FieldGen myWidth = Rectangle.Private.Field(typeof(int), "myWidth"); FieldGen myHeight = Rectangle.Private.Field(typeof(int), "myHeight"); CodeGen g = Rectangle.Public.Constructor() .Parameter(typeof(int), "width") .Parameter(typeof(int), "height") .Parameter(typeof(string), "id") ; { g.InvokeBase(g.Arg("id")); g.Assign(myWidth, g.Arg("width")); g.Assign(myHeight, g.Arg("height")); } PropertyGen Area = Rectangle.Public.Override.Property(typeof(double), "Area"); g = Area.Getter(); { // Given the width and height, return the area of a rectangle: g.Return(myWidth * myHeight); } } // shapetest.cs TypeGen TestClass = ag.Public.Class("TestClass"); { CodeGen g = TestClass.Public.Static.Method(typeof(void), "Main"); { Operand shapes = g.Local(Exp.NewInitializedArray(Shape, Exp.New(Square, 5, "Square #1"), Exp.New(Circle, 3, "Circle #1"), Exp.New(Rectangle, 4, 5, "Rectangle #1"))); g.WriteLine("Shapes Collection"); Operand s = g.ForEach(Shape, shapes); { g.WriteLine(s); } g.End(); } } }
/// <summary> /// Iterate over all loaded mods and emit new types /// </summary> void Awake() { // Generate overloaded PQSMod types AssemblyGen assembly = new AssemblyGen(Guid.NewGuid().ToString(), new CompilerOptions { OutputPath = Path.GetTempFileName() }); List <Type> modTypes = GetModTypes(); foreach (Type modType in modTypes) { if (typeof(PQSMod).IsAssignableFrom(modType)) { // Get the ModLoader type we want to extend Type loaderType = modTypes.FirstOrDefault(t => t.BaseType != null && t.BaseType.FullName != null && t.BaseType.FullName.StartsWith("Kopernicus.Configuration.ModLoader.ModLoader") && t.BaseType.GetGenericArguments()[0] == modType); if (loaderType == null) { continue; } // Generate the Mod Type TypeGen modGen = assembly.Public.Class($"{modType.Name}Regional", modType); { FieldGen multiplierMap = modGen.Public.Field(typeof(MapSO), "multiplierMap"); FieldGen splitChannels = modGen.Public.Field(typeof(Boolean), "splitChannels"); FieldGen multiplier = modGen.Private.Field(typeof(Color), "multiplier"); FieldGen preBuildColor = modGen.Private.Field(typeof(Color), "preBuildColor"); FieldGen preBuildHeight = modGen.Private.Field(typeof(Double), "preBuildHeight"); // OnVertexBuildHeight CodeGen onVertexBuild = modGen.Public.Override.Method(typeof(void), "OnVertexBuild") .Parameter(typeof(PQS.VertexBuildData), "data"); { ContextualOperand data = onVertexBuild.Arg("data"); onVertexBuild.Assign(multiplier, onVertexBuild.Local(multiplierMap.Invoke( "GetPixelColor", new TypeMapper(), data.Field("u"), data.Field("v")))); onVertexBuild.If(!splitChannels); { onVertexBuild.Assign(multiplier.Field("a", new TypeMapper()), multiplier.Field("r", new TypeMapper())); } onVertexBuild.End(); onVertexBuild.Assign(preBuildColor, data.Field("vertColor")); onVertexBuild.Assign(preBuildHeight, data.Field("vertHeight")); onVertexBuild.Invoke(onVertexBuild.Base(), "OnVertexBuild", data); onVertexBuild.Assign(data.Field("vertColor"), assembly.StaticFactory.Invoke(typeof(Color), "Lerp", preBuildColor, data.Field("vertColor"), multiplier.Field("a", new TypeMapper()))); onVertexBuild.Assign(data.Field("vertHeight"), assembly.StaticFactory.Invoke(typeof(UtilMath), "Lerp", preBuildHeight, data.Field("vertHeight"), multiplier.Field("r", new TypeMapper()))); } // OnVertexBuildHeight CodeGen onVertexBuildHeight = modGen.Public.Override.Method(typeof(void), "OnVertexBuildHeight") .Parameter(typeof(PQS.VertexBuildData), "data"); { ContextualOperand data = onVertexBuildHeight.Arg("data"); onVertexBuildHeight.Assign(multiplier, onVertexBuildHeight.Local(multiplierMap.Invoke( "GetPixelColor", new TypeMapper(), data.Field("u"), data.Field("v")))); onVertexBuildHeight.If(!splitChannels); { onVertexBuildHeight.Assign(multiplier.Field("a", new TypeMapper()), multiplier.Field("r", new TypeMapper())); } onVertexBuildHeight.End(); onVertexBuildHeight.Assign(preBuildColor, data.Field("vertColor")); onVertexBuildHeight.Assign(preBuildHeight, data.Field("vertHeight")); onVertexBuildHeight.Invoke(onVertexBuildHeight.Base(), "OnVertexBuildHeight", data); onVertexBuildHeight.Assign(data.Field("vertColor"), assembly.StaticFactory.Invoke(typeof(Color), "Lerp", preBuildColor, data.Field("vertColor"), multiplier.Field("a", new TypeMapper()))); onVertexBuildHeight.Assign(data.Field("vertHeight"), assembly.StaticFactory.Invoke(typeof(UtilMath), "Lerp", preBuildHeight, data.Field("vertHeight"), multiplier.Field("r", new TypeMapper()))); } } // Generate the Loader Type Type modLoader = typeof(ModLoader <>).MakeGenericType(modGen); TypeGen loaderGen = assembly.Public.Class($"{modType.Name.Replace("PQSMod_", "").Replace("PQS", "")}Regional", modLoader); { PropertyGen multiplierMap = loaderGen.Public.Property(typeof(MapSOParserRGB <MapSO>), "multiplierMap") .Attribute(typeof(ParserTarget), "multiplierMap"); { CodeGen getter = multiplierMap.Getter(); { getter.Return(getter.Base().Property("Mod").Field("multiplierMap")); } CodeGen setter = multiplierMap.Setter(); { setter.Assign(setter.Base().Property("Mod").Field("multiplierMap"), setter.PropertyValue()); } } PropertyGen splitChannels = loaderGen.Public.Property(typeof(NumericParser <Boolean>), "splitChannels") .Attribute(typeof(ParserTarget), "splitChannels"); { CodeGen getter = splitChannels.Getter(); { getter.Return(getter.Base().Property("Mod").Field("splitChannels")); } CodeGen setter = splitChannels.Setter(); { setter.Assign(setter.Base().Property("Mod").Field("splitChannels"), setter.PropertyValue()); } } FieldGen loader = loaderGen.Public.Field(loaderType, "loader") .BeginAttribute(typeof(ParserTarget), "Mod").SetField("AllowMerge", true).End(); CodeGen create_PQS = loaderGen.Public.Override.Method(typeof(void), "Create") .Parameter(typeof(PQS), "pqsVersion"); { ContextualOperand pqsVersion = create_PQS.Arg("pqsVersion"); create_PQS.Invoke(create_PQS.Base(), "Create", pqsVersion); create_PQS.Assign(loader, assembly.ExpressionFactory.New(loaderType)); create_PQS.Invoke(loader, "Create", create_PQS.Base().Property("Mod"), pqsVersion); } CodeGen create_Mod_PQS = loaderGen.Public.Override.Method(typeof(void), "Create") .Parameter(modGen, "_mod") .Parameter(typeof(PQS), "pqsVersion"); { ContextualOperand _mod = create_Mod_PQS.Arg("_mod"); ContextualOperand pqsVersion = create_Mod_PQS.Arg("pqsVersion"); create_Mod_PQS.Invoke(create_Mod_PQS.Base(), "Create", _mod, pqsVersion); create_Mod_PQS.Assign(loader, assembly.ExpressionFactory.New(loaderType)); create_Mod_PQS.Invoke(loader, "Create", create_Mod_PQS.Base().Property("Mod"), pqsVersion); } } } } assembly.Save(); // Hacking into my own mod. Oh well. modTypes.AddRange(assembly.GetAssembly().GetTypes()); typeof(Parser).GetField("_modTypes", BindingFlags.NonPublic | BindingFlags.Static) ?.SetValue(null, modTypes); }
// example based on the MSDN User-Defined Conversions Sample (structconversion.cs) public static void GenStructConversion(AssemblyGen ag) { TypeGen BinaryNumeral = ag.Struct("BinaryNumeral"); { FieldGen value = BinaryNumeral.Private.Field <int>("value"); CodeGen g = BinaryNumeral.Public.Constructor().Parameter <int>("value"); { g.Assign(value, g.Arg("value")); } g = BinaryNumeral.Public.ImplicitConversionFrom <int>(); { g.Return(Exp.New(BinaryNumeral, g.Arg("value"))); } g = BinaryNumeral.Public.ImplicitConversionTo <string>(); { g.Return("Conversion not yet implemented"); } g = BinaryNumeral.Public.ExplicitConversionTo <int>("binary"); { g.Return(g.Arg("binary").Field("value")); } } TypeGen RomanNumeral = ag.Struct("RomanNumeral"); { FieldGen value = RomanNumeral.Private.Field <int>("value"); CodeGen g = RomanNumeral.Public.Constructor().Parameter <int>("value"); { g.Assign(value, g.Arg("value")); } g = RomanNumeral.Public.ImplicitConversionFrom <int>(); { g.Return(Exp.New(RomanNumeral, g.Arg("value"))); } g = RomanNumeral.Public.ImplicitConversionFrom(BinaryNumeral, "binary"); { g.Return(Exp.New(RomanNumeral, g.Arg("binary").Cast <int>())); } g = RomanNumeral.Public.ExplicitConversionTo <int>("roman"); { g.Return(g.Arg("roman").Field("value")); } g = RomanNumeral.Public.ImplicitConversionTo <string>(); { g.Return("Conversion not yet implemented"); } } TypeGen Test = ag.Class("Test"); { CodeGen g = Test.Public.Static.Void("Main"); { Operand roman = g.Local(RomanNumeral); g.Assign(roman, 10); Operand binary = g.Local(BinaryNumeral); // Perform a conversion from a RomanNumeral to a // BinaryNumeral: g.Assign(binary, roman.Cast <int>().Cast(BinaryNumeral)); // Performs a conversion from a BinaryNumeral to a RomanNumeral. // No cast is required: g.Assign(roman, binary); g.WriteLine(binary.Cast <int>()); g.WriteLine(binary); } } }
// example based on the MSDN Delegates Sample (bookstore.cs) public static void GenBookstore(AssemblyGen ag) { TypeGen Book, ProcessBookDelegate, BookDB; // A set of classes for handling a bookstore: using (ag.Namespace("Bookstore")) { // Describes a book in the book list: Book = ag.Public.Struct("Book"); { FieldGen Title = Book.Public.Field <string>("Title"); // Title of the book. FieldGen Author = Book.Public.Field <string>("Author"); // Author of the book. FieldGen Price = Book.Public.Field <decimal>("Price"); // Price of the book. FieldGen Paperback = Book.Public.Field <bool>("Paperback"); // Is it paperback? CodeGen g = Book.Public.Constructor() .Parameter <string>("title") .Parameter <string>("author") .Parameter <decimal>("price") .Parameter <bool>("paperBack"); { g.Assign(Title, g.Arg("title")); g.Assign(Author, g.Arg("author")); g.Assign(Price, g.Arg("price")); g.Assign(Paperback, g.Arg("paperBack")); } } // Declare a delegate type for processing a book: ProcessBookDelegate = ag.Public.DelegateVoid("ProcessBookDelegate").Parameter(Book, "book"); // Maintains a book database. BookDB = ag.Public.Class("BookDB"); { // List of all books in the database: FieldGen list = BookDB.Field <ArrayList>("list", Exp.New <ArrayList>()); // Add a book to the database: CodeGen g = BookDB.Public.Void("AddBook") .Parameter <string>("title") .Parameter <string>("author") .Parameter <decimal>("price") .Parameter <bool>("paperBack"); { g.Invoke(list, "Add", Exp.New(Book, g.Arg("title"), g.Arg("author"), g.Arg("price"), g.Arg("paperBack"))); } // Call a passed-in delegate on each paperback book to process it: g = BookDB.Public.Void("ProcessPaperbackBooks").Parameter(ProcessBookDelegate, "processBook"); { Operand b = g.ForEach(Book, list); { g.If(b.Field("Paperback")); { g.InvokeDelegate(g.Arg("processBook"), b); } g.End(); } g.End(); } } } // Using the Bookstore classes: using (ag.Namespace("BookTestClient")) { // Class to total and average prices of books: TypeGen PriceTotaller = ag.Class("PriceTotaller"); { FieldGen countBooks = PriceTotaller.Field <int>("countBooks", 0); FieldGen priceBooks = PriceTotaller.Field <decimal>("priceBooks", 0.0m); CodeGen g = PriceTotaller.Internal.Void("AddBookToTotal").Parameter(Book, "book"); { g.AssignAdd(countBooks, 1); g.AssignAdd(priceBooks, g.Arg("book").Field("Price")); } g = PriceTotaller.Internal.Method <decimal>("AveragePrice"); { g.Return(priceBooks / countBooks); } } // Class to test the book database: TypeGen Test = ag.Class("Test"); { // Print the title of the book. CodeGen g = Test.Static.Void("PrintTitle").Parameter(Book, "book"); { g.WriteLine(" {0}", g.Arg("book").Field("Title")); } // Initialize the book database with some test books: g = Test.Static.Void("AddBooks").Parameter(BookDB, "bookDB"); { Operand bookDB = g.Arg("bookDB"); g.Invoke(bookDB, "AddBook", "The C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true); g.Invoke(bookDB, "AddBook", "The Unicode Standard 2.0", "The Unicode Consortium", 39.95m, true); g.Invoke(bookDB, "AddBook", "The MS-DOS Encyclopedia", "Ray Duncan", 129.95m, false); g.Invoke(bookDB, "AddBook", "Dogbert's Clues for the Clueless", "Scott Adams", 12.00m, true); } // Execution starts here. g = Test.Static.Void("Main"); { Operand bookDB = g.Local(Exp.New(BookDB)); // Initialize the database with some books: g.Invoke(Test, "AddBooks", bookDB); // Print all the titles of paperbacks: g.WriteLine("Paperback Book Titles:"); // Create a new delegate object associated with the static // method Test.PrintTitle: g.Invoke(bookDB, "ProcessPaperbackBooks", Exp.NewDelegate(ProcessBookDelegate, Test, "PrintTitle")); // Get the average price of a paperback by using // a PriceTotaller object: Operand totaller = g.Local(Exp.New(PriceTotaller)); // Create a new delegate object associated with the nonstatic // method AddBookToTotal on the object totaller: g.Invoke(bookDB, "ProcessPaperbackBooks", Exp.NewDelegate(ProcessBookDelegate, totaller, "AddBookToTotal")); g.WriteLine("Average Paperback Book Price: ${0:#.##}", totaller.Invoke("AveragePrice")); } } } }
// example based on the MSDN Delegates Sample (bookstore.cs) public static void GenBookstore(AssemblyGen ag) { var st = ag.StaticFactory; var exp = ag.ExpressionFactory; ITypeMapper m = ag.TypeMapper; TypeGen book, processBookDelegate, BookDBLocal; // A set of classes for handling a bookstore: using (ag.Namespace("Bookstore")) { // Describes a book in the book list: book = ag.Public.Struct("Book"); { FieldGen title = book.Public.Field(typeof(string), "Title"); // Title of the book. FieldGen author = book.Public.Field(typeof(string), "Author"); // Author of the book. FieldGen price = book.Public.Field(typeof(decimal), "Price"); // Price of the book. FieldGen paperback = book.Public.Field(typeof(bool), "Paperback"); // Is it paperback? CodeGen g = book.Public.Constructor() .Parameter(typeof(string), "title") .Parameter(typeof(string), "author") .Parameter(typeof(decimal), "price") .Parameter(typeof(bool), "paperBack"); { g.Assign(title, g.Arg("title")); g.Assign(author, g.Arg("author")); g.Assign(price, g.Arg("price")); g.Assign(paperback, g.Arg("paperBack")); } } // Declare a delegate type for processing a book: processBookDelegate = ag.Public.Delegate(typeof(void), "ProcessBookDelegate").Parameter(book, "book"); // Maintains a book database. BookDBLocal = ag.Public.Class("BookDB"); { // List of all books in the database: FieldGen list = BookDBLocal.Field(typeof(ArrayList), "list", exp.New(typeof(ArrayList))); // Add a book to the database: CodeGen g = BookDBLocal.Public.Method(typeof(void), "AddBook") .Parameter(typeof(string), "title") .Parameter(typeof(string), "author") .Parameter(typeof(decimal), "price") .Parameter(typeof(bool), "paperBack") ; { g.Invoke(list, "Add", exp.New(book, g.Arg("title"), g.Arg("author"), g.Arg("price"), g.Arg("paperBack"))); } // Call a passed-in delegate on each paperback book to process it: g = BookDBLocal.Public.Method(typeof(void), "ProcessPaperbackBooks").Parameter(processBookDelegate, "processBook"); { var b = g.ForEach(book, list); { g.If(b.Field("Paperback")); { g.InvokeDelegate(g.Arg("processBook"), b); } g.End(); } g.End(); } } } // Using the Bookstore classes: using (ag.Namespace("BookTestClient")) { // Class to total and average prices of books: TypeGen priceTotaller = ag.Class("PriceTotaller"); { FieldGen countBooks = priceTotaller.Field(typeof(int), "countBooks", 0); FieldGen priceBooks = priceTotaller.Field(typeof(decimal), "priceBooks", 0.0m); CodeGen g = priceTotaller.Internal.Method(typeof(void), "AddBookToTotal").Parameter(book, "book"); { g.AssignAdd(countBooks, 1); g.AssignAdd(priceBooks, g.Arg("book").Field("Price")); } g = priceTotaller.Internal.Method(typeof(decimal), "AveragePrice"); { g.Return(priceBooks / countBooks); } } // Class to test the book database: TypeGen test = ag.Class("Test"); { // Print the title of the book. CodeGen g = test.Static.Method(typeof(void), "PrintTitle").Parameter(book, "book"); { g.WriteLine(" {0}", g.Arg("book").Field("Title")); } // Initialize the book database with some test books: g = test.Static.Method(typeof(void), "AddBooks").Parameter(BookDBLocal, "bookDB"); { var bookDb = g.Arg("bookDB"); g.Invoke(bookDb, "AddBook", "The C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true); g.Invoke(bookDb, "AddBook", "The Unicode Standard 2.0", "The Unicode Consortium", 39.95m, true); g.Invoke(bookDb, "AddBook", "The MS-DOS Encyclopedia", "Ray Duncan", 129.95m, false); g.Invoke(bookDb, "AddBook", "Dogbert's Clues for the Clueless", "Scott Adams", 12.00m, true); } // Execution starts here. g = test.Public.Static.Method(typeof(void), "Main"); { var bookDb = g.Local(exp.New(BookDBLocal)); // Initialize the database with some books: g.Invoke(test, "AddBooks", bookDb); // Print all the titles of paperbacks: g.WriteLine("Paperback Book Titles:"); // Create a new delegate object associated with the static // method Test.PrintTitle: g.Invoke(bookDb, "ProcessPaperbackBooks", (Operand)exp.NewDelegate(processBookDelegate, test, "PrintTitle")); // Get the average price of a paperback by using // a PriceTotaller object: var totaller = g.Local(exp.New(priceTotaller)); // Create a new delegate object associated with the nonstatic // method AddBookToTotal on the object totaller: g.Invoke(bookDb, "ProcessPaperbackBooks", (Operand)exp.NewDelegate(processBookDelegate, totaller, "AddBookToTotal")); g.WriteLine("Average Paperback Book Price: ${0:#.##}", totaller.Invoke("AveragePrice")); } } } }
// example based on the MSDN Operator Overloading Sample (dbbool.cs) public static void GenDbBool(AssemblyGen ag) { TypeGen DBBool = ag.Public.Struct("DBBool"); { // Private field that stores -1, 0, 1 for dbFalse, dbNull, dbTrue: FieldGen value = DBBool.Field <int>("value"); // Private constructor. The value parameter must be -1, 0, or 1: CodeGen g = DBBool.Constructor().Parameter <int>("value"); { g.Assign(value, g.Arg("value")); } // The three possible DBBool values: FieldGen dbNull = DBBool.Public.Static.ReadOnly.Field(DBBool, "dbNull", Exp.New(DBBool, 0)); FieldGen dbFalse = DBBool.Public.Static.ReadOnly.Field(DBBool, "dbFalse", Exp.New(DBBool, -1)); FieldGen dbTrue = DBBool.Public.Static.ReadOnly.Field(DBBool, "dbTrue", Exp.New(DBBool, 1)); // Implicit conversion from bool to DBBool. Maps true to // DBBool.dbTrue and false to DBBool.dbFalse: g = DBBool.ImplicitConversionFrom <bool>("x"); { Operand x = g.Arg("x"); g.Return(x.Conditional(dbTrue, dbFalse)); } // Explicit conversion from DBBool to bool. Throws an // exception if the given DBBool is dbNull, otherwise returns // true or false: g = DBBool.ExplicitConversionTo <bool>("x"); { Operand x = g.Arg("x"); g.If(x.Field("value") == 0); { g.Throw(Exp.New(typeof(InvalidOperationException))); } g.End(); g.Return(x.Field("value") > 0); } // Equality operator. Returns dbNull if either operand is dbNull, // otherwise returns dbTrue or dbFalse: g = DBBool.Operator(Operator.Equality, DBBool, DBBool, "x", DBBool, "y"); { Operand x = g.Arg("x"), y = g.Arg("y"); g.If(x.Field("value") == 0 || y.Field("value") == 0); { g.Return(dbNull); } g.End(); g.Return((x.Field("value") == y.Field("value")).Conditional(dbTrue, dbFalse)); } // Inequality operator. Returns dbNull if either operand is // dbNull, otherwise returns dbTrue or dbFalse: g = DBBool.Operator(Operator.Inequality, DBBool, DBBool, "x", DBBool, "y"); { Operand x = g.Arg("x"), y = g.Arg("y"); g.If(x.Field("value") == 0 || y.Field("value") == 0); { g.Return(dbNull); } g.End(); g.Return((x.Field("value") != y.Field("value")).Conditional(dbTrue, dbFalse)); } // Logical negation operator. Returns dbTrue if the operand is // dbFalse, dbNull if the operand is dbNull, or dbFalse if the // operand is dbTrue: g = DBBool.Operator(Operator.LogicalNot, DBBool, DBBool, "x"); { Operand x = g.Arg("x"); g.Return(Exp.New(DBBool, -x.Field("value"))); } // Logical AND operator. Returns dbFalse if either operand is // dbFalse, dbNull if either operand is dbNull, otherwise dbTrue: g = DBBool.Operator(Operator.And, DBBool, DBBool, "x", DBBool, "y"); { Operand x = g.Arg("x"), y = g.Arg("y"); g.Return(Exp.New(DBBool, (x.Field("value") < y.Field("value")).Conditional(x.Field("value"), y.Field("value")))); } // Logical OR operator. Returns dbTrue if either operand is // dbTrue, dbNull if either operand is dbNull, otherwise dbFalse: g = DBBool.Operator(Operator.Or, DBBool, DBBool, "x", DBBool, "y"); { Operand x = g.Arg("x"), y = g.Arg("y"); g.Return(Exp.New(DBBool, (x.Field("value") > y.Field("value")).Conditional(x.Field("value"), y.Field("value")))); } // Definitely true operator. Returns true if the operand is // dbTrue, false otherwise: g = DBBool.Operator(Operator.True, typeof(bool), DBBool, "x"); { Operand x = g.Arg("x"); g.Return(x.Field("value") > 0); } // Definitely false operator. Returns true if the operand is // dbFalse, false otherwise: g = DBBool.Operator(Operator.False, typeof(bool), DBBool, "x"); { Operand x = g.Arg("x"); g.Return(x.Field("value") < 0); } // Overload the conversion from DBBool to string: g = DBBool.ImplicitConversionTo(typeof(string), "x"); { Operand x = g.Arg("x"); g.Return((x.Field("value") > 0).Conditional("dbTrue", (x.Field("value") < 0).Conditional("dbFalse", "dbNull"))); } // Override the Object.Equals(object o) method: g = DBBool.Public.Override.Method <bool>("Equals").Parameter <object>("o"); { g.Try(); { g.Return((g.This() == g.Arg("o").Cast(DBBool)).Cast <bool>()); } g.CatchAll(); { g.Return(false); } g.End(); } // Override the Object.GetHashCode() method: g = DBBool.Public.Override.Method <int>("GetHashCode"); { g.Return(value); } // Override the ToString method to convert DBBool to a string: g = DBBool.Public.Override.Method <string>("ToString"); { g.Switch(value); { g.Case(-1); g.Return("DBBool.False"); g.Case(0); g.Return("DBBool.Null"); g.Case(1); g.Return("DBBool.True"); g.DefaultCase(); g.Throw(Exp.New <InvalidOperationException>()); } g.End(); } } TypeGen Test = ag.Class("Test"); { CodeGen g = Test.Static.Void("Main"); { Operand a = g.Local(DBBool), b = g.Local(DBBool); g.Assign(a, Static.Field(DBBool, "dbTrue")); g.Assign(b, Static.Field(DBBool, "dbNull")); g.WriteLine("!{0} = {1}", a, !a); g.WriteLine("!{0} = {1}", b, !b); g.WriteLine("{0} & {1} = {2}", a, b, a & b); g.WriteLine("{0} | {1} = {2}", a, b, a | b); // Invoke the true operator to determine the Boolean // value of the DBBool variable: g.If(b); { g.WriteLine("b is definitely true"); } g.Else(); { g.WriteLine("b is not definitely true"); } g.End(); } } }
/// <summary> /// Create a wrapper class for a generic interface with more general type parameters than the wrapped interface. /// Downcasts to the correct more specific type are generated where necessary. /// This of course breaks type safety, and only calls to the class with the correct orginal types will work. /// Incorrect calls will throw <see cref = "InvalidCastException" />. /// </summary> /// <remarks> /// This is useful during reflection, when you don't want to know about specific types, but you can guarantee /// that a certain call will always be done with objects of the correct type. /// TODO: This non-generic method is only needed since RunSharp can't call generic methods, needed to generate wrappers recursively. /// TODO: Possibly Castle DynamicProxy could replace this if it allows creating 'non-matching' proxies and thus support the downcasting. /// </remarks> /// <param name = "typeToCreate">The less-specific generic type of the wrapper which will be generated.</param> /// <param name = "o">The object to wrap, which should implement the desired interface, with arbitrary type parameters.</param> /// <returns>An instance of the specified type which wraps the given object.</returns> public static object CreateGenericInterfaceWrapper(Type typeToCreate, object o) { Contract.Requires(o.GetType().IsOfGenericType(typeToCreate.GetGenericTypeDefinition())); Contract.Requires(typeToCreate.IsInterface); Type typeToCreateGeneric = typeToCreate.GetGenericTypeDefinition(); Type innerType = o.GetType(); Type innerMatchingType = innerType.GetMatchingGenericType(typeToCreateGeneric); // Implement passed type and redirect all public calls to inner instance. var assembly = new AssemblyGen("Whathecode.System.RunSharp"); TypeGen type = assembly.Public.Class("Wrapped" + typeToCreate.Name, typeof(object), typeToCreate); { const string inner = "inner"; FieldGen innerInstance = type.Private.Field(innerType, "_innerInstance"); FieldGen returnCached = type.Private.Field(typeof(Dictionary <int, object>), "_returnCached"); FieldGen returnWrappers = type.Private.Field(typeof(Dictionary <int, object>), "_returnWrappers"); // Create constructor which takes the wrapped instance as an argument. ConstructorGen constructor = type.Public.Constructor(); { constructor.Parameter(innerType, inner); CodeGen code = constructor.GetCode(); { code.Assign(innerInstance, code.Arg(inner)); code.Assign(returnCached, Exp.New(typeof(Dictionary <int, object>))); code.Assign(returnWrappers, Exp.New(typeof(Dictionary <int, object>))); } } // Create methods. int methodCount = 0; MethodInfo[] innerMethods = innerMatchingType.GetFlattenedInterfaceMethods(ReflectionHelper.FlattenedInstanceMembers).ToArray(); MethodInfo[] toCreateMethods = typeToCreate.GetFlattenedInterfaceMethods(ReflectionHelper.FlattenedInstanceMembers).ToArray(); MethodInfo[] genericMethods = typeToCreateGeneric.GetFlattenedInterfaceMethods(ReflectionHelper.FlattenedInstanceMembers).ToArray(); foreach (var method in innerMethods .Zip(toCreateMethods, genericMethods, (matching, toCreate, generic) => new { Id = methodCount++, Matching = matching, ToCreate = toCreate, Generic = generic }) .Where(z => z.Matching.IsPublic || z.Matching.IsFamily)) { // TODO: Not quite certain why override is required for extended interfaces (DeclaringType != typeTocreate), // but this seems to work. MethodInfo toCreate = method.ToCreate; MethodGen methodGen = toCreate.DeclaringType == typeToCreate ? type.MethodImplementation(typeToCreate, toCreate.ReturnType, toCreate.Name) : type.Public.Override.Method(toCreate.ReturnType, toCreate.Name); { ParameterInfo[] toCreateParameters = toCreate.GetParameters(); var parameters = toCreateParameters .Select(p => { var info = methodGen.BeginParameter(p.ParameterType, p.Name); info.End(); return(info); }).ToArray(); CodeGen code = methodGen.GetCode(); { // Cast arguments to the type of the inner instance. Operand[] args = parameters.Select(p => code.Arg(p.Name)).ToArray(); Operand[] castArgs = { }; if (args.Length > 0) { Type[] parameterTypes = method.Matching.GetParameters().Select(p => p.ParameterType).ToArray(); // TODO: When searching for generic methods, GetMethod returns null. http://stackoverflow.com/questions/4035719/getmethod-for-generic-method // Even when the correct method is found through custom filtering, RunSharp does not seem to be able to create generic methods yet. MethodInfo methodToCall = innerType.GetMethod(toCreate.Name, ReflectionHelper.FlattenedInstanceMembers, parameterTypes); castArgs = methodToCall.GetParameters() .Select((p, index) => args[index].Cast(typeof(object)).Cast(p.ParameterType)).ToArray(); } // Call inner instance and return value when needed. if (toCreate.ReturnType != typeof(void)) { Operand result = innerInstance.Invoke(toCreate.Name, castArgs); // Wrappers will recursively need to be created for generic return types. Type genericReturnType = method.Generic.ReturnType; if (genericReturnType.IsGenericType && genericReturnType.ContainsGenericParameters && genericReturnType.IsInterface) { // Check whether a new result is returned. Operand innerCached = code.Local(typeof(object)); code.If(returnCached.Invoke("TryGetValue", method.Id, innerCached.Ref())); { code.If((innerCached == result).LogicalNot()); { code.Invoke(returnWrappers, "Remove", method.Id); code.Invoke(returnCached, "Remove", method.Id); code.Invoke(returnCached, "Add", method.Id, result); } code.End(); } code.Else(); { code.Invoke(returnCached, "Add", method.Id, result); } code.End(); // Check whether a wrapper needs to be generated. Operand wrappedCached = code.Local(typeof(object)); code.If(returnWrappers.Invoke("TryGetValue", method.Id, wrappedCached.Ref()).LogicalNot()); { Operand proxied = Static.Invoke(typeof(Proxy), "CreateGenericInterfaceWrapper", toCreate.ReturnType, result); code.Assign(wrappedCached, proxied); code.Invoke(returnWrappers, "Add", method.Id, wrappedCached); } code.End(); code.Return(wrappedCached.Cast(toCreate.ReturnType)); } else { // A simple cast will work. // TODO: Throw proper exception when this is known to fail. E.g. generic type which is not an interface? code.Return(result.Cast(toCreate.ReturnType)); } } else { code.Invoke(innerInstance, toCreate.Name, castArgs); } } } } } Type wrapperType = type.GetCompletedType(true); return(Activator.CreateInstance(wrapperType, new[] { o })); }