Пример #1
0
        CodeNode GenerateAssignment(KeyValuePair <FieldLayoutAttribute, PropertyInfo> pair)
        {
            var fieldType = pair.Key.FieldType;
            StringFieldLayoutAttribute stringLayout = pair.Key as StringFieldLayoutAttribute;
            ArrayFieldLayoutAttribute  arrayLayout  = pair.Key as ArrayFieldLayoutAttribute;

            //if it is an array, defer to GenerateArrayAssignment
            if (arrayLayout != null)
            {
                // 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));
            }

            var initNodes = new List <CodeNode>();

            bool localWasPresent = true;

            if (_FieldLocalsTouched.Add(pair.Key.FieldIndex))
            {
                localWasPresent = false;
                //add a create local node
                initNodes.Add(new CreateFieldLocalForWritingNode(pair.Key.FieldIndex, pair.Key.FieldType));
                _FieldLocalsTouched.Add(pair.Key.FieldIndex);
            }

            //find out if there is an optional field flag that we need to manage
            FieldLayoutAttribute        optionalFieldLayout          = null;
            FlaggedFieldLayoutAttribute currentAsOptionalFieldLayout = pair.Key as FlaggedFieldLayoutAttribute;

            if (currentAsOptionalFieldLayout != null)
            {
                optionalFieldLayout = _Fields[currentAsOptionalFieldLayout.FlagIndex].Key;
                if (_FieldLocalsTouched.Add(currentAsOptionalFieldLayout.FlagIndex))
                {
                    initNodes.Add(new CreateFieldLocalForWritingNode(currentAsOptionalFieldLayout.FlagIndex, optionalFieldLayout.FieldType));
                }
            }

            //this will hold a node that will write in the case we have no value to write
            CodeNode noValueWriteContingency = null;
            //this will hold the source of the write that will happen above
            CodeNode noValueWriteContingencySource = null;

            //Decide what to do if we don't have a value to write.
            //This will happen if we don't store the value in a property, it is "missing" from the property source, or something else
            //TODO: should these have a different precedence?
            if (pair.Key.MissingValue != null)
            {
                //if we have a missing value, set that as the write source
                noValueWriteContingencySource = new LoadMissingValueNode(pair.Key.MissingValue, fieldType);
            }
            else if (localWasPresent || optionalFieldLayout != null)
            {
                //if the local was present when we started, that means it was initialized by another field. We can safely write it
                //Similarly, if this is marked as an optional field, we can still write whatever the value of the local is (cheat)
                noValueWriteContingencySource = new LoadFieldLocalNode(pair.Key.FieldIndex);
            }
            else if (fieldType.IsValueType)
            {
                //if T is a value type, we're up a creek with nothing to write.
                //this is obviously not a good place, so throw in the converter
                noValueWriteContingency = new ThrowInvalidOperationNode(string.Format(Resources.NonNullableField, pair.Key.FieldIndex, _Type));
            }
            else
            {
                //otherwise, we can try to write null (unless it is a fixed-length string, which should have a default instead)
                if (stringLayout != null && stringLayout.Length > 0)
                {
                    //TODO: move this check into StdfStringLayout if we can, along with a check that the missing value length matches
                    throw new NotSupportedException(Resources.FixedLengthStringMustHaveDefault);
                }
                noValueWriteContingencySource = new LoadNullNode();
            }

            //create the write node and the no-value contingency if we don't already have one
            CodeNode writeNode;

            if (stringLayout != null && stringLayout.Length > 0)
            {
                noValueWriteContingency = noValueWriteContingency ?? new WriteFixedStringNode(stringLayout.Length, noValueWriteContingencySource);
                writeNode = new WriteFixedStringNode(stringLayout.Length, new LoadFieldLocalNode(pair.Key.FieldIndex));
            }
            else
            {
                noValueWriteContingency = noValueWriteContingency ?? new WriteTypeNode(fieldType, noValueWriteContingencySource);
                writeNode = new WriteTypeNode(fieldType, new LoadFieldLocalNode(pair.Key.FieldIndex));
            }
            //return the crazy node
            //TODO: refactor this better, this sucks
            return(new WriteFieldNode(pair.Key.FieldIndex, fieldType,
                                      initialization: new BlockNode(initNodes),
                                      sourceProperty: pair.Value,
                                      writeOperation: writeNode,
                                      noValueWriteContingency: noValueWriteContingency,
                                      optionalFieldIndex: optionalFieldLayout == null ? null : (int?)optionalFieldLayout.FieldIndex,
                                      optionalFieldMask: optionalFieldLayout == null ? (byte)0 : currentAsOptionalFieldLayout.FlagMask));
        }
Пример #2
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
            StringFieldLayoutAttribute stringLayout = pair.Key as StringFieldLayoutAttribute;
            var stringLength = -1;

            if (stringLayout != null && 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
                FlaggedFieldLayoutAttribute optionalLayout = pair.Key as FlaggedFieldLayoutAttribute;
                if (optionalLayout != null)
                {
                    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)
                {
                    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, pair.Key.PersistMissingValue));
                }
                //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));
        }