public override CodeNode VisitUnconverterShell(UnconverterShellNode node) { _Writer.WriteStartElement("UnconverterShell"); Visit(node.Block); _Writer.WriteEndElement(); return(node); }
//unconverter node visiting public virtual CodeNode VisitUnconverterShell(UnconverterShellNode node) { var visitedBlock = Visit(node.Block); if (visitedBlock == node.Block) { return(node); } else { return(new UnconverterShellNode(visitedBlock as BlockNode ?? new BlockNode(visitedBlock))); } }
public void GenerateUnconverter() { _Fields = GetFieldLayoutsAndAssignments(); var node = new UnconverterShellNode( new BlockNode( from pair in _Fields.AsEnumerable().Reverse() //don't generate code for dependency properties where !(pair.Key is DependencyProperty) //this call through reflection is icky, but marginally better than the hard-coded table //we're just binding to the generic GenerateAssignment method for the field's type select GenerateAssignment(pair))); new UnconverterEmittingVisitor { ConcreteType = _Type, ILGen = _ILGen, }.Visit(node); }
public override CodeNode VisitUnconverterShell(UnconverterShellNode node) { Log($"Unconverter for {ConcreteType}"); //initialize the concrete record and cast the arg to it Log($"Creating instance"); _ConcreteRecordLocal = ILGen.DeclareLocal(ConcreteType); ILGen.Ldarg_0(); ILGen.Castclass(ConcreteType); ILGen.Stloc(_ConcreteRecordLocal); //initialize _StartedWriting _StartedWriting = ILGen.DeclareLocal <bool>(); ILGen.Ldc_I4_0(); ILGen.Stloc(_StartedWriting); //create a memory stream for writing Log($"Generating writer over stream"); LocalBuilder memoryStream = ILGen.DeclareLocal <MemoryStream>(); ILGen.Newobj <MemoryStream>(); ILGen.Stloc(memoryStream); ILGen.BeginExceptionBlock(); //create a binary writer _Writer = ILGen.DeclareLocal <BinaryWriter>(); //load args for binary writer .ctor ILGen.Ldloc(memoryStream); ILGen.Ldarg_1(); //the endianness ILGen.Ldc_I4_1(); //true for writing backwards ILGen.Newobj <BinaryWriter>(typeof(MemoryStream), typeof(Endian), typeof(bool)); ILGen.Stloc(_Writer); //nothing on the stack //visit the children and let them emit Visit(node.Block); //at this point, the memory stream should have all the bytes for the content in it, but backwards //get the content Log($"Getting data and reversing"); ILGen.Ldloc(memoryStream); ILGen.Callvirt(typeof(MemoryStream).GetMethod("ToArray")); var content = ILGen.DeclareLocal <byte[]>(); ILGen.Stloc(content); ILGen.Ldloc(content); ILGen.Call(typeof(Array).GetMethod("Reverse", typeof(Array))); ILGen.BeginFinallyBlock(); //dispose the memorystream Log($"Cleaning up"); ILGen.Ldloc(memoryStream); ILGen.Callvirt(typeof(Stream).GetMethod("Dispose")); ILGen.EndExceptionBlock(); //get the record type ILGen.Ldarg_0(); ILGen.Callvirt(typeof(StdfRecord).GetProperty("RecordType").GetGetMethod()); //load the content ILGen.Ldloc(content); //get the endian ILGen.Ldarg_1(); //new up a new UnknownRecord! Log($"returning the populated UnknownRecord"); ILGen.Newobj <UnknownRecord>(typeof(RecordType), typeof(byte[]), typeof(Endian)); ILGen.Ret(); return(node); }