| | | 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 function call expressions. |
| | | 9 | | /// </summary> |
| | | 10 | | public class FunctionCallExpression : Expression, IEquatable<FunctionCallExpression?>, IHeapElement, ISubstitutable< |
| | | 11 | | /// <summary> |
| | | 12 | | /// Creates a new instance of a function call expression that calls the function with the given <paramref name=" |
| | | 13 | | /// </summary> |
| | | 14 | | /// <param name="name">Name of the function to call.</param> |
| | | 15 | | /// <param name="locations">Locations that the function operates on.</param> |
| | | 16 | | /// <param name="parameters">Parameters that are passed to the function.</param> |
| | 218 | 17 | | public FunctionCallExpression(string name, string[] locations, params PureExpression[] parameters) { |
| | 109 | 18 | | Name = name; |
| | 109 | 19 | | Locations = locations; |
| | 109 | 20 | | Parameters = parameters; |
| | 109 | 21 | | } |
| | | 22 | | /// <summary> |
| | | 23 | | /// Name of the function to call. |
| | | 24 | | /// </summary> |
| | 295 | 25 | | public string Name { get; } |
| | | 26 | | /// <summary> |
| | | 27 | | /// Locations that the function operates on. |
| | | 28 | | /// </summary> |
| | 343 | 29 | | public string[] Locations { get; } |
| | | 30 | | /// <summary> |
| | | 31 | | /// Parameters that are passed to the function. |
| | | 32 | | /// </summary> |
| | 326 | 33 | | public PureExpression[] Parameters { get; } |
| | | 34 | | /// <summary> |
| | | 35 | | /// Gets the arity of the function call, being the number of supplied parameters. |
| | | 36 | | /// </summary> |
| | 0 | 37 | | public int Arity => Parameters.Length; |
| | | 38 | | /// <inheritdoc/> |
| | 15 | 39 | | protected override World DoInferWorld(GlobalEnvironment phi, LocalEnvironment gamma, Heap heap) { |
| | 15 | 40 | | VerbConsole.WriteLine(VerbosityLevel.Default, "T-Call"); |
| | 15 | 41 | | if (!phi.TryGetValue(Name, out var rawschema)) |
| | 0 | 42 | | throw new IllFormedException(this, $"No function named {Name} was declared in this environment!"); |
| | 15 | 43 | | var schema = rawschema.Build(phi); |
| | 15 | 44 | | var theta = GetSubstitutions(schema); |
| | 15 | 45 | | CheckParameterSubtyping(gamma, schema, theta); |
| | 15 | 46 | | var usedLocs = new HashSet<string>(Locations); |
| | 47 | 47 | | var hm = heap.Filter(i => usedLocs.Contains(i.Name)); |
| | 47 | 48 | | var hu = heap.Filter(i => !usedLocs.Contains(i.Name)); |
| | | 49 | | // hu.WellFormed(gamma); |
| | 15 | 50 | | hm.WellFormed(gamma); |
| | 15 | 51 | | if (!hm.SubHeap(gamma, schema.Heap.Replace(theta))) |
| | 0 | 52 | | throw new IllFormedException(this, "Heap is not compatible with function schema heap!"); |
| | 15 | 53 | | var hout = hu * schema.World.Heap.Replace(theta); |
| | 15 | 54 | | hout.WellFormed(gamma); |
| | 15 | 55 | | return new World(schema.World.Type.Replace(theta), hout); |
| | 15 | 56 | | } |
| | | 57 | | /// <inheritdoc cref="IHeapElement.GetBindings(GlobalEnvironment, out IEnumerable{KeyValuePair{string, string}}) |
| | 58 | 58 | | public IEnumerable<LocationBinding> GetBindings(GlobalEnvironment phi, out IEnumerable<KeyValuePair<string, stri |
| | 58 | 59 | | VerbConsole.WriteLine(VerbosityLevel.Default, "WF-StructCall"); |
| | 58 | 60 | | if (Locations.Length < 1) |
| | 0 | 61 | | throw new IllFormedException(this, "At least one location must be given. The first location sets the mai |
| | 58 | 62 | | var l = new Location(Locations[0], true); |
| | 58 | 63 | | if (!phi.TryGetStruct(Name, out var def)) |
| | 1 | 64 | | throw new IllFormedException(this, $"No structure named {Name} was declared in this environment!"); |
| | 57 | 65 | | var linklist = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>(l.Name, Name) }; |
| | 57 | 66 | | var bindings = new List<LocationBinding>(); |
| | 57 | 67 | | var theta = GetSubstitutions(def); |
| | 227 | 68 | | foreach (var dep in def.Dependencies.Select(i => i.Replace(theta))) { |
| | 14 | 69 | | bindings.AddRange(dep.GetBindings(phi, out var newLinks)); |
| | 14 | 70 | | linklist.AddRange(newLinks); |
| | 14 | 71 | | } |
| | 128 | 72 | | bindings.Add(new LocationBinding(l, def.Fields.Select(i => i.Binding.Replace(theta).Replace(def.GetSubstitut |
| | 57 | 73 | | links = linklist; |
| | 57 | 74 | | return bindings; |
| | 57 | 75 | | } |
| | | 76 | | |
| | 15 | 77 | | private void CheckParameterSubtyping(LocalEnvironment gamma, FunctionSchema schema, Substitutor theta) { |
| | 147 | 78 | | for (var i = 0; i < Parameters.Length; i++) { |
| | 39 | 79 | | var param = Parameters[i]; |
| | 39 | 80 | | var expParam = schema.Parameters[i]; |
| | 39 | 81 | | param.CheckType(gamma, expParam.Type.Replace(theta)); |
| | 39 | 82 | | } |
| | 15 | 83 | | } |
| | | 84 | | |
| | 72 | 85 | | private Substitutor GetSubstitutions(ICallable callable) => new Substitutor() { Locations = LocationSubstitution |
| | | 86 | | |
| | 72 | 87 | | private IDictionary<string, PureExpression> VariableSubstitution(Base entity, TypeParameter[] schemaparams, Pure |
| | 72 | 88 | | return schemaparams.Length != @params.Length |
| | 72 | 89 | | ? throw new IllFormedException(entity, $"Parameter count mismatch! Expected {schemaparams.Length}, bu |
| | 125 | 90 | | : new Dictionary<string, PureExpression>(schemaparams.Zip(@params, (a, b) => new KeyValuePair<s |
| | 72 | 91 | | } |
| | | 92 | | |
| | 72 | 93 | | private static IDictionary<string, string> LocationSubstitution(Base entity, string[] schemalocations, string[] |
| | 72 | 94 | | return schemalocations.Length != locations.Length |
| | 72 | 95 | | ? throw new IllFormedException(entity, $"Location count mismatch! Expected {schemalocations.Length}, |
| | 250 | 96 | | : new Dictionary<string, string>(schemalocations.Zip(locations, (a, b) => new KeyValuePair<stri |
| | 72 | 97 | | } |
| | | 98 | | /// <inheritdoc/> |
| | 32 | 99 | | public override IEnumerable<StringFormatterToken> Tokens(NanoCSourceFormat args) { |
| | 32 | 100 | | yield return "["; |
| | 252 | 101 | | foreach (var tk in StringFormatterToken.Separated(Locations, args.ParameterListSeparator)) yield return tk; |
| | 32 | 102 | | yield return "]"; |
| | 32 | 103 | | if (args.SpaceBetweenLocationsAndFunctionName) yield return " "; |
| | 32 | 104 | | yield return Name; |
| | 32 | 105 | | if (args.SpaceAfterFunctionName) yield return " "; |
| | 32 | 106 | | yield return "("; |
| | 396 | 107 | | foreach (var tk in StringFormatterToken.Separated(Parameters, args, args.ParameterListSeparator)) yield retu |
| | 32 | 108 | | if (args.SpaceInEmptyArgList && Parameters.Length == 0) yield return " "; |
| | 32 | 109 | | yield return ")"; |
| | 32 | 110 | | } |
| | | 111 | | /// <inheritdoc/> |
| | 21 | 112 | | public override IEnumerable<StringFormatterToken> Tokens(CSourceFormat args) { |
| | 21 | 113 | | var requireReturn = args.PureRequiresReturn; |
| | 25 | 114 | | if (requireReturn) yield return "return "; |
| | 21 | 115 | | yield return Name; |
| | 21 | 116 | | if (args.SpaceAfterFunctionName) yield return " "; |
| | 21 | 117 | | yield return "("; |
| | 21 | 118 | | args.PureRequiresReturn = false; |
| | 396 | 119 | | foreach (var tk in StringFormatterToken.Separated(Parameters, args, args.ParameterListSeparator)) yield retu |
| | 21 | 120 | | if (args.SpaceInEmptyArgList && Parameters.Length == 0) yield return " "; |
| | 21 | 121 | | yield return ")"; |
| | 25 | 122 | | if (requireReturn) yield return ";"; |
| | 21 | 123 | | args.PureRequiresReturn = requireReturn; |
| | 21 | 124 | | } |
| | | 125 | | /// <inheritdoc/> |
| | 9 | 126 | | public override IEnumerable<string> RequiredFunctions() { yield return Name; } |
| | | 127 | | #region Equality checks |
| | | 128 | | /// <inheritdoc/> |
| | 31 | 129 | | public override bool Equals(object? obj) => Equals(obj as FunctionCallExpression); |
| | | 130 | | /// <inheritdoc/> |
| | 33 | 131 | | public bool Equals(FunctionCallExpression? other) => !(other is null) && Name == other.Name && Locations.Sequenc |
| | | 132 | | /// <inheritdoc/> |
| | 28 | 133 | | public override int GetHashCode() { |
| | 28 | 134 | | var hash = new HashCode(); |
| | 28 | 135 | | hash.Add(Name); |
| | 204 | 136 | | foreach (var loc in Locations) hash.Add(loc); |
| | 120 | 137 | | foreach (var param in Parameters) hash.Add(param); |
| | 28 | 138 | | return hash.ToHashCode(); |
| | 28 | 139 | | } |
| | | 140 | | /// <inheritdoc/> |
| | 14 | 141 | | public FunctionCallExpression Replace(Substitutor sub) => new FunctionCallExpression(Name, |
| | 14 | 142 | | Locations.Select(i => sub.Locations.TryGetValue(i, out var subs) ? subs : i).ToArray(), |
| | 14 | 143 | | Parameters.Select(i => i.Replace(sub)).ToArray()); |
| | | 144 | | /// <inheritdoc/> |
| | 0 | 145 | | public static bool operator ==(FunctionCallExpression? left, FunctionCallExpression? right) => EqualityComparer< |
| | | 146 | | /// <inheritdoc/> |
| | 0 | 147 | | public static bool operator !=(FunctionCallExpression? left, FunctionCallExpression? right) => !(left == right); |
| | | 148 | | #endregion |
| | | 149 | | } |
| | | 150 | | } |