public static SpecificationResult ParseSpecification(SymbolTable symbolTable, SpecificationContext context, Expression body) { if (body is MethodCallExpression methodCall) { var method = methodCall.Method; if (method.DeclaringType == typeof(FactRepository) && method.Name == nameof(FactRepository.OfType)) { var type = method.GetGenericArguments()[0]; var factType = type.FactTypeName(); var set = FactsOfType(factType, type); var sourceSymbolValue = new SymbolValueSetDefinition(set); var source = SpecificationResult.FromValue(sourceSymbolValue) .WithTarget(set); if (methodCall.Arguments.Count == 0) { return(source); } else { return(ParseWhere(source, symbolTable, context, methodCall.Arguments[0])); } } else if (method.DeclaringType == typeof(Queryable)) { if (method.Name == nameof(Queryable.Where) && methodCall.Arguments.Count == 2) { var source = ParseSpecification(symbolTable, context, methodCall.Arguments[0]); return(ParseWhere(source, symbolTable, context, methodCall.Arguments[1])); } else if (method.Name == nameof(Queryable.Select) && methodCall.Arguments.Count == 2) { var source = ParseSpecification(symbolTable, context, methodCall.Arguments[0]); return(ParseSelect(source, symbolTable, context, methodCall.Arguments[1])); } else if (method.Name == nameof(Queryable.SelectMany) && methodCall.Arguments.Count == 3) { var source = ParseSpecification(symbolTable, context, methodCall.Arguments[0]); return(ParseSelectMany(source, symbolTable, context, methodCall.Arguments[1], methodCall.Arguments[2])); } else { throw new SpecificationException($"You cannot use {method.Name} in a Jinaga specification."); } } else { throw new SpecificationException($"You cannot use {method.DeclaringType.Name}.{method.Name} in a Jinaga specification."); } } else { throw new SpecificationException($"You cannot use the syntax {body} in a Jinaga specification."); } }
private static SpecificationResult ParseWhere(SpecificationResult source, SymbolTable symbolTable, SpecificationContext context, Expression predicate) { if (predicate is UnaryExpression { Operand : LambdaExpression lambda })
public static (SymbolValue symbolValue, string tag) ParseValue(SymbolTable symbolTable, SpecificationContext context, Expression expression) { if (expression is NewExpression newBody) { var names = newBody.Members != null ? newBody.Members.Select(member => member.Name) : newBody.Constructor.GetParameters().Select(parameter => parameter.Name); var values = newBody.Arguments .Select(arg => ParseValue(symbolTable, context, arg).symbolValue); var fields = names.Zip(values, (name, value) => KeyValuePair.Create(name, value)) .ToImmutableDictionary(); return(new SymbolValueComposite(fields), ""); } else if (expression is MemberInitExpression memberInit) { var fields = memberInit.Bindings .Select(binding => ParseMemberBinding(symbolTable, context, binding)) .ToImmutableDictionary(); return(new SymbolValueComposite(fields), ""); } else if (expression is MemberExpression { Member : PropertyInfo propertyInfo } memberExpression) { switch (ParseValue(symbolTable, context, memberExpression.Expression)) { case (SymbolValueComposite compositeValue, _) : return(compositeValue.GetField(propertyInfo.Name), propertyInfo.Name); case (SymbolValueSetDefinition setValue, string tag): var role = propertyInfo.Name; var predecessorType = propertyInfo.PropertyType.FactTypeName(); var setDefinition = setValue.SetDefinition.AppendChain(role, predecessorType, propertyInfo.PropertyType); return(new SymbolValueSetDefinition(setDefinition), tag); default: throw new NotImplementedException(); } }