public static void GenTypeAttributeTest(AssemblyGen ag) { TypeGen MyAttribute = ag.Public.Class("MyAttribute", typeof(Attribute)) .BeginAttribute <AttributeUsageAttribute>(AttributeTargets.Class).Set("AllowMultiple", true).End(); FieldGen testField = MyAttribute.Field <object>("testField") .Attribute <DescriptionAttribute>("Test field"); PropertyGen testProperty = MyAttribute.Public.SimpleProperty(testField, "TestProperty") .Attribute <ObsoleteAttribute>("Do not use this"); testProperty.Getter().Attribute <DescriptionAttribute>("Getter method"); testProperty.Getter().ReturnParameter.Attribute <DescriptionAttribute>("Getter return value"); testProperty.Setter().Attribute <DescriptionAttribute>("Setter method"); TypeGen tg = ag.Class("Test") .BeginAttribute(MyAttribute).Set("TestProperty", 3).End() .Attribute <DescriptionAttribute>("Test class"); tg.Static.Void("Main") .BeginAttribute(MyAttribute).Set("TestProperty", 3).End(); TypeGen SimpleDelegate = ag.DelegateVoid("SimpleDelegate") .Attribute <DescriptionAttribute>("Test delegate"); EventGen TestEvent = tg.Static.Event(SimpleDelegate, "TestEvent") .Attribute <DescriptionAttribute>("Test event"); TestEvent.AddMethod().Attribute <DescriptionAttribute>("Event add method"); TestEvent.RemoveMethod().Attribute <DescriptionAttribute>("Event remove method"); }
// example based on the MSDN Structs Sample (struct1.cs) public static void GenStruct1(AssemblyGen ag) { var st = ag.StaticFactory; var exp = ag.ExpressionFactory; CodeGen g; TypeGen SimpleStruct = ag.Struct("SimpleStruct"); { FieldGen xval = SimpleStruct.Field(typeof(int), "xval"); PropertyGen X = SimpleStruct.Public.Property(typeof(int), "X"); { X.Getter().GetCode().Return(xval); g = X.Setter(); { g.If(g.PropertyValue() < 100); { g.Assign(xval, g.PropertyValue()); } g.End(); } } g = SimpleStruct.Public.Method(typeof(void), "DisplayX"); { g.WriteLine("The stored value is: {0}", xval); } } TypeGen TestClass = ag.Class("TestClass"); { g = TestClass.Public.Static.Method(typeof(void), "Main"); { var ss = g.Local(SimpleStruct); g.InitObj(ss); ITypeMapper typeMapper = ag.TypeMapper; g.Assign(ss.Property("X"), 5); g.Invoke(ss, "DisplayX"); } } }
// example based on the MSDN Structs Sample (struct1.cs) public static void GenStruct1(AssemblyGen ag) { CodeGen g; TypeGen SimpleStruct = ag.Struct("SimpleStruct"); { FieldGen xval = SimpleStruct.Field <int>("xval"); PropertyGen X = SimpleStruct.Public.Property <int>("X"); { X.Getter().GetCode().Return(xval); g = X.Setter(); { g.If(g.PropertyValue() < 100); { g.Assign(xval, g.PropertyValue()); } g.End(); } } g = SimpleStruct.Public.Void("DisplayX"); { g.WriteLine("The stored value is: {0}", xval); } } TypeGen TestClass = ag.Class("TestClass"); { g = TestClass.Public.Static.Void("Main"); { Operand ss = g.Local(SimpleStruct); g.InitObj(ss); g.Assign(ss.Property("X"), 5); g.Invoke(ss, "DisplayX"); } } }
// example based on the MSDN Indexed Properties Sample (indexedproperty.cs) public static void GenIndexedProperty(AssemblyGen ag) { var st = ag.StaticFactory; var exp = ag.ExpressionFactory; CodeGen g; ITypeMapper m = ag.TypeMapper; TypeGen Document = ag.Public.Class("Document"); { FieldGen TextArray = Document.Private.Field(typeof(char[]), "TextArray"); // The text of the document. // Type allowing the document to be viewed like an array of words: TypeGen WordCollection = Document.Public.Class("WordCollection"); { FieldGen document = WordCollection.ReadOnly.Field(Document, "document"); // The containing document var document_TextArray = document.Field("TextArray", m); // example of a saved expression - it is always re-evaluated when used g = WordCollection.Internal.Constructor().Parameter(Document, "d"); { g.Assign(document, g.Arg("d")); } // Helper function -- search character array "text", starting at // character "begin", for word number "wordCount." Returns false // if there are less than wordCount words.Sets "start" and // length" to the position and length of the word within text: g = WordCollection.Private.Method(typeof(bool), "GetWord") .Parameter(typeof(char[]), "text") .Parameter(typeof(int), "begin") .Parameter(typeof(int), "wordCount") .Out.Parameter(typeof(int), "start") .Out.Parameter(typeof(int), "length") ; { ContextualOperand text = g.Arg("text"), begin = g.Arg("begin"), wordCount = g.Arg("wordCount"), start = g.Arg("start"), length = g.Arg("length"); var end = g.Local(text.ArrayLength()); var count = g.Local(0); var inWord = g.Local(-1); g.Assign(start, length.Assign(0)); var i = g.Local(); g.For(i.Assign(begin), i <= end, i.Increment()); { var isLetter = g.Local(i < end && st.Invoke(typeof(char), "IsLetterOrDigit", text[i])); g.If(inWord >= 0); { g.If(!isLetter); { g.If(count.PostIncrement() == wordCount); { g.Assign(start, inWord); g.Assign(length, i - inWord); g.Return(true); } g.End(); g.Assign(inWord, -1); } g.End(); } g.Else(); { g.If(isLetter); { g.Assign(inWord, i); } g.End(); } g.End(); } g.End(); g.Return(false); } // Indexer to get and set words of the containing document: PropertyGen Item = WordCollection.Public.Indexer(typeof(string)).Index(typeof(int), "index"); { g = Item.Getter(); { var index = g.Arg("index"); var start = g.Local(0); var length = g.Local(0); g.If(g.This().Invoke("GetWord", document_TextArray, 0, index, start.Ref(), length.Ref())); { g.Return(exp.New(typeof(string), document_TextArray, start, length)); } g.Else(); { g.Throw(exp.New(typeof(IndexOutOfRangeException))); } g.End(); } g = Item.Setter(); { var index = g.Arg("index"); var value = g.PropertyValue(); var start = g.Local(0); var length = g.Local(0); g.If(g.This().Invoke("GetWord", document_TextArray, 0, index, start.Ref(), length.Ref())); { // Replace the word at start/length with the // string "value": g.If(length == value.Property("Length")); { g.Invoke(typeof(Array), "Copy", value.Invoke("ToCharArray"), 0, document_TextArray, start, length); } g.Else(); { var newText = g.Local(exp.NewArray(typeof(char), document_TextArray.ArrayLength() + value.Property("Length") - length)); g.Invoke(typeof(Array), "Copy", document_TextArray, 0, newText, 0, start); g.Invoke(typeof(Array), "Copy", value.Invoke("ToCharArray"), 0, newText, start, value.Property("Length")); g.Invoke(typeof(Array), "Copy", document_TextArray, start + length, newText, start + value.Property("Length"), document_TextArray.ArrayLength() - start - length); g.Assign(document_TextArray, newText); } g.End(); } g.Else(); { g.Throw(exp.New(typeof(IndexOutOfRangeException))); } g.End(); } } // Get the count of words in the containing document: g = WordCollection.Public.Property(typeof(int), "Count").Getter(); { ContextualOperand count = g.Local(0), start = g.Local(0), length = g.Local(0); g.While(g.This().Invoke("GetWord", document_TextArray, start + length, 0, start.Ref(), length.Ref())); { g.Increment(count); } g.End(); g.Return(count); } } // Type allowing the document to be viewed like an "array" // of characters: TypeGen CharacterCollection = Document.Public.Class("CharacterCollection"); { FieldGen document = CharacterCollection.ReadOnly.Field(Document, "document"); // The containing document var document_TextArray = document.Field("TextArray", m); g = CharacterCollection.Internal.Constructor().Parameter(Document, "d"); { g.Assign(document, g.Arg("d")); } // Indexer to get and set characters in the containing document: PropertyGen Item = CharacterCollection.Public.Indexer(typeof(char)).Index(typeof(int), "index"); { g = Item.Getter(); { g.Return(document_TextArray[g.Arg("index")]); } g = Item.Setter(); { g.Assign(document_TextArray[g.Arg("index")], g.PropertyValue()); } } // Get the count of characters in the containing document: g = CharacterCollection.Public.Property(typeof(int), "Count").Getter(); { g.Return(document_TextArray.ArrayLength()); } } // Because the types of the fields have indexers, // these fields appear as "indexed properties": FieldGen Words = Document.Public.ReadOnly.Field(WordCollection, "Words"); FieldGen Characters = Document.Public.ReadOnly.Field(CharacterCollection, "Characters"); g = Document.Public.Constructor().Parameter(typeof(string), "initialText"); { g.Assign(TextArray, g.Arg("initialText").Invoke("ToCharArray")); g.Assign(Words, exp.New(WordCollection, g.This())); g.Assign(Characters, exp.New(CharacterCollection, g.This())); } g = Document.Public.Property(typeof(string), "Text").Getter(); { g.Return(exp.New(typeof(string), TextArray)); } } TypeGen Test = ag.Class("Test"); { g = Test.Public.Static.Method(typeof(void), "Main"); { var d = g.Local(exp.New(Document, "peter piper picked a peck of pickled peppers. How many pickled peppers did peter piper pick?")); // Change word "peter" to "penelope": var i = g.Local(); g.For(i.Assign(0), i < d.Field("Words").Property("Count"), i.Increment()); { g.If(d.Field("Words")[i] == "peter"); { g.Assign(d.Field("Words")[i], "penelope"); } g.End(); } g.End(); // Change character "p" to "P" g.For(i.Assign(0), i < d.Field("Characters").Property("Count"), i.Increment()); { g.If(d.Field("Characters")[i] == 'p'); { g.Assign(d.Field("Characters")[i], 'P'); } g.End(); } g.End(); g.WriteLine(d.Property("Text")); } } }
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); }