using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace Swan.Parsers
{
///
/// 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) =>
ResolveExpression(tokens, System.Globalization.CultureInfo.InvariantCulture);
///
/// Resolves the expression.
///
/// The type of expression result.
/// The tokens.
/// The format provider.
/// The representation of the expression parsed.
public virtual T ResolveExpression(IEnumerable tokens, IFormatProvider formatProvider)
{
var conversion = Expression.Convert(Parse(tokens,formatProvider), typeof(T));
return Expression.Lambda>(conversion).Compile()();
}
///
/// Parses the specified tokens.
///
/// The tokens.
///
/// The final expression.
///
public virtual Expression Parse(IEnumerable tokens) =>
Parse(tokens, System.Globalization.CultureInfo.InvariantCulture);
///
/// Parses the specified tokens.
///
/// The tokens.
/// The format provider.
///
/// The final expression.
///
public virtual Expression Parse(IEnumerable tokens, IFormatProvider formatProvider)
{
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, formatProvider)));
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);
}
}