RaspberryIO/Unosquare.Swan.Lite/Abstractions/ExpressionParser.cs
2019-02-17 14:08:57 +01:00

95 lines
3.6 KiB
C#

namespace Unosquare.Swan.Abstractions
{
using System;
using System.Linq;
using System.Collections.Generic;
using System.Linq.Expressions;
/// <summary>
/// Represents a generic expression parser.
/// </summary>
public abstract class ExpressionParser
{
/// <summary>
/// Resolves the expression.
/// </summary>
/// <typeparam name="T">The type of expression result.</typeparam>
/// <param name="tokens">The tokens.</param>
/// <returns>The representation of the expression parsed.</returns>
public virtual T ResolveExpression<T>(IEnumerable<Token> tokens)
{
var conversion = Expression.Convert(Parse(tokens), typeof(T));
return Expression.Lambda<Func<T>>(conversion).Compile()();
}
/// <summary>
/// Parses the specified tokens.
/// </summary>
/// <param name="tokens">The tokens.</param>
/// <returns>The final expression.</returns>
public virtual Expression Parse(IEnumerable<Token> tokens)
{
var expressionStack = new List<Stack<Expression>>();
foreach (var token in tokens)
{
if (expressionStack.Any() == false)
expressionStack.Add(new Stack<Expression>());
switch (token.Type)
{
case TokenType.Wall:
expressionStack.Add(new Stack<Expression>());
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();
}
/// <summary>
/// Resolves the variable.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="expressionStack">The expression stack.</param>
public abstract void ResolveVariable(string value, Stack<Expression> expressionStack);
/// <summary>
/// Resolves the operator.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="expressionStack">The expression stack.</param>
public abstract void ResolveOperator(string value, Stack<Expression> expressionStack);
/// <summary>
/// Resolves the function.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="expressionStack">The expression stack.</param>
public abstract void ResolveFunction(string value, Stack<Expression> expressionStack);
}
}