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));
        }
示例#2
0
        /// <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);
        }
示例#3
0
        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));
        }
示例#4
0
 public FieldAssignmentBlockNode(BlockNode node)
 {
     Block = node;
 }
示例#5
0
 public UnconverterShellNode(BlockNode block)
 {
     Block = block;
 }
示例#6
0
 public virtual CodeNode VisitBlock(BlockNode node)
 {
     return(new BlockNode(from n in node.Nodes select Visit(n)));
 }