add logic expression classes for use with XML parsing

This commit is contained in:
Michael Becker 2020-02-29 17:58:47 -05:00
parent 4272a80e4a
commit 731a050979
No known key found for this signature in database
GPG Key ID: 506F54899E2BFED7
11 changed files with 322 additions and 0 deletions

View File

@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using MBS.Framework.Logic.Expressions;
namespace MBS.Framework.Logic
{
public abstract class Expression
{
public static Expression Empty { get; } = new EmptyExpression();
public class ExpressionCollection
: System.Collections.ObjectModel.Collection<Expression>
{
}
/// <summary>
/// Parses the expression represented by <paramref name="value"/>.
/// </summary>
/// <returns>The parsed <see cref="Expression" />.</returns>
/// <param name="value">The value to parse.</param>
public static Expression Parse(string value)
{
Expression expr = Expression.Empty;
if (String.IsNullOrEmpty(value))
return expr;
if (value.ToLower() == "true")
{
return new BooleanExpression(true);
}
else if (value.ToLower() == "false")
{
return new BooleanExpression(false);
}
// see if there are any variables
if (value.Contains("$(") && value.Contains(")"))
{
int variableStartIndex = value.IndexOf("$(", StringComparison.Ordinal);
int variableEndIndex = value.IndexOf(")", variableStartIndex, StringComparison.Ordinal);
string wleft = value.Substring(0, variableStartIndex);
string wvar = value.Substring(variableStartIndex + 2, variableEndIndex - 2);
string wright = value.Substring(variableEndIndex + 1);
Expression exprLeft = Expression.Parse(wleft);
Expression exprRight = Expression.Parse(wright);
List<Expression> list = new List<Expression>();
if (exprLeft != Expression.Empty) list.Add(exprLeft);
list.Add(new VariableExpression(wvar));
if (exprRight != Expression.Empty) list.Add(exprRight);
if (list.Count == 1)
return list[0];
return new ComplexExpression(list.ToArray());
}
else
{
// first try parsing it as a double
double doublevalue = 0.0;
if (Double.TryParse(value, out doublevalue))
{
return new LiteralExpression<double>(doublevalue);
}
// otherwise, idk
return new LiteralExpression<string>(value);
}
return expr;
}
public abstract Expression Evaluate(ExpressionContext context);
public T Evaluate<T>(ExpressionContext context)
{
Expression exprResult = Evaluate(context);
if (exprResult is LiteralExpression<T>)
{
return ((LiteralExpression<T>)exprResult).Value;
}
throw new InvalidCastException("expression cannot be evaluated to LiteralExpression<" + typeof(T).Name + ">");
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
namespace MBS.Framework.Logic
{
public class ExpressionContext
{
public Variable.VariableCollection Variables { get; } = new Variable.VariableCollection();
public void SetVariableValue<T>(string variableName, T value)
{
Variables[variableName].Expression = new Expressions.LiteralExpression<T>(value);
}
public event VariableRequestedEventHandler VariableRequested;
protected virtual void OnVariableRequested(VariableRequestedEventArgs e)
{
VariableRequested?.Invoke(this, e);
}
}
}

View File

@ -0,0 +1,38 @@
using System;
namespace MBS.Framework.Logic.Expressions
{
public enum ArithmeticOperation
{
None = 0,
Addition,
Subtraction,
Multiplication,
Division,
And,
Or,
Xor,
Modulus
}
public class ArithmeticExpression : Expression
{
public ArithmeticOperation Operation { get; set; } = ArithmeticOperation.Addition;
public Expression PrimaryExpression { get; set; } = null;
public Expression SecondaryExpression { get; set; } = null;
public ArithmeticExpression()
{
}
public ArithmeticExpression(ArithmeticOperation operation, Expression primary, Expression secondary)
{
Operation = operation;
PrimaryExpression = primary;
SecondaryExpression = secondary;
}
public override Expression Evaluate(ExpressionContext context)
{
// TODO: implement Evaluate() on ArithmeticExpression
return null;
}
}
}

View File

@ -0,0 +1,25 @@
using System;
namespace MBS.Framework.Logic.Expressions
{
public enum BooleanExpressionComparison
{
Equal,
LessThan,
GreaterThan,
LessThanOrEqual,
GreaterThanOrEqual
}
public class BooleanExpression : Expression
{
public BooleanExpression(bool value = false)
{
Value = value;
}
public bool Value { get; set; } = false;
public override Expression Evaluate(ExpressionContext context)
{
return this;
}
}
}

View File

@ -0,0 +1,21 @@
using System;
namespace MBS.Framework.Logic.Expressions
{
public class ComplexExpression : Expression
{
public ComplexExpression(Expression[] exprs)
{
for (int i = 0; i < exprs.Length; i++)
{
Expressions.Add(exprs[i]);
}
}
public Expression.ExpressionCollection Expressions { get; } = new Expression.ExpressionCollection();
public override Expression Evaluate(ExpressionContext context)
{
return null;
}
}
}

View File

@ -0,0 +1,11 @@
using System;
namespace MBS.Framework.Logic.Expressions
{
public class EmptyExpression : Expression
{
public override Expression Evaluate(ExpressionContext context)
{
return Expression.Empty;
}
}
}

View File

@ -0,0 +1,18 @@
using System;
namespace MBS.Framework.Logic.Expressions
{
public class LiteralExpression<T> : Expression
{
public T Value { get; set; } = default(T);
public LiteralExpression(T value = default(T))
{
Value = value;
}
public override Expression Evaluate(ExpressionContext context)
{
return this;
}
}
}

View File

@ -0,0 +1,23 @@
using System;
namespace MBS.Framework.Logic.Expressions
{
public class VariableExpression : Expression
{
public VariableExpression(string variableName)
{
VariableName = variableName;
}
public string VariableName { get; set; } = null;
public override Expression Evaluate(ExpressionContext context)
{
Variable varr = context.Variables[VariableName];
if (varr != null)
{
return varr.Expression;
}
return null;
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
namespace MBS.Framework.Logic
{
public class Variable
{
public class VariableCollection
: System.Collections.ObjectModel.Collection<Variable>
{
private Dictionary<string, Variable> _itemsByName = new Dictionary<string, Variable>();
public Variable this[string name]
{
get
{
if (_itemsByName.ContainsKey(name))
return _itemsByName[name];
return null;
}
}
protected override void ClearItems()
{
base.ClearItems();
_itemsByName.Clear();
}
protected override void InsertItem(int index, Variable item)
{
base.InsertItem(index, item);
_itemsByName[item.Name] = item;
}
protected override void RemoveItem(int index)
{
_itemsByName.Remove(this[index].Name);
base.RemoveItem(index);
}
}
public string Name { get; set; } = null;
public Expression Expression { get; set; } = null;
public Variable(string name, Expression expression)
{
Name = name;
Expression = expression;
}
}
}

View File

@ -0,0 +1,16 @@
using System;
namespace MBS.Framework.Logic
{
public class VariableRequestedEventArgs : EventArgs
{
public bool Handled { get; set; } = false;
public string VariableName { get; set; } = null;
public object Value { get; set; } = null;
public VariableRequestedEventArgs(string variableName)
{
VariableName = variableName;
}
}
public delegate void VariableRequestedEventHandler(object sender, VariableRequestedEventArgs e);
}

View File

@ -50,6 +50,20 @@
<Compile Include="ArrayExtensions.cs" />
<Compile Include="Reflection.cs" />
<Compile Include="Security\Cryptography\ExtensionMethods.cs" />
<Compile Include="Logic\Expression.cs" />
<Compile Include="Logic\Expressions\BooleanExpression.cs" />
<Compile Include="Logic\Expressions\LiteralExpression.cs" />
<Compile Include="Logic\Expressions\ComplexExpression.cs" />
<Compile Include="Logic\Expressions\VariableExpression.cs" />
<Compile Include="Logic\ExpressionContext.cs" />
<Compile Include="Logic\Variable.cs" />
<Compile Include="Logic\Expressions\EmptyExpression.cs" />
<Compile Include="Logic\Expressions\ArithmeticExpression.cs" />
<Compile Include="Logic\VariableRequestedEvent.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Logic\" />
<Folder Include="Logic\Expressions\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>