From 731a050979248f1bcbfee9be72ea7e5637ffcc61 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Sat, 29 Feb 2020 17:58:47 -0500 Subject: [PATCH] add logic expression classes for use with XML parsing --- MBS.Framework/Logic/Expression.cs | 87 +++++++++++++++++++ MBS.Framework/Logic/ExpressionContext.cs | 21 +++++ .../Logic/Expressions/ArithmeticExpression.cs | 38 ++++++++ .../Logic/Expressions/BooleanExpression.cs | 25 ++++++ .../Logic/Expressions/ComplexExpression.cs | 21 +++++ .../Logic/Expressions/EmptyExpression.cs | 11 +++ .../Logic/Expressions/LiteralExpression.cs | 18 ++++ .../Logic/Expressions/VariableExpression.cs | 23 +++++ MBS.Framework/Logic/Variable.cs | 48 ++++++++++ MBS.Framework/Logic/VariableRequestedEvent.cs | 16 ++++ MBS.Framework/MBS.Framework.csproj | 14 +++ 11 files changed, 322 insertions(+) create mode 100644 MBS.Framework/Logic/Expression.cs create mode 100644 MBS.Framework/Logic/ExpressionContext.cs create mode 100644 MBS.Framework/Logic/Expressions/ArithmeticExpression.cs create mode 100644 MBS.Framework/Logic/Expressions/BooleanExpression.cs create mode 100644 MBS.Framework/Logic/Expressions/ComplexExpression.cs create mode 100644 MBS.Framework/Logic/Expressions/EmptyExpression.cs create mode 100644 MBS.Framework/Logic/Expressions/LiteralExpression.cs create mode 100644 MBS.Framework/Logic/Expressions/VariableExpression.cs create mode 100644 MBS.Framework/Logic/Variable.cs create mode 100644 MBS.Framework/Logic/VariableRequestedEvent.cs diff --git a/MBS.Framework/Logic/Expression.cs b/MBS.Framework/Logic/Expression.cs new file mode 100644 index 0000000..83a0019 --- /dev/null +++ b/MBS.Framework/Logic/Expression.cs @@ -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 + { + + } + + /// + /// Parses the expression represented by . + /// + /// The parsed . + /// The value to parse. + 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 list = new List(); + 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(doublevalue); + } + + // otherwise, idk + return new LiteralExpression(value); + } + return expr; + } + + public abstract Expression Evaluate(ExpressionContext context); + + public T Evaluate(ExpressionContext context) + { + Expression exprResult = Evaluate(context); + if (exprResult is LiteralExpression) + { + return ((LiteralExpression)exprResult).Value; + } + throw new InvalidCastException("expression cannot be evaluated to LiteralExpression<" + typeof(T).Name + ">"); + } + } +} diff --git a/MBS.Framework/Logic/ExpressionContext.cs b/MBS.Framework/Logic/ExpressionContext.cs new file mode 100644 index 0000000..8f56a67 --- /dev/null +++ b/MBS.Framework/Logic/ExpressionContext.cs @@ -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(string variableName, T value) + { + Variables[variableName].Expression = new Expressions.LiteralExpression(value); + } + + public event VariableRequestedEventHandler VariableRequested; + protected virtual void OnVariableRequested(VariableRequestedEventArgs e) + { + VariableRequested?.Invoke(this, e); + } + } +} diff --git a/MBS.Framework/Logic/Expressions/ArithmeticExpression.cs b/MBS.Framework/Logic/Expressions/ArithmeticExpression.cs new file mode 100644 index 0000000..9c42d28 --- /dev/null +++ b/MBS.Framework/Logic/Expressions/ArithmeticExpression.cs @@ -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; + } + } +} diff --git a/MBS.Framework/Logic/Expressions/BooleanExpression.cs b/MBS.Framework/Logic/Expressions/BooleanExpression.cs new file mode 100644 index 0000000..e52968c --- /dev/null +++ b/MBS.Framework/Logic/Expressions/BooleanExpression.cs @@ -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; + } + } +} diff --git a/MBS.Framework/Logic/Expressions/ComplexExpression.cs b/MBS.Framework/Logic/Expressions/ComplexExpression.cs new file mode 100644 index 0000000..494fb0a --- /dev/null +++ b/MBS.Framework/Logic/Expressions/ComplexExpression.cs @@ -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; + } + } +} diff --git a/MBS.Framework/Logic/Expressions/EmptyExpression.cs b/MBS.Framework/Logic/Expressions/EmptyExpression.cs new file mode 100644 index 0000000..0064346 --- /dev/null +++ b/MBS.Framework/Logic/Expressions/EmptyExpression.cs @@ -0,0 +1,11 @@ +using System; +namespace MBS.Framework.Logic.Expressions +{ + public class EmptyExpression : Expression + { + public override Expression Evaluate(ExpressionContext context) + { + return Expression.Empty; + } + } +} diff --git a/MBS.Framework/Logic/Expressions/LiteralExpression.cs b/MBS.Framework/Logic/Expressions/LiteralExpression.cs new file mode 100644 index 0000000..623786a --- /dev/null +++ b/MBS.Framework/Logic/Expressions/LiteralExpression.cs @@ -0,0 +1,18 @@ +using System; +namespace MBS.Framework.Logic.Expressions +{ + public class LiteralExpression : Expression + { + public T Value { get; set; } = default(T); + + public LiteralExpression(T value = default(T)) + { + Value = value; + } + + public override Expression Evaluate(ExpressionContext context) + { + return this; + } + } +} diff --git a/MBS.Framework/Logic/Expressions/VariableExpression.cs b/MBS.Framework/Logic/Expressions/VariableExpression.cs new file mode 100644 index 0000000..e90d14a --- /dev/null +++ b/MBS.Framework/Logic/Expressions/VariableExpression.cs @@ -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; + } + } +} diff --git a/MBS.Framework/Logic/Variable.cs b/MBS.Framework/Logic/Variable.cs new file mode 100644 index 0000000..d548309 --- /dev/null +++ b/MBS.Framework/Logic/Variable.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; + +namespace MBS.Framework.Logic +{ + public class Variable + { + public class VariableCollection + : System.Collections.ObjectModel.Collection + { + private Dictionary _itemsByName = new Dictionary(); + 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; + } + } +} diff --git a/MBS.Framework/Logic/VariableRequestedEvent.cs b/MBS.Framework/Logic/VariableRequestedEvent.cs new file mode 100644 index 0000000..21aa994 --- /dev/null +++ b/MBS.Framework/Logic/VariableRequestedEvent.cs @@ -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); +} diff --git a/MBS.Framework/MBS.Framework.csproj b/MBS.Framework/MBS.Framework.csproj index da6beef..8b9f31f 100644 --- a/MBS.Framework/MBS.Framework.csproj +++ b/MBS.Framework/MBS.Framework.csproj @@ -50,6 +50,20 @@ + + + + + + + + + + + + + +