| | | 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 definitions. |
| | | 9 | | /// </summary> |
| | | 10 | | public class FunctionDefinition : Base, IEquatable<FunctionDefinition?> { |
| | | 11 | | /// <summary> |
| | | 12 | | /// Creates a new instance of a function definition with a specific <paramref name="schema"/> and a <paramref na |
| | | 13 | | /// </summary> |
| | | 14 | | /// <param name="body">Expression body of the function.</param> |
| | | 15 | | /// <param name="schema">Schema of the function.</param> |
| | 100 | 16 | | public FunctionDefinition(Expression body, RawFunctionSchema schema) { |
| | 50 | 17 | | Body = body; |
| | 50 | 18 | | Schema = schema; |
| | 50 | 19 | | } |
| | | 20 | | /// <summary> |
| | | 21 | | /// Expression that the function evaluates to. |
| | | 22 | | /// </summary> |
| | 111 | 23 | | public Expression Body { get; } |
| | | 24 | | /// <summary> |
| | | 25 | | /// Schema of the function. |
| | | 26 | | /// </summary> |
| | 217 | 27 | | public RawFunctionSchema Schema { get; } |
| | | 28 | | /// <summary> |
| | | 29 | | /// Checks if the function definition is well-formed and raises an exception if it is ill-formed. |
| | | 30 | | /// </summary> |
| | | 31 | | /// <param name="phi">Environemt to check the function definition with.</param> |
| | | 32 | | /// <param name="name">Name of the function to be defined.</param> |
| | | 33 | | /// <exception cref="IllFormedException">Function definition is ill-formed.</exception> |
| | 21 | 34 | | public void WellFormed(GlobalEnvironment phi, string name) { |
| | 21 | 35 | | if (!Schema.HasWorld && Body.RequiredFunctions().Contains(name)) |
| | 0 | 36 | | throw new IllFormedException(this, $"Cannot infer worlds of recursive function {name}. Please specify th |
| | 21 | 37 | | var schema = Schema.Build(phi, out var links); |
| | | 38 | | |
| | 21 | 39 | | schema.WellFormed(); |
| | 21 | 40 | | var gamma = schema.GetEnvironment(); |
| | 21 | 41 | | gamma.AddStructLocs(links); |
| | | 42 | | World inferredWorld; |
| | | 43 | | //try { |
| | 21 | 44 | | inferredWorld = Body.InferWorld(phi, gamma, schema.Heap); |
| | | 45 | | //} catch (IllFormedException e) { |
| | | 46 | | // throw new IllFormedException(this, $"In function {name}: body is ill-formed!", e); |
| | | 47 | | //} |
| | 21 | 48 | | var world = Schema.FixWorld(inferredWorld).Build(phi); |
| | | 49 | | |
| | 21 | 50 | | var domain = inferredWorld.Heap.Domain().Concat(schema.Heap.Domain()).Concat(world.Heap.Domain()).ToHashSet( |
| | 48 | 51 | | var h = inferredWorld.Heap.Filter(l => domain.Contains(l)); |
| | 21 | 52 | | if (h != world.Heap) |
| | 0 | 53 | | throw new IllFormedException(world, "Expression heap does not match schema!"); |
| | 48 | 54 | | var h0 = inferredWorld.Heap.Filter(l => !domain.Contains(l)); |
| | | 55 | | //world.WellFormed(gamma); |
| | 21 | 56 | | h0.WellFormed(gamma); |
| | 21 | 57 | | } |
| | | 58 | | /// <inheritdoc/> |
| | 20 | 59 | | public override IEnumerable<StringFormatterToken> Tokens(NanoCSourceFormat args) { |
| | 20 | 60 | | yield return "fun"; |
| | 20 | 61 | | if (args.SpaceAfterFunKeyword) yield return " "; |
| | 20 | 62 | | yield return "("; |
| | 20 | 63 | | if (args.FunctionParamNamesInDefinition) |
| | 203 | 64 | | foreach (var tk in StringFormatterToken.Separated(Schema.Parameters.Select(i => i.Name), args.ParameterL |
| | 20 | 65 | | if (args.SpaceInEmptyArgList && Schema.Parameters.Length == 0) yield return " "; |
| | 20 | 66 | | yield return ")"; |
| | 20 | 67 | | if (args.NewlineBeforeFunctionBody) { |
| | 0 | 68 | | yield return new NewLineToken(); |
| | 0 | 69 | | if (args.IndentFunctionBodyOpenBrace) yield return new string(' ', args.FunctionBodyIndent); |
| | 40 | 70 | | } else if (args.SpaceBeforeFunctionBody) yield return " "; |
| | 20 | 71 | | yield return "{"; |
| | 3656 | 72 | | foreach (var tk in StringFormatterToken.Indented(args.FunctionBodyIndent, () => Body.Tokens(args).Prepend(ne |
| | 40 | 73 | | if (args.NewlineBeforeFunctionBodyCloseBrace) { |
| | 20 | 74 | | yield return new NewLineToken(); |
| | 20 | 75 | | if (args.IndentFunctionBodyCloseBrace) yield return new string(' ', args.FunctionBodyIndent); |
| | 20 | 76 | | } else if (args.SpaceBeforeFunctionBodyCloseBrace) yield return " "; |
| | 20 | 77 | | yield return "}"; |
| | 20 | 78 | | if (args.NewlineBeforeFunctionSchemaColon) { |
| | 0 | 79 | | yield return new NewLineToken(); |
| | 0 | 80 | | if (args.IndentFunctionSchemaColon) yield return new string(' ', args.FunctionSchemaIndent); |
| | 40 | 81 | | } else if (args.SpaceBeforeFunctionSchemaColon) yield return " "; |
| | 20 | 82 | | yield return ":"; |
| | 20 | 83 | | if (args.NewlineAfterFunctionSchemaColon) { |
| | 0 | 84 | | yield return new NewLineToken(); |
| | 0 | 85 | | if (args.IndentFunctionSchema) yield return new string(' ', args.FunctionSchemaIndent); |
| | 40 | 86 | | } else if (args.SpaceAfterFunctionSchemaColon) yield return " "; |
| | 6695 | 87 | | foreach (var tk in StringFormatterToken.Indented(args.FunctionSchemaIndent, () => Schema.Tokens(args))) yiel |
| | 20 | 88 | | } |
| | | 89 | | /// <inheritdoc/> |
| | 25 | 90 | | public override IEnumerable<StringFormatterToken> Tokens(CSourceFormat args) { |
| | 25 | 91 | | yield return "("; |
| | 363 | 92 | | foreach (var tk in StringFormatterToken.Separated(Schema.Parameters, args, ", ")) yield return tk; |
| | 25 | 93 | | yield return ")"; |
| | 25 | 94 | | yield return " "; |
| | 25 | 95 | | yield return "{"; |
| | 25 | 96 | | args.PureRequiresReturn = true; |
| | 4741 | 97 | | foreach (var tk in StringFormatterToken.Indented(4, () => Body.Tokens(args).Prepend(new NewLineToken()))) yi |
| | 25 | 98 | | yield return new NewLineToken(); |
| | 25 | 99 | | yield return "}"; |
| | 25 | 100 | | } |
| | | 101 | | #region Equality checks |
| | | 102 | | /// <inheritdoc/> |
| | 0 | 103 | | public override bool Equals(object? obj) => Equals(obj as FunctionDefinition); |
| | | 104 | | /// <inheritdoc/> |
| | 21 | 105 | | public bool Equals(FunctionDefinition? other) => !(other is null) && EqualityComparer<Expression>.Default.Equals |
| | | 106 | | /// <inheritdoc/> |
| | 0 | 107 | | public override int GetHashCode() => HashCode.Combine(Body, Schema); |
| | | 108 | | /// <inheritdoc/> |
| | 0 | 109 | | public static bool operator ==(FunctionDefinition? left, FunctionDefinition? right) => EqualityComparer<Function |
| | | 110 | | /// <inheritdoc/> |
| | 0 | 111 | | public static bool operator !=(FunctionDefinition? left, FunctionDefinition? right) => !(left == right); |
| | | 112 | | #endregion |
| | | 113 | | } |
| | | 114 | | } |