| | | 1 | | using NanoCLang.Environemnts; |
| | | 2 | | using System; |
| | | 3 | | using System.Collections.Generic; |
| | | 4 | | using System.Linq; |
| | | 5 | | |
| | | 6 | | namespace NanoCLang.Entities { |
| | | 7 | | /// <summary> |
| | | 8 | | /// Provides a class for structure write expressions. |
| | | 9 | | /// </summary> |
| | | 10 | | public class StructWriteExpression : WriteExpression, IEquatable<StructWriteExpression?> { |
| | | 11 | | /// <summary> |
| | | 12 | | /// Creates a new instance of a structure write expression that writes the value to the <paramref name="structur |
| | | 13 | | /// </summary> |
| | | 14 | | /// <param name="structure">Structure to write to.</param> |
| | | 15 | | /// <param name="member">Member in the structure to write to.</param> |
| | | 16 | | /// <param name="value">Value to insert into the <paramref name="member"/>.</param> |
| | 26 | 17 | | public StructWriteExpression(PureExpression structure, string member, PureExpression value) { |
| | 13 | 18 | | Structure = structure; |
| | 13 | 19 | | Member = member; |
| | 13 | 20 | | Value = value; |
| | 13 | 21 | | } |
| | | 22 | | /// <summary> |
| | | 23 | | /// Structure that is written to. |
| | | 24 | | /// </summary> |
| | 21 | 25 | | public PureExpression Structure { get; } |
| | | 26 | | /// <summary> |
| | | 27 | | /// Member in the structure to write to. |
| | | 28 | | /// </summary> |
| | 13 | 29 | | public string Member { get; } |
| | | 30 | | /// <summary> |
| | | 31 | | /// Value to insert into the <see cref="Member"/>. |
| | | 32 | | /// </summary> |
| | 9 | 33 | | public PureExpression Value { get; } |
| | | 34 | | /// <inheritdoc/> |
| | 9 | 35 | | protected override World DoInferWorld(GlobalEnvironment phi, LocalEnvironment gamma, Heap heap) { |
| | 9 | 36 | | VerbConsole.WriteLine(VerbosityLevel.Default, "T-StrWrite"); |
| | 9 | 37 | | return (BaseWrite = new PointerWriteExpression(GetProjectionPointer(phi, gamma, Structure, Member), Value)) |
| | 9 | 38 | | .InferWorld(phi, gamma, heap); |
| | 5 | 39 | | } |
| | | 40 | | /// <summary> |
| | | 41 | | /// Resolves the structure projection and outputs a correctly offset pointer to the requested structure member. |
| | | 42 | | /// </summary> |
| | | 43 | | /// <param name="phi">Global environment that contains the structures definition.</param> |
| | | 44 | | /// <param name="gamma">Local environment that contains information about the location of the pointer.</param> |
| | | 45 | | /// <param name="origin">Pointer to the origin of the structure.</param> |
| | | 46 | | /// <param name="member">Name of requested structure member.</param> |
| | | 47 | | /// <returns>Offset pointer to member of structure.</returns> |
| | 15 | 48 | | internal static PureExpression GetProjectionPointer(GlobalEnvironment phi, LocalEnvironment gamma, PureExpressio |
| | 15 | 49 | | var type = origin.InferType(gamma); |
| | 15 | 50 | | var baseType = type.BaseType; |
| | 15 | 51 | | if (!(baseType is ReferenceType t)) |
| | 2 | 52 | | throw new IllFormedException(origin, $"Cannot perform structure projection on non-reference type!"); |
| | 13 | 53 | | if (baseType != new ReferenceType(new Location(t.Location.Name, false), Index.Zero)) |
| | 2 | 54 | | throw new IllFormedException(origin, $"Pointer must point to beginning of a structure!"); |
| | 11 | 55 | | if (!gamma.TryGetStructLoc(t.Location.Name, out var structName)) |
| | 0 | 56 | | throw new IllFormedException(origin, $"Location {t.Location} is not linked to a structure type!"); |
| | 11 | 57 | | if (!phi.TryGetStruct(structName, out var def)) |
| | 0 | 58 | | throw new IllFormedException(origin, $"Link to undefined structure named {structName}!"); |
| | 11 | 59 | | var offset = FindOffset(def, member); |
| | 10 | 60 | | return origin + new IntegerConstant(offset, 4); |
| | 10 | 61 | | } |
| | | 62 | | |
| | | 63 | | /// <summary> |
| | | 64 | | /// Finds the offset of the requested member in the struct given its definition <paramref name="def"/>. |
| | | 65 | | /// </summary> |
| | | 66 | | /// <param name="def">Structure definition.</param> |
| | | 67 | | /// <param name="member">Requested member to access.</param> |
| | | 68 | | /// <returns>Offset of the member in the struct.</returns> |
| | 11 | 69 | | private static int FindOffset(StructDefinition def, string member) { |
| | 26 | 70 | | var memberField = def.Fields.FirstOrDefault(i => i.Name == member); |
| | 11 | 71 | | if (memberField is null) |
| | 1 | 72 | | throw new IllFormedException(def, $"Structure has no member named {member}!"); |
| | 10 | 73 | | if (!(memberField.Binding.Index is SingletonIndex i)) |
| | 0 | 74 | | throw new IllFormedException(def, $"Structure member must point to a signle offset, instead it points to |
| | 10 | 75 | | return i.Offset; |
| | 10 | 76 | | } |
| | | 77 | | |
| | | 78 | | /// <inheritdoc/> |
| | 4 | 79 | | public override IEnumerable<StringFormatterToken> Tokens(NanoCSourceFormat args) { |
| | 24 | 80 | | foreach (var tk in Structure.Tokens(args)) yield return tk; |
| | 4 | 81 | | yield return "->"; |
| | 4 | 82 | | yield return Member; |
| | 8 | 83 | | if (args.SpaceBeforeBindingAssignment) yield return " "; |
| | 4 | 84 | | yield return "="; |
| | 8 | 85 | | if (args.SpaceAfterBindingAssignment) yield return " "; |
| | 24 | 86 | | foreach (var tk in Value.Tokens(args)) yield return tk; |
| | 4 | 87 | | } |
| | | 88 | | /// <inheritdoc/> |
| | 0 | 89 | | public override IEnumerable<string> RequiredFunctions() { yield break; } |
| | | 90 | | #region Equality checks |
| | | 91 | | /// <inheritdoc/> |
| | 4 | 92 | | public override bool Equals(object? obj) => Equals(obj as StructWriteExpression); |
| | | 93 | | /// <inheritdoc/> |
| | 4 | 94 | | public bool Equals(StructWriteExpression? other) => !(other is null) && EqualityComparer<PureExpression>.Default |
| | | 95 | | /// <inheritdoc/> |
| | 0 | 96 | | public override int GetHashCode() => HashCode.Combine(Structure); |
| | | 97 | | /// <inheritdoc/> |
| | 0 | 98 | | public static bool operator ==(StructWriteExpression? left, StructWriteExpression? right) => EqualityComparer<St |
| | | 99 | | /// <inheritdoc/> |
| | 0 | 100 | | public static bool operator !=(StructWriteExpression? left, StructWriteExpression? right) => !(left == right); |
| | | 101 | | #endregion |
| | | 102 | | } |
| | | 103 | | } |