| | | 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 unfold expressions. |
| | | 9 | | /// </summary> |
| | | 10 | | public class UnfoldExpression : Expression, IEquatable<UnfoldExpression?> { |
| | | 11 | | /// <summary> |
| | | 12 | | /// Creates an instance of an unfold expression that unfolds the pointer in the <paramref name="expression"/> at |
| | | 13 | | /// </summary> |
| | | 14 | | /// <param name="name">Name of the binding.</param> |
| | | 15 | | /// <param name="location">Location that the <paramref name="expression"/> refers to.</param> |
| | | 16 | | /// <param name="expression">Expression that is bound to the <paramref name="name"/>.</param> |
| | | 17 | | /// <param name="next">Expression that is evaluated with the binding.</param> |
| | 30 | 18 | | public UnfoldExpression(string name, string location, PureExpression expression, Expression next) { |
| | 15 | 19 | | Name = name; |
| | 15 | 20 | | Location = location; |
| | 15 | 21 | | Expression = expression; |
| | 15 | 22 | | Next = next; |
| | 15 | 23 | | } |
| | | 24 | | /// <summary> |
| | | 25 | | /// Name that the <see cref="Expression"/> is bound to. |
| | | 26 | | /// </summary> |
| | 35 | 27 | | public string Name { get; } |
| | | 28 | | /// <summary> |
| | | 29 | | /// Location that the pointer in the <see cref="Expression"/> refers to. |
| | | 30 | | /// </summary> |
| | 35 | 31 | | public string Location { get; } |
| | | 32 | | /// <summary> |
| | | 33 | | /// Pointer that shall be unfolded and bound to the <see cref="Name"/>. |
| | | 34 | | /// </summary> |
| | 41 | 35 | | public PureExpression Expression { get; } |
| | | 36 | | /// <summary> |
| | | 37 | | /// Expression that is evaluated with the binding. |
| | | 38 | | /// </summary> |
| | 41 | 39 | | public Expression Next { get; } |
| | | 40 | | /// <inheritdoc/> |
| | 6 | 41 | | protected override World DoInferWorld(GlobalEnvironment phi, LocalEnvironment gamma, Heap heap) { |
| | 6 | 42 | | var ptrType = Expression.InferType(gamma); |
| | 6 | 43 | | if (!(ptrType.BaseType is ReferenceType ptrBase)) |
| | 0 | 44 | | throw new IllFormedException(Expression, $"Cannot unfold expression of non-reference type {ptrType.BaseT |
| | 6 | 45 | | var labs = ptrBase.Location; |
| | 6 | 46 | | var lj = new Location(labs.Name, false); |
| | 6 | 47 | | if (ptrBase.Concrete) |
| | 0 | 48 | | throw new IllFormedException(Expression, $"Cannot unfold reference to concrete location {labs}!"); |
| | 6 | 49 | | if (!heap.TryGetBinding(labs, out var b)) |
| | 0 | 50 | | throw new IllFormedException(Expression, $"Cannot unfold reference to location {labs} without a heap bin |
| | 6 | 51 | | if (heap.Contains(lj)) |
| | 0 | 52 | | throw new IllFormedException(Expression, $"Cannot unfold, because {lj} was already unfolded in heap!"); |
| | 12 | 53 | | if (!ptrType.SubType(gamma, new RefinedType(ptrBase, v => PureExpression.UnqualExpression(v, new IntegerCons |
| | 0 | 54 | | throw new IllFormedException(Expression, $"Cannot unfold possibly nullptr reference {ptrBase}!"); |
| | 6 | 55 | | var theta = new Substitutor(); |
| | 39 | 56 | | for (var i = 0; i < b.Length; i++) { |
| | 9 | 57 | | var blockType = b[i]; |
| | 9 | 58 | | switch (blockType.Index) { |
| | | 59 | | case SingletonIndex idx: |
| | 6 | 60 | | var fresh = new VariableExpression(Heap.OffsetVar(idx.Offset)); |
| | 6 | 61 | | theta.BlockOffsets.Add(idx.Offset, fresh); |
| | 6 | 62 | | break; |
| | 3 | 63 | | case SequenceIndex idx: break; |
| | 0 | 64 | | default: throw new InvalidProgramException("Expected singleton or sequence index!"); |
| | | 65 | | } |
| | 9 | 66 | | } |
| | 6 | 67 | | BlockType[] bj = new BlockType[b.Length]; |
| | 39 | 68 | | for (var i = 0; i < b.Length; i++) { |
| | 9 | 69 | | var blockType = b[i]; |
| | | 70 | | bj[i] = (blockType.Index) switch { |
| | 12 | 71 | | SingletonIndex idx => new BlockType((Index)idx.Clone(), new RefinedType(blockType.Type.BaseType, v = |
| | 3 | 72 | | SequenceIndex idx => new BlockType((Index)idx.Clone(), blockType.Type.Replace(theta)), |
| | 0 | 73 | | _ => throw new InvalidProgramException("Expected singleton or sequence index!") |
| | | 74 | | }; |
| | 9 | 75 | | } |
| | 6 | 76 | | var h1 = heap * new Heap(new LocationBinding(lj, bj)); |
| | 24 | 77 | | var world = gamma.With(b.Where(i => i.Index is SingletonIndex) |
| | 12 | 78 | | .Select(i => new KeyValuePair<string, Type>(Heap.OffsetVar((i.Index as SingletonIndex ?? throw new Inval |
| | 6 | 79 | | gamma => { |
| | 6 | 80 | | h1.WellFormed(gamma); |
| | 12 | 81 | | return gamma.With(Name, new RefinedType(new ReferenceType(lj, ptrBase.Offsets), v => PureExpression. |
| | 12 | 82 | | gamma => Next.InferWorld(phi, gamma, h1)); |
| | 12 | 83 | | }); |
| | 6 | 84 | | world.WellFormed(gamma); |
| | 6 | 85 | | return world; |
| | 6 | 86 | | } |
| | | 87 | | /// <inheritdoc/> |
| | 7 | 88 | | public override IEnumerable<StringFormatterToken> Tokens(NanoCSourceFormat args) { |
| | 7 | 89 | | yield return "letu"; |
| | 7 | 90 | | yield return " "; |
| | 7 | 91 | | yield return Name; |
| | 14 | 92 | | if (args.SpaceBeforeBindingAssignment) yield return " "; |
| | 7 | 93 | | yield return "="; |
| | 14 | 94 | | if (args.SpaceAfterBindingAssignment) yield return " "; |
| | 7 | 95 | | yield return "["; |
| | 7 | 96 | | if (args.SpaceBeforeFoldingKeywords) yield return " "; |
| | 7 | 97 | | yield return "unfold"; |
| | 7 | 98 | | yield return " "; |
| | 7 | 99 | | yield return Location; |
| | 7 | 100 | | if (args.SpaceAfterFoldingKeywords) yield return " "; |
| | 7 | 101 | | yield return "]"; |
| | 7 | 102 | | if (args.SpaceBetweenUnfoldAndExpression) yield return " "; |
| | 42 | 103 | | foreach (var tk in Expression.Tokens(args)) yield return tk; |
| | 7 | 104 | | yield return " "; |
| | 7 | 105 | | yield return "in"; |
| | 7 | 106 | | if (args.NewlinesAfterUnfoldExpression <= 0) yield return " "; |
| | 35 | 107 | | else for (int i = 0; i < args.NewlinesAfterUnfoldExpression; i++) yield return new NewLineToken(); |
| | 1596 | 108 | | foreach (var tk in Next.Tokens(args)) yield return tk; |
| | 7 | 109 | | } |
| | | 110 | | /// <inheritdoc/> |
| | 6 | 111 | | public override IEnumerable<StringFormatterToken> Tokens(CSourceFormat args) { |
| | 54 | 112 | | foreach (var tk in new ReferenceType(new Location(Location, true), Index.Zero).Tokens(args)) yield return tk |
| | 6 | 113 | | yield return " "; |
| | 6 | 114 | | yield return Name; |
| | 12 | 115 | | if (args.SpaceBeforeBindingAssignment) yield return " "; |
| | 6 | 116 | | yield return "="; |
| | 12 | 117 | | if (args.SpaceAfterBindingAssignment) yield return " "; |
| | 6 | 118 | | yield return "/* ["; |
| | 6 | 119 | | if (args.SpaceBeforeFoldingKeywords) yield return " "; |
| | 6 | 120 | | yield return "unfold"; |
| | 6 | 121 | | yield return " "; |
| | 6 | 122 | | yield return Location; |
| | 6 | 123 | | if (args.SpaceAfterFoldingKeywords) yield return " "; |
| | 6 | 124 | | yield return "] */ "; |
| | 6 | 125 | | args.PureRequiresReturn = false; |
| | 6 | 126 | | if (args.SpaceBetweenUnfoldAndExpression) yield return " "; |
| | 36 | 127 | | foreach (var tk in Expression.Tokens(args)) yield return tk; |
| | 6 | 128 | | yield return ";"; |
| | 6 | 129 | | if (args.NewlinesAfterUnfoldExpression <= 0) yield return " "; |
| | 30 | 130 | | else for (int i = 0; i < args.NewlinesAfterUnfoldExpression; i++) yield return new NewLineToken(); |
| | 6 | 131 | | args.PureRequiresReturn = false; |
| | 2196 | 132 | | foreach (var tk in Next.Tokens(args)) yield return tk; |
| | 6 | 133 | | } |
| | | 134 | | /// <inheritdoc/> |
| | 6 | 135 | | public override IEnumerable<string> RequiredFunctions() => Next.RequiredFunctions(); |
| | | 136 | | #region Equality checks |
| | | 137 | | /// <inheritdoc/> |
| | 8 | 138 | | public override bool Equals(object? obj) => Equals(obj as UnfoldExpression); |
| | | 139 | | /// <inheritdoc/> |
| | 8 | 140 | | public bool Equals(UnfoldExpression? other) => !(other is null) && Name == other.Name && Location == other.Locat |
| | | 141 | | /// <inheritdoc/> |
| | 0 | 142 | | public override int GetHashCode() => HashCode.Combine(Name, Location, Expression, Next); |
| | | 143 | | /// <inheritdoc/> |
| | 0 | 144 | | public static bool operator ==(UnfoldExpression? left, UnfoldExpression? right) => EqualityComparer<UnfoldExpres |
| | | 145 | | /// <inheritdoc/> |
| | 0 | 146 | | public static bool operator !=(UnfoldExpression? left, UnfoldExpression? right) => !(left == right); |
| | | 147 | | #endregion |
| | | 148 | | } |
| | | 149 | | } |