private static Tuple<string, string> parseExpression(
Dictionary<Tuple<string, string>, double> terms,
Expression expr, out double scalar, bool dontAdd = false)
{
scalar = 0;
if (expr == null)
return null;
BinaryExpression eb = expr as BinaryExpression;
MemberExpression em = expr as MemberExpression;
UnaryExpression eu = expr as UnaryExpression;
if (em != null) // member expression
{
var term = Tuple.Create(em.Member.Name, (string)null);
terms[term] = 1;
return term;
}
else if (eb != null) // binary expression
{
if (expr.NodeType == ExpressionType.Multiply)
{
// This could be either a constant*expression, expression*constant or expression*expression
ConstantExpression c = eb.Left as ConstantExpression ?? eb.Right as ConstantExpression;
MemberExpression lm = eb.Left as MemberExpression;
BinaryExpression lb = eb.Left as BinaryExpression;
UnaryExpression lu = eb.Left as UnaryExpression;
MemberExpression rm = eb.Right as MemberExpression;
BinaryExpression rb = eb.Right as BinaryExpression;
UnaryExpression ru = eb.Right as UnaryExpression;
if (c != null)
{
// This is constant*expression or expression*constant
scalar = (double)c.Value;
if ((lm ?? rm) != null)
{
var term = Tuple.Create((lm ?? rm).Member.Name, (string)null);
if (!dontAdd) terms[term] = scalar;
return term;
}
else if ((lb ?? rb ?? (Expression)lm ?? lu) != null)
{
double n;
var term = parseExpression(terms, lb ?? lu ?? (Expression)rb ?? ru, out n);
if (!dontAdd) terms[term] = scalar;
return term;
}
else throw new FormatException("Unexpected expression.");
}
else
{
// This is x * x
if (lm != null && rm != null)
{
scalar = 1;
return addTuple(terms, scalar, lm.Member.Name, rm.Member.Name);
}
else if ((lb ?? rb ?? lu ?? (Expression)ru) != null && (lm ?? rm) != null)
{
// This is expression * x
var term = parseExpression(terms, (lb ?? rb ?? lu ?? (Expression)ru), out scalar, dontAdd: true);
return addTuple(terms, scalar, term.Item1, (lm ?? rm).Member.Name);
}
else throw new FormatException("Unexpected expression.");
}
}
else if (expr.NodeType == ExpressionType.Add)
{
// This could be an expression + term, a term + expression or an expression + expression
BinaryExpression lb = eb.Left as BinaryExpression;
MemberExpression lm = eb.Left as MemberExpression;
UnaryExpression lu = eb.Left as UnaryExpression;
BinaryExpression rb = eb.Right as BinaryExpression;
MemberExpression rm = eb.Right as MemberExpression;
ConstantExpression rc = eb.Right as ConstantExpression;
scalar = 1;
if (lb != null)
{
parseExpression(terms, lb, out scalar);
}
else if (lm != null)
{
var term = Tuple.Create(lm.Member.Name, (string)null);
if (!dontAdd)
terms[term] = scalar;
}
else if (lu != null)
{
parseExpression(terms, lu, out scalar);
}
else throw new FormatException("Unexpected expression.");
scalar = 1;
if (rb != null)
{
parseExpression(terms, rb, out scalar);
}
else if (rm != null)
{
var term = Tuple.Create(rm.Member.Name, (string)null);
if (!dontAdd)
terms[term] = scalar;
}
else if (rc != null)
{
scalar = (double)rc.Value;
var term = Tuple.Create((string)null, (string)null);
if (!dontAdd)
terms[term] = scalar;
}
else throw new FormatException("Unexpected expression.");
}
else if (expr.NodeType == ExpressionType.Subtract)
{
// This could be an expression - term, a term - expression or an expression - expression
BinaryExpression lb = eb.Left as BinaryExpression;
MemberExpression lm = eb.Left as MemberExpression;
UnaryExpression lu = eb.Left as UnaryExpression;
BinaryExpression rb = eb.Right as BinaryExpression;
MemberExpression rm = eb.Right as MemberExpression;
ConstantExpression rc = eb.Right as ConstantExpression;
if (lb != null)
{
parseExpression(terms, lb, out scalar);
}
else if (lm != null)
{
scalar = 1;
var term = Tuple.Create(lm.Member.Name, (string)null);
if (!dontAdd) terms[term] = scalar;
}
else if (lu != null)
{
parseExpression(terms, lu, out scalar);
}
else throw new FormatException("Unexpected expression.");
if (rb != null)
{
var term = parseExpression(terms, rb, out scalar);
terms[term] = -scalar;
}
else if (rm != null)
{
scalar = -1;
var term = Tuple.Create(rm.Member.Name, (string)null);
if (!dontAdd) terms[term] = scalar;
}
else if (rc != null)
{
scalar = (double)rc.Value;
var term = Tuple.Create((string)null, (string)null);
terms[term] = -scalar;
}
else throw new FormatException("Unexpected expression.");
}
}
else if (eu != null) // unary expression
{
if (expr.NodeType == ExpressionType.UnaryPlus)
{
BinaryExpression lb = eu.Operand as BinaryExpression;
MemberExpression lm = eu.Operand as MemberExpression;
if (lm != null)
{
scalar = 1;
var term = Tuple.Create(lm.Member.Name, (string)null);
if (!dontAdd) terms[term] = scalar;
return term;
}
else if (lb != null)
{
var term = parseExpression(terms, lb, out scalar);
if (!dontAdd) terms[term] = scalar;
}
else throw new FormatException("Unexpected expression.");
}
else if (expr.NodeType == ExpressionType.Negate)
{
BinaryExpression lb = eu.Operand as BinaryExpression;
MemberExpression lm = eu.Operand as MemberExpression;
if (lm != null)
{
scalar = -1;
var term = Tuple.Create(lm.Member.Name, (string)null);
if (!dontAdd) terms[term] = scalar;
return term;
}
else if (lb != null)
{
var term = parseExpression(terms, lb, out scalar);
terms[term] = -scalar;
}
else throw new FormatException("Unexpected expression.");
}
else throw new FormatException("Unexpected expression.");
}
else throw new FormatException("Unexpected expression.");
return null;
}