public override async IAsyncEnumerable <Path> ComputeSelect(EvaluationContext ctx) { _listCandidate ??= TemplexBase.Parse(ListExpression); if (_listCandidate != null) { // Expression select var select = _listCandidate.ComputeSelect(ctx); await foreach (var atom in select) { yield return(atom); } // Expression paths var paths = _listCandidate.ComputePaths(ctx); await foreach (var path in paths) { yield return(path.Append("Id")); } // Inner template select var scopedCtx = ctx.Clone(); scopedCtx.SetLocalVariable(IteratorVariableName, new EvaluationVariable( eval: TemplateUtil.VariableThatThrows(IteratorVariableName), selectResolver: () => select, pathsResolver: () => paths )); await foreach (var atom in Inner.ComputeSelect(scopedCtx)) { yield return(atom); } } }
/// <summary> /// Creates a new <see cref="TemplexBinaryOperator"/> based on the operator. /// </summary> public static TemplexBinaryOperator Make(string op, TemplexBase left, TemplexBase right) { TemplexBinaryOperator result = op switch { // Arithmetic "+" => new Addition(), "-" => new Subtraction(), "*" => new Multiplication(), "/" => new Division(), "%" => new Modulo(), // Logical "&&" => new Conjunction(), "||" => new Disjunction(), // Comparison "!=" => new NotEqual(), "<>" => new NotEqual(), "<=" => new LessThanOrEqual(), ">=" => new GreaterThanOrEqual(), "<" => new LessThan(), ">" => new GreaterThan(), "=" => new AreEqual(), // Error _ => throw new TemplateException($"Unkown binary operator {op}.") }; result.Left = left; result.Right = right; result._op = op; return(result); }
public override async Task GenerateOutputs(EvaluationContext ctx) { _listCandidate ??= TemplexBase.Parse(ListExpression); if (_listCandidate != null) { var listObj = (await _listCandidate.Evaluate(ctx)) ?? new List <object>(); if (listObj is IList list) { foreach (var listItem in list) { // Initialize new evaluation context with the new variable in it var scopedCtx = ctx.Clone(); scopedCtx.SetLocalVariable(IteratorVariableName, new EvaluationVariable( evalAsync: () => Task.FromResult(listItem), selectResolver: () => AsyncUtil.Empty <Path>(), // It doesn't matter when generating output pathsResolver: () => AsyncUtil.Empty <Path>() // It doesn't matter when generating output )); // Run the template again on that context await Inner.GenerateOutputs(scopedCtx); } } else { throw new TemplateException($"Expression does not evaluate to a list ({_listCandidate})."); } } }
/// <summary> /// Creates a new <see cref="TemplexIndexer"/>. /// </summary> public static TemplexIndexer Make(TemplexBase listCandidate, int index) { return(new TemplexIndexer { ListCandidate = listCandidate, Index = index }); }
/// <summary> /// Creates a new <see cref="TemplexPropertyAccess"/>. /// </summary> public static TemplexPropertyAccess Make(TemplexBase entityCandidate, string propName) { return(new TemplexPropertyAccess { EntityCandidate = entityCandidate, PropertyName = propName }); }
/// <summary> /// Clones the <see cref="EvaluationContext"/> and returns a new one that contains the new variable. /// </summary> private EvaluationContext GetScopeLocalContext(EvaluationContext ctx) { _varExpression ??= TemplexBase.Parse(VariableExpression); var variable = new EvaluationVariable( evalAsync: () => _varExpression.Evaluate(ctx), selectResolver: () => _varExpression.ComputeSelect(ctx), pathsResolver: () => _varExpression.ComputePaths(ctx)); var ctxClone = ctx.Clone(); ctxClone.SetLocalVariable(VariableName, variable); return(ctxClone); }
public override async IAsyncEnumerable <Path> ComputeSelect(EvaluationContext ctx) { _conditionCandidate ??= TemplexBase.Parse(ConditionExpression); if (_conditionCandidate != null && Inner != null) { await foreach (var select in _conditionCandidate.ComputeSelect(ctx)) { yield return(select); } await foreach (var select in Inner.ComputeSelect(ctx)) { yield return(select); } } }
/// <summary> /// Creates a new <see cref="TemplexUnaryOperator"/> based on the operator. /// </summary> public static TemplexUnaryOperator Make(string op, TemplexBase operand) { if (operand is null) { throw new ArgumentNullException(nameof(operand)); } TemplexUnaryOperator result = op switch { "!" => new Negation(), "-" => new Negative(), "+" => new Positive(), _ => throw new TemplateException($"Unkown unary operator {op}.") }; result.Operand = operand; result._op = op; return(result); }
public override async Task GenerateOutputs(EvaluationContext ctx) { _conditionCandidate ??= TemplexBase.Parse(ConditionExpression); if (_conditionCandidate != null && Inner != null) { var conditionObj = (await _conditionCandidate.Evaluate(ctx)) ?? false; if (conditionObj is bool condition) { if (condition) { await Inner.GenerateOutputs(ctx); } } else { throw new TemplateException($"If expression could not be applied. Expression ({_conditionCandidate}) does not evaluate to a true or false."); } } }
/// <summary> /// Divides left by right after converting both to their common numeric type. /// Throws a meaningful exception if right is equal to 0. /// </summary> /// <exception cref="TemplateException">If <paramref name="right"/> is equal to zero.</exception> public static object Divide(object left, object right, Type commonType, TemplexBase rightExp) { try { return(commonType.Name switch { _sbyte => Convert.ToSByte(left) / Convert.ToSByte(right), _byte => Convert.ToByte(left) / Convert.ToByte(right), _short => Convert.ToInt16(left) / Convert.ToInt16(right), _ushort => Convert.ToUInt16(left) / Convert.ToUInt16(right), _int => Convert.ToInt32(left) / Convert.ToInt32(right), _uint => Convert.ToUInt32(left) / Convert.ToUInt32(right), _long => Convert.ToInt64(left) / Convert.ToInt64(right), _ulong => Convert.ToUInt64(left) / Convert.ToUInt64(right), _float => Convert.ToSingle(left) / Convert.ToSingle(right), _double => Convert.ToDouble(left) / Convert.ToDouble(right), _decimal => Convert.ToDecimal(left) / Convert.ToDecimal(right), _ => throw new InvalidOperationException($"Unknown numeric type {commonType.Name}"), // Developer mistake }); }