Skip to content

Commit

Permalink
Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
miroiu committed Aug 25, 2021
1 parent c00d592 commit 0cf073c
Show file tree
Hide file tree
Showing 19 changed files with 190 additions and 112 deletions.
12 changes: 6 additions & 6 deletions StringMath.Tests/OptimizerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ public void Optimize(string input, string expected)
{
ITokenizer tokenizer = new Tokenizer(input);
IParser parser = new Parser(tokenizer, _context);
IExpressionVisitor<Expression> optimizer = new ExpressionOptimizer(_context);
IExpressionVisitor<IExpression> optimizer = new ExpressionOptimizer(_context);

Expression parsedExpr = parser.Parse();
Expression optimizedExpr = optimizer.Visit(parsedExpr);
IExpression parsedExpr = parser.Parse();
IExpression optimizedExpr = optimizer.Visit(parsedExpr);
string actual = optimizedExpr.ToString();

Assert.AreEqual(expected, actual);
Expand All @@ -45,10 +45,10 @@ public void Optimize_Fails(string input, string expected)
{
ITokenizer tokenizer = new Tokenizer(input);
IParser parser = new Parser(tokenizer, _context);
IExpressionVisitor<Expression> optimizer = new ExpressionOptimizer(_context);
IExpressionVisitor<IExpression> optimizer = new ExpressionOptimizer(_context);

Expression parsedExpr = parser.Parse();
Expression optimizedExpr = optimizer.Visit(parsedExpr);
IExpression parsedExpr = parser.Parse();
IExpression optimizedExpr = optimizer.Visit(parsedExpr);
string actual = optimizedExpr.ToString();

Assert.AreNotEqual(expected, actual);
Expand Down
14 changes: 7 additions & 7 deletions StringMath.Tests/ParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void ParseMathExpression(string input, string expected)
ITokenizer tokenizer = new Tokenizer(input);
IParser parser = new Parser(tokenizer, _context);

Expression result = parser.Parse();
IExpression result = parser.Parse();
string actual = result.ToString();

Assert.AreEqual(expected, actual);
Expand Down Expand Up @@ -94,7 +94,7 @@ public void ParseExpression_CustomOperators(string input, string expected)
ITokenizer tokenizer = new Tokenizer(input);
IParser parser = new Parser(tokenizer, context);

Expression result = parser.Parse();
IExpression result = parser.Parse();
string actual = result.ToString();

Assert.AreEqual(expected, actual);
Expand Down Expand Up @@ -129,7 +129,7 @@ public void ParseVariableExpression(string expected, string name)
ITokenizer tokenizer = new Tokenizer(expected);
IParser parser = new Parser(tokenizer, _context);

Expression result = parser.Parse();
IExpression result = parser.Parse();
string actual = result.ToString();

Assert.IsInstanceOf<VariableExpression>(result);
Expand Down Expand Up @@ -169,7 +169,7 @@ public void ParseBinaryExpression(string input, string expected)
ITokenizer tokenizer = new Tokenizer(input);
IParser parser = new Parser(tokenizer, _context);

Expression result = parser.Parse();
IExpression result = parser.Parse();
string actual = result.ToString();

Assert.IsInstanceOf<BinaryExpression>(result);
Expand All @@ -193,7 +193,7 @@ public void ParseUnaryExpression(string input, string expected)
ITokenizer tokenizer = new Tokenizer(input);
IParser parser = new Parser(tokenizer, _context);

Expression result = parser.Parse();
IExpression result = parser.Parse();
string actual = result.ToString();

Assert.IsInstanceOf<UnaryExpression>(result);
Expand Down Expand Up @@ -223,7 +223,7 @@ public void ParseConstantExpression(string expected)
ITokenizer tokenizer = new Tokenizer(expected);
IParser parser = new Parser(tokenizer, _context);

Expression result = parser.Parse();
IExpression result = parser.Parse();
string actual = result.ToString();

Assert.IsInstanceOf<ConstantExpression>(result);
Expand Down Expand Up @@ -260,7 +260,7 @@ public void ParseGroupingExpression(string expected)
ITokenizer tokenizer = new Tokenizer(expected);
IParser parser = new Parser(tokenizer, _context);

Expression result = parser.Parse();
IExpression result = parser.Parse();
string actual = result.ToString();

Assert.IsInstanceOf<GroupingExpression>(result);
Expand Down
2 changes: 1 addition & 1 deletion StringMath/Evaluator/Calculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace StringMath
{
/// <inheritdoc />
public class Calculator : VariablesCollection, ICalculator
public sealed class Calculator : VariablesCollection, ICalculator
{
private readonly IMathContext _mathContext;
private readonly IExpressionVisitor<ValueExpression> _evaluator;
Expand Down
26 changes: 13 additions & 13 deletions StringMath/Evaluator/ExpressionEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace StringMath
/// <inheritdoc />
internal sealed class ExpressionEvaluator : IExpressionVisitor<ValueExpression>
{
private readonly Dictionary<Type, Func<Expression, ValueExpression>> _expressionEvaluators;
private readonly Dictionary<ExpressionType, Func<IExpression, ValueExpression>> _expressionEvaluators;
private readonly IMathContext _context;
private readonly IVariablesCollection _variables;

Expand All @@ -21,20 +21,20 @@ public ExpressionEvaluator(IMathContext context, IVariablesCollection variables)
_variables = variables;
_context = context;

_expressionEvaluators = new Dictionary<Type, Func<Expression, ValueExpression>>
_expressionEvaluators = new Dictionary<ExpressionType, Func<IExpression, ValueExpression>>
{
[typeof(BinaryExpression)] = EvaluateBinaryExpression,
[typeof(UnaryExpression)] = EvaluateUnaryExpression,
[typeof(ConstantExpression)] = EvaluateConstantExpression,
[typeof(GroupingExpression)] = EvaluateGroupingExpression,
[typeof(VariableExpression)] = EvaluateVariableExpression
[ExpressionType.BinaryExpression] = EvaluateBinaryExpression,
[ExpressionType.UnaryExpression] = EvaluateUnaryExpression,
[ExpressionType.ConstantExpression] = EvaluateConstantExpression,
[ExpressionType.GroupingExpression] = EvaluateGroupingExpression,
[ExpressionType.VariableExpression] = EvaluateVariableExpression
};
}

/// <summary>Evaluates an expression tree and returns the resulting value.</summary>
/// <param name="expression">The expression to evaluate.</param>
/// <returns>An value expression.</returns>
public ValueExpression Visit(Expression expression)
public ValueExpression Visit(IExpression expression)
{
if (expression is ValueExpression expected)
{
Expand All @@ -45,21 +45,21 @@ public ValueExpression Visit(Expression expression)
return result;
}

private ValueExpression EvaluateConstantExpression(Expression expr)
private ValueExpression EvaluateConstantExpression(IExpression expr)
{
ConstantExpression constantExpr = (ConstantExpression)expr;
ValueExpression valueExpr = constantExpr.ToValueExpression();
return valueExpr;
}

private ValueExpression EvaluateGroupingExpression(Expression expr)
private ValueExpression EvaluateGroupingExpression(IExpression expr)
{
GroupingExpression groupingExpr = (GroupingExpression)expr;
ValueExpression innerExpr = Visit(groupingExpr.Inner);
return innerExpr;
}

private ValueExpression EvaluateUnaryExpression(Expression expr)
private ValueExpression EvaluateUnaryExpression(IExpression expr)
{
UnaryExpression unaryExpr = (UnaryExpression)expr;
ValueExpression valueExpr = Visit(unaryExpr.Operand);
Expand All @@ -68,7 +68,7 @@ private ValueExpression EvaluateUnaryExpression(Expression expr)
return new ValueExpression(result);
}

private ValueExpression EvaluateBinaryExpression(Expression expr)
private ValueExpression EvaluateBinaryExpression(IExpression expr)
{
BinaryExpression binaryExpr = (BinaryExpression)expr;
ValueExpression leftExpr = Visit(binaryExpr.Left);
Expand All @@ -78,7 +78,7 @@ private ValueExpression EvaluateBinaryExpression(Expression expr)
return new ValueExpression(result);
}

private ValueExpression EvaluateVariableExpression(Expression expr)
private ValueExpression EvaluateVariableExpression(IExpression expr)
{
VariableExpression variableExpr = (VariableExpression)expr;
return _variables.TryGetValue(variableExpr.Name, out double value)
Expand Down
40 changes: 20 additions & 20 deletions StringMath/Evaluator/ExpressionOptimizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
namespace StringMath
{
/// <inheritdoc />
internal class ExpressionOptimizer : IExpressionVisitor<Expression>
internal class ExpressionOptimizer : IExpressionVisitor<IExpression>
{
private readonly Dictionary<Type, Func<Expression, Expression>> _expressionOptimizers;
private readonly Dictionary<ExpressionType, Func<IExpression, IExpression>> _expressionOptimizers;
private readonly IMathContext _context;

/// <summary>Initializez a new instance of an expression optimizer.</summary>
Expand All @@ -16,43 +16,43 @@ public ExpressionOptimizer(IMathContext mathContext)
mathContext.EnsureNotNull(nameof(mathContext));
_context = mathContext;

_expressionOptimizers = new Dictionary<Type, Func<Expression, Expression>>
_expressionOptimizers = new Dictionary<ExpressionType, Func<IExpression, IExpression>>
{
[typeof(BinaryExpression)] = OptimizeBinaryExpression,
[typeof(UnaryExpression)] = EvaluateUnaryExpression,
[typeof(ConstantExpression)] = OptimizeConstantExpression,
[typeof(GroupingExpression)] = OptimizeGroupingExpression,
[typeof(VariableExpression)] = SkipExpressionOptimization,
[typeof(ValueExpression)] = SkipExpressionOptimization
[ExpressionType.BinaryExpression] = OptimizeBinaryExpression,
[ExpressionType.UnaryExpression] = EvaluateUnaryExpression,
[ExpressionType.ConstantExpression] = OptimizeConstantExpression,
[ExpressionType.GroupingExpression] = OptimizeGroupingExpression,
[ExpressionType.VariableExpression] = SkipExpressionOptimization,
[ExpressionType.ValueExpression] = SkipExpressionOptimization
};
}

/// <summary>Simplifies an expression tree by removing unnecessary nodes and evaluating constant expressions.</summary>
/// <param name="expression">The expression tree to optimize.</param>
/// <returns>An optimized expression tree.</returns>
public Expression Visit(Expression expression)
public IExpression Visit(IExpression expression)
{
Expression result = _expressionOptimizers[expression.Type](expression);
IExpression result = _expressionOptimizers[expression.Type](expression);
return result;
}

private Expression OptimizeConstantExpression(Expression expr)
private IExpression OptimizeConstantExpression(IExpression expr)
{
ConstantExpression constantExpr = (ConstantExpression)expr;
return constantExpr.ToValueExpression();
}

private Expression OptimizeGroupingExpression(Expression expr)
private IExpression OptimizeGroupingExpression(IExpression expr)
{
GroupingExpression groupingExpr = (GroupingExpression)expr;
Expression innerExpr = Visit(groupingExpr.Inner);
IExpression innerExpr = Visit(groupingExpr.Inner);
return innerExpr;
}

private Expression EvaluateUnaryExpression(Expression expr)
private IExpression EvaluateUnaryExpression(IExpression expr)
{
UnaryExpression unaryExpr = (UnaryExpression)expr;
Expression operandExpr = Visit(unaryExpr.Operand);
IExpression operandExpr = Visit(unaryExpr.Operand);
if (operandExpr is ValueExpression valueExpr)
{
double result = _context.EvaluateUnary(unaryExpr.OperatorName, valueExpr.Value);
Expand All @@ -62,11 +62,11 @@ private Expression EvaluateUnaryExpression(Expression expr)
return new UnaryExpression(unaryExpr.OperatorName, operandExpr);
}

private Expression OptimizeBinaryExpression(Expression expr)
private IExpression OptimizeBinaryExpression(IExpression expr)
{
BinaryExpression binaryExpr = (BinaryExpression)expr;
Expression leftExpr = Visit(binaryExpr.Left);
Expression rightExpr = Visit(binaryExpr.Right);
IExpression leftExpr = Visit(binaryExpr.Left);
IExpression rightExpr = Visit(binaryExpr.Right);

if (leftExpr is ValueExpression leftValue && rightExpr is ValueExpression rightValue)
{
Expand All @@ -77,7 +77,7 @@ private Expression OptimizeBinaryExpression(Expression expr)
return new BinaryExpression(leftExpr, binaryExpr.OperatorName, rightExpr);
}

private Expression SkipExpressionOptimization(Expression expr)
private IExpression SkipExpressionOptimization(IExpression expr)
{
return expr;
}
Expand Down
4 changes: 2 additions & 2 deletions StringMath/Evaluator/IExpressionVisitor.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace StringMath
{
/// <summary>Contract for expression visitors.</summary>
internal interface IExpressionVisitor<T> where T : Expression
internal interface IExpressionVisitor<out T> where T : IExpression
{
/// <summary>Visits an expression tree and transforms it to another of type <typeparamref name="T"/>.</summary>
/// <param name="expression">The expression to transform.</param>
/// <returns>An expression of type <typeparamref name="T"/>.</returns>
T Visit(Expression expression);
T Visit(IExpression expression);
}
}
12 changes: 6 additions & 6 deletions StringMath/Evaluator/OperationInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@
namespace StringMath
{
/// <summary>An optimized and cached math expression.</summary>
public class OperationInfo
public sealed class OperationInfo
{
/// <summary>Initializez a new instance of an operation info.</summary>
/// <param name="root">The optimized expression tree.</param>
/// <param name="expression">The math expression string.</param>
/// <param name="variables">A collection of variables extracted from the expression.</param>
private OperationInfo(Expression root, string expression, IReadOnlyCollection<string> variables)
private OperationInfo(IExpression root, string expression, IReadOnlyCollection<string> variables)
{
Root = root;
Expression = expression;
Variables = variables;
}

/// <summary>The cached expression tree.</summary>
internal Expression Root { get; }
internal IExpression Root { get; }

/// <summary>The math expression that was used to create this operation.</summary>
public string Expression { get; }
Expand All @@ -33,9 +33,9 @@ internal static OperationInfo Create(string expression, IMathContext context)
{
ITokenizer tokenizer = new Tokenizer(expression);
IParser parser = new Parser(tokenizer, context);
IExpressionVisitor<Expression> optimizer = new ExpressionOptimizer(context);
Expression root = parser.Parse();
Expression optimized = optimizer.Visit(root);
IExpressionVisitor<IExpression> optimizer = new ExpressionOptimizer(context);
IExpression root = parser.Parse();
IExpression optimized = optimizer.Visit(root);

return new OperationInfo(optimized, expression, parser.Variables);
}
Expand Down
23 changes: 18 additions & 5 deletions StringMath/Parser/BinaryExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,33 @@

namespace StringMath
{
internal sealed class BinaryExpression : Expression
/// <summary>A binary expression.</summary>
internal sealed class BinaryExpression : IExpression
{
public BinaryExpression(Expression left, string operatorName, Expression right)
/// <summary>Initializez a new instance of a binary expression.</summary>
/// <param name="left">The left expression tree.</param>
/// <param name="operatorName">The binary operator's name.</param>
/// <param name="right">The right expression tree.</param>
public BinaryExpression(IExpression left, string operatorName, IExpression right)
{
Left = left;
OperatorName = operatorName;
Right = right;
}

public Expression Left { get; }
/// <summary>The left expression tree.</summary>
public IExpression Left { get; }

/// <summary>The binary operator's name.</summary>
public string OperatorName { get; }
public Expression Right { get; }
public override Type Type => typeof(BinaryExpression);

/// <summary>The right expression tree.</summary>
public IExpression Right { get; }

/// <inheritdoc />
public ExpressionType Type => ExpressionType.BinaryExpression;

/// <inheritdoc />
public override string ToString()
{
return $"{Left} {OperatorName} {Right}";
Expand Down
15 changes: 10 additions & 5 deletions StringMath/Parser/ConstantExpression.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
using System;

namespace StringMath
namespace StringMath
{
internal sealed class ConstantExpression : Expression
/// <summary>A constant expression.</summary>
internal sealed class ConstantExpression : IExpression
{
/// <summary>Initializez a new instance of a constant expression.</summary>
/// <param name="value">The value of the constant.</param>
public ConstantExpression(string value)
=> Value = value;

/// <summary>The constant value.</summary>
public string Value { get; }
public override Type Type => typeof(ConstantExpression);

/// <inheritdoc />
public ExpressionType Type => ExpressionType.ConstantExpression;

/// <inheritdoc />
public override string ToString()
{
return Value;
Expand Down
Loading

0 comments on commit 0cf073c

Please sign in to comment.