-
Notifications
You must be signed in to change notification settings - Fork 216
/
Copy pathExpressionParser.cs
73 lines (60 loc) · 3.07 KB
/
ExpressionParser.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Sprache;
namespace LinqyCalculator
{
static class ExpressionParser
{
public static Expression<Func<double>> ParseExpression(string text)
{
return Lambda.Parse(text);
}
static Parser<ExpressionType> Operator(string op, ExpressionType opType)
{
return Parse.String(op).Token().Return(opType);
}
static readonly Parser<ExpressionType> Add = Operator("+", ExpressionType.AddChecked);
static readonly Parser<ExpressionType> Subtract = Operator("-", ExpressionType.SubtractChecked);
static readonly Parser<ExpressionType> Multiply = Operator("*", ExpressionType.MultiplyChecked);
static readonly Parser<ExpressionType> Divide = Operator("/", ExpressionType.Divide);
static readonly Parser<ExpressionType> Modulo = Operator("%", ExpressionType.Modulo);
static readonly Parser<ExpressionType> Power = Operator("^", ExpressionType.Power);
static readonly Parser<Expression> Function =
from name in Parse.Letter.AtLeastOnce().Text()
from lparen in Parse.Char('(')
from expr in Parse.Ref(() => Expr).DelimitedBy(Parse.Char(',').Token())
from rparen in Parse.Char(')')
select CallFunction(name, expr.ToArray());
static Expression CallFunction(string name, Expression[] parameters)
{
var methodInfo = typeof(Math).GetTypeInfo().GetMethod(name, parameters.Select(e => e.Type).ToArray());
if (methodInfo == null)
throw new ParseException(string.Format("Function '{0}({1})' does not exist.", name,
string.Join(",", parameters.Select(e => e.Type.Name))));
return Expression.Call(methodInfo, parameters);
}
static readonly Parser<Expression> Constant =
Parse.Decimal
.Select(x => Expression.Constant(double.Parse(x)))
.Named("number");
static readonly Parser<Expression> Factor =
(from lparen in Parse.Char('(')
from expr in Parse.Ref(() => Expr)
from rparen in Parse.Char(')')
select expr).Named("expression")
.XOr(Constant)
.XOr(Function);
static readonly Parser<Expression> Operand =
((from sign in Parse.Char('-')
from factor in Factor
select Expression.Negate(factor)
).XOr(Factor)).Token();
static readonly Parser<Expression> InnerTerm = Parse.ChainRightOperator(Power, Operand, Expression.MakeBinary);
static readonly Parser<Expression> Term = Parse.ChainOperator(Multiply.Or(Divide).Or(Modulo), InnerTerm, Expression.MakeBinary);
static readonly Parser<Expression> Expr = Parse.ChainOperator(Add.Or(Subtract), Term, Expression.MakeBinary);
static readonly Parser<Expression<Func<double>>> Lambda =
Expr.End().Select(body => Expression.Lambda<Func<double>>(body));
}
}