/// <summary> /// Creates a store operation of an object field using the given field access. /// </summary> /// <param name="location">The current location.</param> /// <param name="objectValue">The object value.</param> /// <param name="fieldSpan">The field span.</param> /// <param name="value">The field value to store.</param> /// <returns>A reference to the requested value.</returns> public ValueReference CreateSetField( Location location, Value objectValue, FieldSpan fieldSpan, Value value) { var structureType = objectValue.Type.As <StructureType>(location); location.Assert(structureType.Get(Context, fieldSpan) == value.Type); // Fold structure values if (objectValue is StructureValue structureValue) { var instance = CreateStructure(location, structureType); foreach (Value fieldValue in structureValue.Nodes) { instance.Add(fieldValue); } for (int i = 0; i < fieldSpan.Span; ++i) { instance[fieldSpan.Index + i] = CreateGetField( location, value, new FieldSpan(i)); } return(instance.Seal()); } return(objectValue is NullValue && fieldSpan.Span == structureType.NumFields ? (ValueReference)value : Append(new SetField( GetInitializer(location), objectValue, fieldSpan, value))); }
public ValueReference CreateGetField( Location location, Value objectValue, FieldSpan fieldSpan) { var structureType = objectValue.Type as StructureType; if (structureType == null && fieldSpan.Span < 2) { return(objectValue); } // Must be a structure type location.AssertNotNull(structureType); // Try to combine different get and set operations operating on similar spans switch (objectValue) { case StructureValue structureValue: return(structureValue.Get(this, location, fieldSpan)); case NullValue _: return(CreateNull( location, structureType.Get(Context, fieldSpan))); case SetField setField: // Optimize for simple cases if (setField.FieldSpan == fieldSpan) { return(setField.Value); } // Check whether our field span is included in the updated field span else if (setField.FieldSpan.Contains(fieldSpan)) { // Our field span is included in the parent span return(CreateGetField( location, setField.Value, new FieldSpan( fieldSpan.Index - setField.FieldSpan.Index, fieldSpan.Span))); } // If our field span overlaps with the found one we have to split // the part into an overlapping part and the remaining part(s) else if (fieldSpan.Overlaps(setField.FieldSpan)) { // Ignore this case for now as it adds even more nodes break; } // These field spans have to be distinct from each other else { location.Assert(!fieldSpan.Contains(setField.FieldSpan)); // We can safely continue with the parent value since this // SetField operation does not influence the new GetField value return(CreateGetField( location, setField.ObjectValue, fieldSpan)); } } // We could not find any matching constant value return(Append(new GetField( GetInitializer(location), objectValue, fieldSpan))); }
/// <summary> /// Appends the referenced field accessor. /// </summary> /// <param name="fieldAccess">The field access.</param> public void AppendField(FieldSpan fieldAccess) { stringBuilder.Append('.'); AppendFieldName(fieldAccess.Index); }
/// <summary> /// Appends a field target. /// </summary> /// <param name="target">The target.</param> /// <param name="fieldSpan">The field span.</param> internal void AppendFieldTarget(Variable target, FieldSpan fieldSpan) { BeginAppendTarget(target, false); AppendField(fieldSpan); stringBuilder.Append(" = "); }
/// <summary> /// Creates a store operation of an object field using the given field access. /// </summary> /// <param name="location">The current location.</param> /// <param name="objectValue">The object value.</param> /// <param name="fieldSpan">The field span.</param> /// <param name="value">The field value to store.</param> /// <returns>A reference to the requested value.</returns> public ValueReference CreateSetField( Location location, Value objectValue, FieldSpan fieldSpan, Value value) { var structureType = objectValue.Type.As <StructureType>(location); location.Assert(structureType.Get(BaseContext, fieldSpan) == value.Type); // Fold structure values if (objectValue is StructureValue structureValue) { var instance = CreateStructure(location, structureType); foreach (Value fieldValue in structureValue.Nodes) { instance.Add(fieldValue); } for (int i = 0; i < fieldSpan.Span; ++i) { instance[fieldSpan.Index + i] = CreateGetField( location, value, new FieldSpan(i)); } return(instance.Seal()); } // Optimize common cases in which this set field operation fills a whole // structure instance if (objectValue is SetField && !fieldSpan.HasSpan && fieldSpan.Index + 1 == structureType.NumFields && structureType.NumFields < 32) { // Initialize our internal field-value lookup var fieldValues = new Value[structureType.NumFields]; fieldValues[fieldSpan.Index] = value; // Traverse the whole chain of all set-field operations var parent = objectValue; int traversalLength = structureType.NumFields - 1; while (!(parent is NullValue) && traversalLength > 0) { // Check whether we are still on the right track while traversing // set of (possibly unordered) set-field operations if (!(parent is SetField otherSetField) || otherSetField.FieldSpan.HasSpan || fieldValues[otherSetField.FieldSpan.Index] != null) { break; } // Register this set-field operation fieldValues[otherSetField.FieldSpan.Index] = otherSetField.Value; // Decrease the traversal length --traversalLength; // Update the parent parent = otherSetField.ObjectValue; } // Check whether all indices have been visited found if (traversalLength < 1 && parent is NullValue) { // Build new structure value containing all traversed values var instance = CreateStructure(location, structureType); foreach (var fieldValue in fieldValues) { instance.Add(fieldValue); } return(instance.Seal()); } } return(objectValue is NullValue && fieldSpan.Span == structureType.NumFields ? (ValueReference)value : Append(new SetField( GetInitializer(location), objectValue, fieldSpan, value))); }