Skip to content

Commit 7dad43a

Browse files
committed
Merge pull request sprache#23 from tibel/master
LinqyCalculator: additonal operators and math functions
2 parents 9275a81 + 1610e75 commit 7dad43a

File tree

1 file changed

+39
-9
lines changed

1 file changed

+39
-9
lines changed
Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
using System;
2+
using System.Linq;
23
using System.Linq.Expressions;
34
using Sprache;
45

56
namespace LinqyCalculator
67
{
78
static class ExpressionParser
89
{
9-
public static Expression<Func<decimal>> ParseExpression(string text)
10+
public static Expression<Func<double>> ParseExpression(string text)
1011
{
1112
return Lambda.Parse(text);
1213
}
@@ -20,23 +21,52 @@ static Parser<ExpressionType> Operator(string op, ExpressionType opType)
2021
static readonly Parser<ExpressionType> Subtract = Operator("-", ExpressionType.SubtractChecked);
2122
static readonly Parser<ExpressionType> Multiply = Operator("*", ExpressionType.MultiplyChecked);
2223
static readonly Parser<ExpressionType> Divide = Operator("/", ExpressionType.Divide);
24+
static readonly Parser<ExpressionType> Modulo = Operator("%", ExpressionType.Modulo);
25+
static readonly Parser<ExpressionType> Power = Operator("^", ExpressionType.Power);
26+
27+
static readonly Parser<Expression> Function =
28+
from name in Parse.Letter.AtLeastOnce().Text()
29+
from lparen in Parse.Char('(')
30+
from expr in Parse.Ref(() => Expr).DelimitedBy(Parse.Char(',').Token())
31+
from rparen in Parse.Char(')')
32+
select CallFunction(name, expr.ToArray());
33+
34+
static Expression CallFunction(string name, Expression[] parameters)
35+
{
36+
var methodInfo = typeof (Math).GetMethod(name, parameters.Select(e => e.Type).ToArray());
37+
if (methodInfo == null)
38+
throw new ParseException(string.Format("Function '{0}({1})' does not exist.", name,
39+
string.Join(",", parameters.Select(e => e.Type.Name))));
40+
41+
return Expression.Call(methodInfo, parameters);
42+
}
2343

2444
static readonly Parser<Expression> Constant =
25-
(from d in Parse.Decimal.Token()
26-
select (Expression)Expression.Constant(decimal.Parse(d))).Named("number");
45+
Parse.Decimal
46+
.Select(x => Expression.Constant(double.Parse(x)))
47+
.Named("number");
2748

2849
static readonly Parser<Expression> Factor =
29-
((from lparen in Parse.Char('(')
50+
(from lparen in Parse.Char('(')
3051
from expr in Parse.Ref(() => Expr)
3152
from rparen in Parse.Char(')')
3253
select expr).Named("expression")
33-
.XOr(Constant)).Token();
54+
.XOr(Constant)
55+
.XOr(Function);
3456

35-
static readonly Parser<Expression> Term = Parse.ChainOperator(Multiply.Or(Divide), Factor, Expression.MakeBinary);
57+
static readonly Parser<Expression> Operand =
58+
((from sign in Parse.Char('-')
59+
from factor in Factor
60+
select Expression.Negate(factor)
61+
).XOr(Factor)).Token();
62+
63+
static readonly Parser<Expression> InnerTerm = Parse.ChainOperator(Power, Operand, Expression.MakeBinary);
64+
65+
static readonly Parser<Expression> Term = Parse.ChainOperator(Multiply.Or(Divide).Or(Modulo), InnerTerm, Expression.MakeBinary);
3666

3767
static readonly Parser<Expression> Expr = Parse.ChainOperator(Add.Or(Subtract), Term, Expression.MakeBinary);
38-
39-
static readonly Parser<Expression<Func<decimal>>> Lambda =
40-
Expr.End().Select(body => Expression.Lambda<Func<decimal>>(body));
68+
69+
static readonly Parser<Expression<Func<double>>> Lambda =
70+
Expr.End().Select(body => Expression.Lambda<Func<double>>(body));
4171
}
4272
}

0 commit comments

Comments
 (0)