AspectedRouting/AspectedRouting/Language/Funcs.cs

172 lines
No EOL
5.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using AspectedRouting.Language.Expression;
using AspectedRouting.Language.Functions;
using AspectedRouting.Language.Typ;
using Type = AspectedRouting.Language.Typ.Type;
// ReSharper disable UnusedMember.Global
namespace AspectedRouting.Language
{
public static class Funcs
{
public static readonly Dictionary<string, Function> Builtins = new Dictionary<string, Function>();
public static IEnumerable<string> BuiltinNames = Builtins.Keys;
public static readonly Function Eq = new Eq();
public static readonly Function NotEq = new NotEq();
public static readonly Function Inv = new Inv();
public static readonly Function IsNull = new IsNull();
public static readonly Function Default = new Default();
public static readonly Function Parse = new Parse();
public static readonly Function ToStringFunc = new ToString();
public static readonly Function Concat = new Concat();
public static readonly Function ContainedIn = new ContainedIn();
public static readonly Function Min = new Min();
public static readonly Function Max = new Max();
public static readonly Function Sum = new Sum();
public static readonly Function Multiply = new Multiply();
public static readonly Function AtLeast = new AtLeast();
public static readonly Function FirstOf = new FirstMatchOf();
public static readonly Function MustMatch = new MustMatch();
public static readonly Function MemberOf = new MemberOf();
public static readonly Function If = new If();
public static readonly Function IfDotted = new IfDotted();
public static readonly Function Id = new Id();
public static readonly Function Const = new Const();
public static readonly Function ConstRight = new ConstRight();
public static readonly Function Dot = new Dot();
public static readonly Function ListDot = new ListDot();
public static readonly Function EitherFunc = new EitherFunc();
public static readonly Function StringStringToTags = new StringStringToTagsFunction();
public static readonly Function Head = new HeadFunction();
public static void AddBuiltin(Function f, string name = null)
{
Builtins.Add(name ?? f.Name, f);
}
public static IExpression Either(IExpression a, IExpression b, IExpression arg)
{
return EitherFunc.Apply(a, b, arg);
}
public static Function BuiltinByName(string funcName)
{
if (funcName.StartsWith("$"))
{
funcName = funcName.Substring(1);
}
if (Builtins.TryGetValue(funcName, out var f)) return f;
return null;
}
public static IExpression Finalize(this IExpression e)
{
if (e == null)
{
return null;
}
if (e.Types.Count() == 0)
{
throw new Exception("Expression has no valid types:\n" + e);
}
var eSmallest = e.SpecializeToSmallestType();
if (eSmallest == null || eSmallest.Types.Count() == 0)
{
throw new Exception("Could not specialize " + e);
}
// TODO FIX THIS so that it works
// An argument 'optimizes' it's types from 'string -> bool' to 'string -> string'
var eOpt = eSmallest.Optimize(out _);
if (eOpt == null || eOpt.Types.Count() == 0)
{
throw new Exception("Could not optimize " + eSmallest);
}
eOpt.SanityCheck();
return eOpt;
}
public static IExpression SpecializeToSmallestType(this IExpression e)
{
if (e == null)
{
throw new Exception("Cannot specialize null to a smallest type");
}
if (e.Types.Count() == 1)
{
return e;
}
Type smallest = null;
foreach (var t in e.Types)
{
if (smallest == null)
{
smallest = t;
continue;
}
var smallestIsSuperset = smallest.IsSuperSet(t);
if (!t.IsSuperSet(smallest) && !smallestIsSuperset)
{
// Neither one is smaller then the other, we can not compare them
return e;
}
if (smallestIsSuperset)
{
smallest = t;
}
}
return e.Specialize(new[] {smallest});
}
public static IExpression Apply(this IExpression function, IEnumerable<IExpression> args)
{
return function.Apply(args.ToList());
}
public static IExpression Apply(this IExpression function, params IExpression[] args)
{
return function.Apply(args.ToList());
}
public static IExpression Apply(this IExpression function, List<IExpression> args)
{
if (args.Count == 0)
{
return function;
}
if (args.Count == 1)
{
return new Apply(function, args[0]);
}
var lastArg = args[args.Count - 1];
var firstArgs = args.GetRange(0, args.Count - 1);
var applied = Apply(function, firstArgs);
return new Apply(applied, lastArg);
}
}
}