| | | 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 definitions. |
| | | 9 | | /// </summary> |
| | | 10 | | public class StructDefinition : Base, IEquatable<StructDefinition?>, ICallable { |
| | | 11 | | /// <summary> |
| | | 12 | | /// Creates a new instance of a structure definition from a list of structure fields. |
| | | 13 | | /// </summary> |
| | | 14 | | /// <param name="locations">Additional locations that the structure operates on.</param> |
| | | 15 | | /// <param name="args">Parameters that the structure invariant depends on.</param> |
| | | 16 | | /// <param name="dependencies">Calls to other structs that the structure depends on.</param> |
| | | 17 | | /// <param name="fields">Fields of the structure.</param> |
| | 52 | 18 | | public StructDefinition(string[] locations, TypeParameter[] args, FunctionCallExpression[] dependencies, StructF |
| | 26 | 19 | | Locations = locations; |
| | 26 | 20 | | Parameters = args; |
| | 26 | 21 | | Dependencies = dependencies; |
| | 26 | 22 | | Fields = fields; |
| | 26 | 23 | | } |
| | | 24 | | /// <summary> |
| | | 25 | | /// Additional locations that the struct operates on. |
| | | 26 | | /// </summary> |
| | 69 | 27 | | public string[] Locations { get; } |
| | | 28 | | /// <summary> |
| | | 29 | | /// Parameters that the structure invariant depends on. |
| | | 30 | | /// </summary> |
| | 88 | 31 | | public TypeParameter[] Parameters { get; } |
| | | 32 | | /// <summary> |
| | | 33 | | /// List of structs that the struct depends on. |
| | | 34 | | /// </summary> |
| | 78 | 35 | | public FunctionCallExpression[] Dependencies { get; } |
| | | 36 | | /// <summary> |
| | | 37 | | /// Member fields of the structure. |
| | | 38 | | /// </summary> |
| | 168 | 39 | | public StructField[] Fields { get; } |
| | | 40 | | /// <summary> |
| | | 41 | | /// Checks if the structure definition is well-formed and raises an exception if it is ill-formed. |
| | | 42 | | /// </summary> |
| | | 43 | | /// <param name="phi">Environemt to check the structure definition with.</param> |
| | | 44 | | /// <exception cref="IllFormedException">structure definition is ill-formed.</exception> |
| | 10 | 45 | | public void WellFormed(GlobalEnvironment phi) { |
| | 10 | 46 | | var gamma = new LocalEnvironment(); |
| | 10 | 47 | | var emptyHeap = new Heap(); |
| | 44 | 48 | | foreach (var param in Parameters) { |
| | | 49 | | // check with empty heap because structures cannot depend on heaps that are external |
| | 5 | 50 | | param.Type.WellFormed(gamma, emptyHeap); |
| | 5 | 51 | | if (!gamma.TryAdd(param.Name, param.Type)) |
| | 1 | 52 | | throw new IllFormedException(param, $"Structure parameters must have distinct names: {param.Name} is |
| | 4 | 53 | | } |
| | 24 | 54 | | var collision = Fields.Select(i => i.Name).Intersect(Parameters.Select(i => i.Name)).ToList(); |
| | 9 | 55 | | if (collision.Any()) |
| | 1 | 56 | | throw new IllFormedException(this, $"Cannot declare fields with name(s) {string.Join(", ", collision)}, |
| | 30 | 57 | | var fieldcollision = Fields.GroupBy(i => i.Name).Where(g => g.Count() > 1).Select(g => g.Key).ToList(); |
| | 8 | 58 | | if (fieldcollision.Any()) |
| | 1 | 59 | | throw new IllFormedException(this, $"Cannot declare fields with name(s) {string.Join(", ", fieldcollisio |
| | | 60 | | |
| | 32 | 61 | | foreach (var dep in Dependencies) dep.GetBindings(phi, out _); |
| | 6 | 62 | | } |
| | | 63 | | /// <summary> |
| | | 64 | | /// Gets a substitutor object that replaces variables that refer to struct members in the heap with their block |
| | | 65 | | /// </summary> |
| | | 66 | | /// <returns>Heap substitutor.</returns> |
| | 71 | 67 | | public Substitutor GetSubstitutor() { |
| | 71 | 68 | | var theta = new Substitutor(); |
| | 510 | 69 | | foreach (var field in Fields) { |
| | 99 | 70 | | if (theta.Variables.ContainsKey(field.Name)) |
| | 0 | 71 | | throw new IllFormedException(field, $"Cannot use field name {field.Name} twice in one structure!"); |
| | 99 | 72 | | else if (field.Binding.Index is SingletonIndex i) |
| | 59 | 73 | | theta.Variables[field.Name] = new VariableExpression(Heap.OffsetVar(i.Offset)); |
| | 99 | 74 | | } |
| | 71 | 75 | | return theta; |
| | 71 | 76 | | } |
| | | 77 | | |
| | | 78 | | /// <inheritdoc/> |
| | 4 | 79 | | public override IEnumerable<StringFormatterToken> Tokens(NanoCSourceFormat args) { |
| | | 80 | | // LBC (fields += structField)+ RBC COLON LBA locations = identifierList RBA |
| | 4 | 81 | | yield return "struct"; |
| | 4 | 82 | | if (args.SpaceAfterFunKeyword) yield return " "; |
| | 4 | 83 | | yield return "("; |
| | 150 | 84 | | foreach (var tk in StringFormatterToken.Separated(Parameters, args, args.ParameterListSeparator)) yield retu |
| | 4 | 85 | | if (args.SpaceInEmptyArgList && Parameters.Length == 0) yield return " "; |
| | 4 | 86 | | yield return ")"; |
| | 6 | 87 | | if (Dependencies.Length > 0) { |
| | 2 | 88 | | yield return " "; |
| | 2 | 89 | | yield return ":"; |
| | 2 | 90 | | yield return " "; |
| | 42 | 91 | | foreach (var tk in StringFormatterToken.Separated(Dependencies, args, args.ParameterListSeparator)) yiel |
| | 2 | 92 | | } |
| | 4 | 93 | | if (args.NewlineBeforeFunctionBody) { |
| | 0 | 94 | | yield return new NewLineToken(); |
| | 0 | 95 | | if (args.IndentFunctionBodyOpenBrace) yield return new string(' ', args.FunctionBodyIndent); |
| | 8 | 96 | | } else if (args.SpaceBeforeFunctionBody) yield return " "; |
| | 4 | 97 | | yield return "{"; |
| | 526 | 98 | | foreach (var tk in StringFormatterToken.Indented(args.FunctionBodyIndent, () => Fields.SelectMany(i => i.Tok |
| | 8 | 99 | | if (args.NewlineBeforeFunctionBodyCloseBrace) { |
| | 4 | 100 | | yield return new NewLineToken(); |
| | 4 | 101 | | if (args.IndentFunctionBodyCloseBrace) yield return new string(' ', args.FunctionBodyIndent); |
| | 4 | 102 | | } else if (args.SpaceBeforeFunctionBodyCloseBrace) yield return " "; |
| | 4 | 103 | | yield return "}"; |
| | 4 | 104 | | if (args.NewlineBeforeFunctionSchemaColon) { |
| | 0 | 105 | | yield return new NewLineToken(); |
| | 0 | 106 | | if (args.IndentFunctionSchemaColon) yield return new string(' ', args.FunctionSchemaIndent); |
| | 8 | 107 | | } else if (args.SpaceBeforeFunctionSchemaColon) yield return " "; |
| | 4 | 108 | | yield return ":"; |
| | 4 | 109 | | if (args.NewlineAfterFunctionSchemaColon) { |
| | 0 | 110 | | yield return new NewLineToken(); |
| | 0 | 111 | | if (args.IndentFunctionSchema) yield return new string(' ', args.FunctionSchemaIndent); |
| | 8 | 112 | | } else if (args.SpaceAfterFunctionSchemaColon) yield return " "; |
| | 4 | 113 | | yield return "["; |
| | 36 | 114 | | foreach (var tk in StringFormatterToken.Separated(Locations, args.ParameterListSeparator)) yield return tk; |
| | 4 | 115 | | yield return "]"; |
| | 4 | 116 | | } |
| | | 117 | | #region Equality checks |
| | | 118 | | /// <inheritdoc/> |
| | 0 | 119 | | public override bool Equals(object? obj) => Equals(obj as StructDefinition); |
| | | 120 | | /// <inheritdoc/> |
| | 4 | 121 | | public bool Equals(StructDefinition? other) => other != null && Locations.SequenceEqual(other.Locations) && Para |
| | | 122 | | /// <inheritdoc/> |
| | 0 | 123 | | public override int GetHashCode() { |
| | 0 | 124 | | var hash = new HashCode(); |
| | 0 | 125 | | foreach (var i in Locations) hash.Add(i); |
| | 0 | 126 | | foreach (var i in Parameters) hash.Add(i); |
| | 0 | 127 | | foreach (var i in Dependencies) hash.Add(i); |
| | 0 | 128 | | foreach (var i in Fields) hash.Add(i); |
| | 0 | 129 | | return hash.ToHashCode(); |
| | 0 | 130 | | } |
| | | 131 | | /// <inheritdoc/> |
| | 4 | 132 | | public static bool operator ==(StructDefinition? left, StructDefinition? right) => EqualityComparer<StructDefini |
| | | 133 | | /// <inheritdoc/> |
| | 4 | 134 | | public static bool operator !=(StructDefinition? left, StructDefinition? right) => !(left == right); |
| | | 135 | | #endregion |
| | | 136 | | } |
| | | 137 | | } |