using Expressive; using Expressive.Expressions; using Expressive.Functions; using InABox.Clients; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace InABox.Core { using FncType = Func, object?>; public interface IExpressionModel { } public interface IExpressionModel : IExpressionModel { } public class CoreExpression { private Expression Expression; public IReadOnlyCollection ReferencedVariables => Expression.ReferencedVariables; protected virtual Type? ReturnType { get; } public CoreExpression(string expressionString) { Expression = new Expression(expressionString); foreach (var (name, function) in _functions) { Expression.RegisterFunction(name, function); } } public object? Evaluate(Dictionary? variables) { var result = Expression.Evaluate(variables); if(ReturnType != null) { return CoreUtils.ChangeType(result, ReturnType); } return result; } #region Static private static List> _functions = new List>(); static CoreExpression() { RegisterFunction("Format", (p, v) => { if (!(p[0].Evaluate(v) is string format)) throw new Exception("No format string given for Format()"); return string.Format(format, p.Skip(1).Select(x => x.Evaluate(v)).ToArray()); }); RegisterFunction("Client_LoadDocument", Fnc_LoadDocument); } private static object? Fnc_LoadDocument(IExpression[] p, IDictionary v) { var id = p[0].Evaluate(v); if (id is null) return null; if (!(id is Guid docID)) return null; return new Client() .Query( new Filter(x => x.ID).IsEqualTo(docID), new Columns(x => x.Data)) .Rows.FirstOrDefault() ?.Get(x => x.Data); } public static void RegisterFunction(string name, FncType function) => _functions.Add(new Tuple(name, function)); #endregion } public class CoreExpression : CoreExpression where TModel : IExpressionModel { protected override Type? ReturnType => typeof(TReturn); public CoreExpression(string expressionString): base(expressionString) { } public new TReturn Evaluate(Dictionary? variables) { var result = base.Evaluate(variables); if(result is TReturn ret) { return ret; } return default(TReturn); } } }