Example #1
0
 /// <summary>
 /// Compile the single item if it is possible to compile.
 /// It concerns those <see cref="ExpressionPart"/>s items which returns expression in <seealso cref="ExpressionPart.GetExpression(EvaluationContext, string, ref ExpressionData)"/>.
 /// </summary>
 /// <param name="context">The context of evaluation.</param>
 /// <param name="expressionTree">The expression tree.</param>
 protected virtual bool CompileSingleItem(EvaluationContext context, IList <ProcessedItem> expressionTree)
 {
     // compile single item
     return(ReverseLoop(expressionTree, i =>
     {
         ProcessedItem item = expressionTree[i];
         if (item.ItemType != null)
         {
             IExpressionPart obj = GetObject(item.ItemType);
             ExpressionData data = new ExpressionData();
             Expression compiled = obj.GetExpression(context, item.Content, ref data);
             if (compiled != null)
             {
                 ProcessedItem newItem = ProcessedItem.Create(compiled);
                 expressionTree.RemoveAt(i);
                 expressionTree.Insert(i, newItem);
                 return true;
             }
             else if (data.TypeToCast != null)
             {
                 ProcessedItem newItem = ProcessedItem.CreateCast(data.TypeToCast);
                 expressionTree.RemoveAt(i);
                 expressionTree.Insert(i, newItem);
                 return true;
             }
         }
         return false;
     }));
 }
Example #2
0
        /// <summary>
        /// Compile the binary operators on the same level of priority. It uses the <seealso cref="EvaluationContext.Priority"/> setting.
        /// </summary>
        /// <param name="context">The context of evaluation.</param>
        /// <param name="expressionTree">The expression tree.</param>
        /// <param name="priority">The priority level.</param>
        /// <returns>True if it changed the expression tree.</returns>
        protected virtual bool CompileBinaryOperatorsByPriority(EvaluationContext context, IList <ProcessedItem> expressionTree, int priority) =>
        ReverseLoop(expressionTree, i =>
        {
            ProcessedItem item = expressionTree[i];
            if (i > 0 && expressionTree.Count > i + 1 &&
                item.ItemType == typeof(EBinaryOperator) &&
                expressionTree[i - 1].Expression != null &&
                expressionTree[i + 1].Expression != null &&
                (context.Priority[priority].Contains(item.Content, StringComparer.OrdinalIgnoreCase)))
            {
                Expression expr1 = expressionTree[i - 1].Expression;
                Expression expr2 = expressionTree[i + 1].Expression;

                Type resultType = context.ConsolidateBinaryTypes(context, expr1.Type, expr2.Type);

                if ((expr1.Type == typeof(string) || expr1.Type == typeof(char)) && item.Content == "+")
                {
                    resultType = typeof(string);
                }
                if (expr1.Type != resultType)
                {
                    expr1 = ConvertExpression(expr1, resultType);
                }
                if (expr2.Type != resultType)
                {
                    expr2 = ConvertExpression(expr2, resultType);
                }
                Expression expr;
                if ((expr1.Type == typeof(string) || expr2.Type == typeof(string)) && item.Content == "+")
                {
                    expr = Expression.Call(StringConcat, new[] { expr1, expr2 });
                }
                else
                {
                    expr =
                        Expression.MakeBinary(context.BinaryNodeTypes[item.Content],
                                              expr1,
                                              expr2);
                }
                ProcessedItem newItem = ProcessedItem.Create(expr);
                expressionTree.RemoveAt(i - 1);
                expressionTree.RemoveAt(i - 1);
                expressionTree.RemoveAt(i - 1);
                expressionTree.Insert(i - 1, newItem);
                return(true);
            }
            return(false);
        });
Example #3
0
        internal virtual Expression Parse(EvaluationContext context, ref string code)
        {
            if (code == null)
            {
                throw new ArgumentNullException(nameof(code));
            }
            IList <ProcessedItem> expressionTree = new List <ProcessedItem>();
            IExpressionPart       current        = GetObject <TParserEntry>();

            code = code.TrimStart(context.Whitespaces);
            string source = code;

            while (!string.IsNullOrEmpty(code))
            {
                bool found = false;
                foreach (Type partType in current.ExpectedParts)
                {
                    IExpressionPart newPart = GetObject(partType);
                    string          part    = newPart.Get(context, ref code);
                    if (!string.IsNullOrEmpty(part))
                    {
                        expressionTree.Add(ProcessedItem.Create(partType, part));
                        current = newPart;
                        found   = true;
                        break;
                    }
                }
                if (!found)
                {
                    string dependentObjects = string.Join(", ",
                                                          current.ExpectedParts.Select(o => o.Name)
#if NET35
                                                          .ToArray()
#endif
                                                          );
                    throw new EvaluationException($"Invalid expression, unable to parse.\nCurrent part: {current.GetType().Name}\nFollowing parts: {dependentObjects}\n{code}")
                          {
                              SourceExpression = source, Position = source.Length - code.Length + 1
                          };
                }
                code = code.TrimStart(context.Whitespaces);
            }

            Expression compiled = Compile(context, expressionTree);

            return(compiled);
        }
Example #4
0
 /// <summary>
 /// Compile the member access.
 /// </summary>
 /// <param name="expressionTree">The expression tree.</param>
 /// <returns>True if it changed the expression tree.</returns>
 protected virtual bool CompileMemberAccess(IList <ProcessedItem> expressionTree)
 => ReverseLoop(expressionTree, i =>
 {
     ProcessedItem item = expressionTree[i];
     if (i > 0 &&
         item.ItemType == typeof(EMemberAccess) &&
         expressionTree[i - 1].Expression != null)
     {
         Expression expr       = expressionTree[i - 1].Expression;
         expr                  = Expression.PropertyOrField(expr, item.Content.Substring(1));
         ProcessedItem newItem = ProcessedItem.Create(expr);
         expressionTree.RemoveAt(i - 1);
         expressionTree.RemoveAt(i - 1);
         expressionTree.Insert(i - 1, newItem);
         return(true);
     }
     return(false);
 });
Example #5
0
        /// <summary>
        /// Compile the conditional operators.
        /// </summary>
        /// <param name="context">The context of evaluation.</param>
        /// <param name="expressionTree">The expression tree.</param>
        /// <returns>True if it changed the expression tree.</returns>
        protected virtual bool CompileIIfOperators(EvaluationContext context, IList <ProcessedItem> expressionTree) =>
        ReverseLoop(expressionTree, i =>
        {
            ProcessedItem item = expressionTree[i];
            if (i > 0 && expressionTree.Count > i + 3 &&
                expressionTree[i - 1].Expression != null &&
                item.ItemType == typeof(EConditionalOperator) &&
                item.Content == "?" &&
                expressionTree[i + 1].Expression != null &&
                expressionTree[i + 2].ItemType == typeof(EConditionalOperator) &&
                expressionTree[i + 2].Content == ":" &&
                expressionTree[i + 3].Expression != null
                )
            {
                Expression expr0 = expressionTree[i - 1].Expression;
                Expression expr1 = expressionTree[i + 1].Expression;
                Expression expr2 = expressionTree[i + 3].Expression;

                Type resultType = context.ConsolidateBinaryTypes(context, expr1.Type, expr2.Type);
                if (expr1.Type != resultType)
                {
                    expr1 = Expression.Convert(expr1, resultType);
                }
                if (expr2.Type != resultType)
                {
                    expr2 = Expression.Convert(expr2, resultType);
                }

                Expression expr       = Expression.Condition(expr0, expr1, expr2);
                ProcessedItem newItem = ProcessedItem.Create(expr);
                expressionTree.RemoveAt(i - 1);
                expressionTree.RemoveAt(i - 1);
                expressionTree.RemoveAt(i - 1);
                expressionTree.RemoveAt(i - 1);
                expressionTree.RemoveAt(i - 1);
                expressionTree.Insert(i - 1, newItem);
                return(true);
            }
            return(false);
        });
Example #6
0
 /// <summary>
 /// Compile the unary operators.
 /// </summary>
 /// <param name="context">The context of evaluation.</param>
 /// <param name="expressionTree">The expression tree.</param>
 /// <returns>True if it changed the expression tree.</returns>
 protected virtual bool CompileUnaryOperators(EvaluationContext context, IList <ProcessedItem> expressionTree) =>
 TreeLoop(expressionTree, i =>
 {
     ProcessedItem item = expressionTree[i];
     if (expressionTree.Count > i + 1 &&
         item.ItemType == typeof(EUnaryOperator) &&
         expressionTree[i + 1].Expression != null)
     {
         Expression expr = expressionTree[i + 1].Expression;
         expr            =
             Expression.MakeUnary(context.UnaryNodeTypes[item.Content],
                                  expr,
                                  expr.Type
                                  );
         ProcessedItem newItem = ProcessedItem.Create(expr);
         expressionTree.RemoveAt(i);
         expressionTree.RemoveAt(i);
         expressionTree.Insert(i, newItem);
         return(true);
     }
     return(false);
 });
Example #7
0
        /// <summary>
        /// Compile the expression tree produced by parser.
        /// </summary>
        /// <param name="context">The context of evaluation.</param>
        /// <param name="expressionTree">The expression tree.</param>
        /// <returns>Result expression.</returns>
        protected virtual Expression Compile(EvaluationContext context, IList <ProcessedItem> expressionTree)
        {
            // move brackets into subtrees
            TreeLoop(expressionTree, i =>
            {
                ProcessedItem item = expressionTree[i];
                if (item.ItemType == typeof(ExpressionBlock))
                {
                    int num = 1;
                    int j   = i + 1;
                    while (num > 0 && j < expressionTree.Count)
                    {
                        ProcessedItem itemToMove = expressionTree[j];
                        if (itemToMove.ItemType == typeof(EExpressionEnd))
                        {
                            num--;
                        }
                        else if (itemToMove.ItemType == typeof(ExpressionBlock))
                        {
                            num++;
                        }
                        if (itemToMove.ItemType != typeof(EExpressionEnd) || num > 0)
                        {
                            item.Items.Add(itemToMove);
                        }
                        expressionTree.RemoveAt(j);
                    }
                    if (num > 0)
                    {
                        throw new EvaluationException("Expected ')' at the end of the expression.");
                    }
                    return(true);
                }
                return(false);
            });

            // compile subtrees
            ReverseLoop(expressionTree, i =>
            {
                ProcessedItem item = expressionTree[i];
                if (item.ItemType == typeof(ExpressionBlock))
                {
                    Expression expr       = Compile(context, item.Items);
                    ProcessedItem newItem = ProcessedItem.Create(expr);
                    expressionTree.RemoveAt(i);
                    expressionTree.Insert(i, newItem);
                    return(true);
                }
                return(false);
            });

            bool changed;

            do
            {
                changed = false;

                changed |= ReverseLoop(expressionTree, i =>
                {
                    ProcessedItem item1 = expressionTree[i];
                    if (item1.ItemType != typeof(ETypeCast) || item1.TypeToCast == null)
                    {
                        return(false);
                    }
                    if (i + 1 >= expressionTree.Count)
                    {
                        return(false);
                    }
                    ProcessedItem item2 = expressionTree[i + 1];
                    if (item2 is ProcessedItem)
                    {
                        Expression expr       = Expression.Convert(item2.Expression, item1.TypeToCast);
                        ProcessedItem newItem = ProcessedItem.Create(expr);
                        expressionTree.RemoveAt(i);
                        expressionTree.RemoveAt(i);
                        expressionTree.Insert(i, newItem);
                        return(true);
                    }
                    return(false);
                });

                changed |= CompileSingleItem(context, expressionTree);
                changed |= CompileMemberAccess(expressionTree);

                changed |= CompileUnaryOperators(context, expressionTree);
                changed |= CompileBinaryOperators(context, expressionTree);
                changed |= CompileIIfOperators(context, expressionTree);

                if (expressionTree.Count == 1 && expressionTree[0].Expression != null)
                {
                    return(expressionTree[0].Expression);
                }

                if (expressionTree.Count == 1 && expressionTree[0].TypeToCast != null)
                {
                    return(null);
                }
            } while (changed);

            throw new EvaluationException($"Expression compilation failed.\n{string.Join("\n", expressionTree.Select(o => o.Content).ToArray())}");
        }