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);
                }
            }
        }
Beispiel #2
0
        /// <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}).");
                }
            }
        }
Beispiel #4
0
 /// <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);
        }
Beispiel #7
0
        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);
                }
            }
        }
Beispiel #8
0
        /// <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);
        }
Beispiel #9
0
        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.");
                }
            }
        }
Beispiel #10
0
 /// <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
         });
     }