namespace Unosquare.Swan.Abstractions { using System; using System.Linq; using System.Collections.Generic; using System.Linq.Expressions; /// /// Represents a generic expression parser. /// public abstract class ExpressionParser { /// /// Resolves the expression. /// /// The type of expression result. /// The tokens. /// The representation of the expression parsed. public virtual T ResolveExpression(IEnumerable tokens) { var conversion = Expression.Convert(Parse(tokens), typeof(T)); return Expression.Lambda>(conversion).Compile()(); } /// /// Parses the specified tokens. /// /// The tokens. /// The final expression. public virtual Expression Parse(IEnumerable tokens) { var expressionStack = new List>(); foreach (var token in tokens) { if (expressionStack.Any() == false) expressionStack.Add(new Stack()); switch (token.Type) { case TokenType.Wall: expressionStack.Add(new Stack()); break; case TokenType.Number: expressionStack.Last().Push(Expression.Constant(Convert.ToDecimal(token.Value))); break; case TokenType.Variable: ResolveVariable(token.Value, expressionStack.Last()); break; case TokenType.String: expressionStack.Last().Push(Expression.Constant(token.Value)); break; case TokenType.Operator: ResolveOperator(token.Value, expressionStack.Last()); break; case TokenType.Function: ResolveFunction(token.Value, expressionStack.Last()); if (expressionStack.Count > 1 && expressionStack.Last().Count == 1) { var lastValue = expressionStack.Last().Pop(); expressionStack.Remove(expressionStack.Last()); expressionStack.Last().Push(lastValue); } break; } } return expressionStack.Last().Pop(); } /// /// Resolves the variable. /// /// The value. /// The expression stack. public abstract void ResolveVariable(string value, Stack expressionStack); /// /// Resolves the operator. /// /// The value. /// The expression stack. public abstract void ResolveOperator(string value, Stack expressionStack); /// /// Resolves the function. /// /// The value. /// The expression stack. public abstract void ResolveFunction(string value, Stack expressionStack); } }