CodeNode GenerateArrayAssignment(KeyValuePair <FieldLayoutAttribute, PropertyInfo> pair) { var fieldType = pair.Key.FieldType; ArrayFieldLayoutAttribute arrayLayout = (ArrayFieldLayoutAttribute)pair.Key; var initNodes = new List <CodeNode>(); //there are no array optionals, we should always have to create the local here if (_FieldLocalsTouched.Add(arrayLayout.FieldIndex)) { initNodes.Add(new CreateFieldLocalForWritingNode(arrayLayout.FieldIndex, fieldType.MakeArrayType())); } else { throw new InvalidOperationException("Array local was touched before we generated code for it."); } if (pair.Value == null) { throw new InvalidOperationException(Resources.ArraysMustBeAssignable); } CodeNode writeNode; FieldLayoutAttribute lengthLayout = _Fields[arrayLayout.ArrayLengthFieldIndex].Key; if (_FieldLocalsTouched.Add(arrayLayout.ArrayLengthFieldIndex)) { writeNode = new BlockNode( new CreateFieldLocalForWritingNode(arrayLayout.ArrayLengthFieldIndex, _Fields[arrayLayout.ArrayLengthFieldIndex].Key.FieldType), new SetLengthLocalNode(arrayLayout.FieldIndex, arrayLayout.ArrayLengthFieldIndex)); } else { writeNode = new ValidateSharedLengthLocalNode(arrayLayout.FieldIndex, arrayLayout.ArrayLengthFieldIndex); } writeNode = new BlockNode( writeNode, new WriteTypeNode(fieldType.MakeArrayType(), new LoadFieldLocalNode(arrayLayout.FieldIndex))); return(new WriteFieldNode(arrayLayout.FieldIndex, fieldType.MakeArrayType(), initialization: new BlockNode(initNodes), sourceProperty: pair.Value, writeOperation: writeNode)); }
/// <summary> /// Does the work of generating the appropriate code. /// </summary> internal void GenerateConverter() { List <KeyValuePair <FieldLayoutAttribute, PropertyInfo> > fields = GetFieldLayoutsAndAssignments(_Type); //pick up any fields that are required to parse the fields we need if (_Fields != null) { foreach (var pair in fields) { //if it's an assigned field that we are parsing if (pair.Value != null && _Fields.Contains(pair.Value.Name)) { //if it's an optional field if (pair.Key is FlaggedFieldLayoutAttribute op) { //if the flag index is an assigned field, add it to our list of parsed fields var prop = fields[op.FlagIndex].Value; if (prop != null) { _Fields.Add(prop.Name); } } else { if (pair.Key is DependencyProperty dep) { var prop = fields[dep.DependentOnIndex].Value; if (prop != null) { _Fields.Add(prop.Name); } } } } } } //generate the assignment nodes var assignments = from pair in fields //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); //add the end label to the end of the assignments var assignmentBlock = new FieldAssignmentBlockNode(new BlockNode(assignments)); //This is the list of nodes to emit to create the converter var block = new BlockNode( new InitializeRecordNode(), new EnsureCompatNode(), new InitReaderNode(), //TODO: Replace TryFinally with something more semantic like BinaryReaderScopeBlock new TryFinallyNode( assignmentBlock, new DisposeReaderNode()), new ReturnRecordNode()); //visit the block with an emitting visitor new ConverterEmittingVisitor() { ILGen = _ILGen, ConcreteType = _Type, EnableLog = ConverterLog.IsLogging, }.Visit(block); }
CodeNode GenerateAssignment(KeyValuePair <FieldLayoutAttribute, PropertyInfo> pair) { var fieldType = pair.Key.FieldType; //if this is an array, defer to GenerateArrayAssignment if (pair.Key is ArrayFieldLayoutAttribute) { // TODO: Why do we need these fieldType checks at all? if (fieldType == typeof(string)) { // TODO: Accept string arrays throw new InvalidOperationException(Resources.NoStringArrays); } if (fieldType == typeof(BitArray)) { throw new InvalidOperationException(Resources.NoBitArrayArrays); } return(GenerateArrayAssignment(pair)); } //get the length if this is a fixed-length string var stringLength = -1; if (pair.Key is StringFieldLayoutAttribute stringLayout && stringLayout.Length > 0) { stringLength = stringLayout.Length; } //just skip this field if we have an assignment, but shouldn't be parsing it if (pair.Value != null && !ShouldParseField(pair.Value.Name)) { if (stringLength > 0) { return(new SkipRawBytesNode(stringLength)); } else { return(new SkipTypeNode(fieldType)); } } //determine how we'll read the field CodeNode readerNode; if (stringLength > 0) { readerNode = new ReadFixedStringNode(stringLength); } else { readerNode = new ReadTypeNode(fieldType); } BlockNode assignmentBlock = null; //if we have a property to assign to, generate the appropriate assignment statements if (pair.Value != null) { var assignmentNodes = new List <CodeNode>(); //if this is optional, set us up to skip if the missing flag is set if (pair.Key is FlaggedFieldLayoutAttribute optionalLayout) { assignmentNodes.Add(new SkipAssignmentIfFlagSetNode(optionalLayout.FlagIndex, optionalLayout.FlagMask)); } //if we have a missing value, set us up to skip if the value matches the missing value else if (pair.Key.MissingValue != null && !pair.Key.PersistMissingValue) { if (!(fieldType.IsAssignableFrom(pair.Key.MissingValue.GetType()))) { throw new InvalidOperationException(string.Format("Missing value {0} is not assignable to {1}.", pair.Key.MissingValue, fieldType)); } assignmentNodes.Add(new SkipAssignmentIfMissingValueNode(pair.Key.MissingValue)); } //set us up to assign to the property assignmentNodes.Add(new AssignFieldToPropertyNode(fieldType, pair.Value)); assignmentBlock = new BlockNode(assignmentNodes); } return(new FieldAssignmentNode(fieldType, pair.Key.FieldIndex, readerNode, assignmentBlock)); }
public FieldAssignmentBlockNode(BlockNode node) { Block = node; }
public UnconverterShellNode(BlockNode block) { Block = block; }
public virtual CodeNode VisitBlock(BlockNode node) { return(new BlockNode(from n in node.Nodes select Visit(n))); }