/Internal/ElementEvaluator.cs
C# | 568 lines | 497 code | 66 blank | 5 comment | 67 complexity | 209e61e605e10da0e37fc659181db297 MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Reflection;
- namespace codesticks.parser.Internal
- {
- public class ElementEvaluator
- {
- IDictionary<string, object> mvariables;
- EvalFunctionRepository mfunctions;
- public readonly static string[] mStandardFunctions = new string[] { "+", "-", "/", "*", "=", "==", ">=", "<=", "!=", ">", "<", "!", "if", "?", ":" };
- public enum EvalValue { noresult }
- public static readonly object resultvoid = EvalValue.noresult;
- public ElementEvaluator()
- {
- mvariables = new Dictionary<string, object>();
- }
- public EvalFunctionRepository Functions { get { return mfunctions; } set { mfunctions = value; } }
- public IDictionary<string, object> Variables { get { return mvariables; } set { mvariables = value; } }
- public object Eval(ParsedElement expression)
- {
- object o = BaseProxy(expression);
- return o;
- }
- protected virtual object BaseProxy(ParsedElement expr)
- {
- if (expr.IsCommandEmpty)
- throw ex("Command Empty", expr);
- switch (expr.ElementType)
- {
- case ElementType.Text:
- return evalText(expr);
- case ElementType.Function:
- return evalFunction(expr);
- case ElementType.Number:
- return evalNumber(expr);
- case ElementType.Bool:
- return evalBool(expr);
- case ElementType.None:
- return evalNonInstruction(expr);
- case ElementType.Variable:
- return evalVariableValue(expr);
- case ElementType.Collection:
- return evalGroup(expr);
- default:
- break;
- }
- throw ex("Not Supported Element Type:", expr);
- }
- #region Getters
- protected virtual IComparable getIComparable(ParsedElement expr)
- {
- object o = getObject(expr);
- if (o is IComparable)
- return (IComparable)o;
- throw ex("The Value returned by '{0}' cannot be compered, must be of type IComparable. value: ", expr, o);
- }
- protected virtual double getDouble(ParsedElement expr)
- {
- object o = getObject(expr);
- try
- {
- return Convert.ToDouble(o);
- }
- catch (Exception)
- {
- throw ex("The Value returned by '{0}' is not a valid number, value: {1} ", expr, o);
- }
- }
- protected virtual bool getBool(ParsedElement expr)
- {
- object o = getObject(expr);
- try
- {
- return Convert.ToBoolean(o);
- }
- catch (Exception)
- {
- throw ex("The Value returned by '{0}' is not a valid boolean, value: {1} ", expr, o);
- }
- }
- protected virtual object getObject(ParsedElement expr)
- {
- return BaseProxy(expr);
- }
- #endregion
- #region Standard Evaluators
- protected virtual object evalFunction(ParsedElement expr)
- {
- //Check Build in Function
- if (IsStandardFunction(expr))
- return evalStandardFunction(expr);
- return callFunction(expr);
- }
- protected virtual object evalStandardFunction(ParsedElement expr)
- {
- string cmd = expr.Command;
- switch (cmd)
- {
- case "+":
- Valid(expr, 2, 0);
- return math_plus(getDouble(expr.Get(0)), getDouble(expr.Get(1)));
- case "-":
- Valid(expr, 2, 0);
- return math_subtract(getDouble(expr.Get(0)), getDouble(expr.Get(1)));
- case "/":
- Valid(expr, 2, 0);
- return math_devide(getDouble(expr.Get(0)), getDouble(expr.Get(1)));
- case "*":
- Valid(expr, 2, 0);
- return math_multiply(getDouble(expr.Get(0)), getDouble(expr.Get(1)));
- case "=":
- Valid(expr, 2, 0);
- if (expr.Get(0).ElementType == ElementType.Variable)
- comp_set(expr.Get(0).Command, getObject(expr.Get(1)));
- else
- throw ex("Only variables values can be set. The first argument must be a variable name. Expression: {0}", expr);
- return resultvoid;
- case "==":
- Valid(expr, 2, 0);
- return comp_equal(getObject(expr.Get(0)), getObject(expr.Get(1)));
- case "!=":
- Valid(expr, 2, 0);
- return comp_notequal(getObject(expr.Get(0)), getObject(expr.Get(1)));
- case "<=":
- Valid(expr, 2, 0);
- return comp_smallerequal(getIComparable(expr.Get(0)), getIComparable(expr.Get(1)));
- case ">=":
- Valid(expr, 2, 0);
- return comp_largerequal(getIComparable(expr.Get(0)), getIComparable(expr.Get(1)));
- case "<":
- Valid(expr, 2, 0);
- return comp_smaller(getIComparable(expr.Get(0)), getIComparable(expr.Get(1)));
- case ">":
- Valid(expr, 2, 0);
- return comp_larger(getIComparable(expr.Get(0)), getIComparable(expr.Get(1)));
- case "&&":
- Valid(expr, 2, 0);
- return comp_opand(getBool(expr.Get(0)), getBool(expr.Get(1)));
- case "||":
- Valid(expr, 2, 0);
- return comp_opor(getBool(expr.Get(0)), getBool(expr.Get(1)));
- case "if":
- Valid(expr, 3, 0);
- return comp_branchif(getBool(expr.Get(0)), expr.Get(1), expr.Get(2));
- case "?":
- Valid(expr, 2, 0);
- return comp_branchif(getBool(expr.Get(0)), expr.Get(1));
- case "!":
- Valid(expr, 1, 0);
- return comp_opnot(getBool(expr.Get(0)));
- case ":":
- Valid(expr, 2, 0);
- return new KeyValuePair<object, object>(getObject(expr.Get(0)), getObject(expr.Get(1)));
- default:
- throw ex("{0} Is not a valid build in function.", expr.Command);
- }
- }
- protected virtual object evalNonInstruction(ParsedElement expr)
- {
- if (expr.IsGrouped && (string.Equals(expr.OpeningToken, "[") || string.Equals(expr.OpeningToken, "{")))
- {
- return evalGroup(expr);
- }
- List<object> values = new List<object>();
- foreach (var item in expr.Arguments)
- {
- object o = getObject(item);
- if (!IsResultVoid(o))
- values.Add(o);
- }
- if (values.Count == 0)
- return resultvoid;
- if (values.Count == 1)
- return values[0];
- return values.ToArray();
- }
- protected virtual object evalGroup(ParsedElement expr)
- {
- //List
- if (string.IsNullOrEmpty(expr.OpeningToken))
- return null;
-
- if (expr.OpeningToken.Equals("["))
- {
- List<object> values = new List<object>();
- foreach (var item in expr.Arguments)
- {
- object o = getObject(item);
- if (!IsResultVoid(o))
- values.Add(o);
- }
- return values;
- }
-
- if (expr.OpeningToken.Equals("{"))
- {
- Dictionary<object, object> dict = new Dictionary<object, object>();
- foreach (var item in expr.Arguments)
- {
- object o = getObject(item);
- if (o is KeyValuePair<object, object>)
- {
- KeyValuePair<object, object> kv = (KeyValuePair<object, object>)o;
- dict.Add(kv.Key, kv.Value);
- }
- else
- {
- throw ex("Dictionary Array expects key value pairs to be separated by ':'. {0}", item);
- }
- }
- return dict;
- }
- throw ex("'{0}' Invalid Grouping Item. {1}", expr.OpeningToken, expr);
- }
- protected virtual bool evalBool(ParsedElement expr)
- {
- bool r;
- if (bool.TryParse(expr.Command, out r))
- return r;
- throw ex("The Value '{0}' is not a valid boolean, booleans must either be true or false", expr);
- }
- protected virtual string evalText(ParsedElement expr)
- {
- string text = expr.Command;
- if (text.StartsWith("\"") && text.EndsWith("\"") || text.StartsWith("'") && text.EndsWith("'"))
- text = text.Substring(1, text.Length - 2);
- return text;
- }
- protected virtual double evalNumber(ParsedElement expr)
- {
- double val;
- if (Double.TryParse(expr.Command, out val))
- return val;
- throw ex("The Value '{0}' is not a valid number.", expr.Command);
- }
- protected virtual object evalVariableValue(ParsedElement expr)
- {
- string name = expr.Command;
- return Get(name);
- }
- #endregion
- #region Reflected Functions
- protected virtual object callFunction(ParsedElement expr)
- {
- if (Functions == null)
- ex("Function calls not allowed. Activate buy adding functions to the functionrepository.", expr);
- string cmd = expr.Command;
- EvalFunctionRepository.functionmeta meta = Functions.Get(cmd);
- //Get Methods
- MethodInfo m = meta.info;
- //Set Parameter values
- ParameterInfo[] ps = m.GetParameters();
- List<object> parametervalues = new List<object>();
- for (int i = 0; i < ps.Length; i++)
- {
- if (i < expr.Count)
- {
- parametervalues.Add(Convert.ChangeType(getObject(expr.Arguments[i]), ps[i].ParameterType));
- }
- else
- {
- if (ps[i].IsOptional)
- parametervalues.Add(ps[i].DefaultValue);
- else
- throw new EvaluatorException(string.Format("The Argument '{1}' of function '{0}' is not optional and must be set.", m.Name, ps[i].Name));
- }
- }
- //Call Function
- return m.Invoke(meta.instance, parametervalues.ToArray());
- }
- #endregion
- #region Boolean Operators
- protected virtual void comp_set(string varname, object value)
- {
- Set(varname, value);
- }
- protected virtual bool comp_equal(Object v1, Object v2)
- {
- return v1.Equals(v2);
- }
- protected virtual bool comp_notequal(Object v1, Object v2)
- {
- return !v1.Equals(v2);
- }
- protected virtual bool comp_smallerequal(IComparable v1, IComparable v2)
- {
- return v1.CompareTo(v2) <= 0;
- }
- protected virtual bool comp_largerequal(IComparable v1, IComparable v2)
- {
- return v1.CompareTo(v2) >= 0;
- }
- protected virtual bool comp_smaller(IComparable v1, IComparable v2)
- {
- return v1.CompareTo(v2) < 0;
- }
- protected virtual bool comp_larger(IComparable v1, IComparable v2)
- {
- return v1.CompareTo(v2) > 0;
- }
- protected virtual object comp_branchif(bool condition, ParsedElement KeyValueElement)
- {
- if (!KeyValueElement.CommandEqual(":"))
- throw ex("'?' statement expects ':' separation after condition. Example: condition?true:false");
- KeyValueElement = KeyValueElement.Get(":");
- Valid(KeyValueElement, 2, 0);
- if (condition)
- return getObject(KeyValueElement.Get(0));
- return getObject(KeyValueElement.Get(1));
- }
- protected virtual object comp_branchif(bool condition, ParsedElement path1, ParsedElement path2)
- {
- if (condition)
- return getObject(path1);
- return getObject(path2);
- }
- protected virtual bool comp_opand(bool b1, bool b2)
- {
- return b1 && b2;
- }
- protected virtual bool comp_opor(bool b1, bool b2)
- {
- return b1 || b2;
- }
- protected virtual bool comp_opnot(bool b1)
- {
- return !b1;
- }
- #endregion
- #region Maths
- protected virtual double math_plus(double v1, double v2)
- {
- return v1 + v2;
- }
- protected virtual double math_subtract(double v1, double v2)
- {
- return v1 - v2;
- }
- protected virtual double math_multiply(double v1, double v2)
- {
- return v1 * v2;
- }
- protected virtual double math_devide(double v1, double v2)
- {
- return v1 / v2;
- }
- #endregion
- #region Variable Management
- public void Set(string name, object value)
- {
- if (mvariables.ContainsKey(name))
- mvariables[name] = value;
- else
- mvariables.Add(name, value);
- }
- public object Get(string name)
- {
- if (mvariables.ContainsKey(name))
- return mvariables[name];
- throw ex("Variable '{0}' not defined!", name);
- }
- public object Get(string name, Type astype)
- {
- if (mvariables.ContainsKey(name))
- return Convert.ChangeType(mvariables[name], astype);
- throw ex("Variable '{0}' not defined!");
- }
- #endregion
- #region Function Management
- public void Valid(ParsedElement expr, int requiredparameters, int optionalparameters)
- {
- if (expr.Count < requiredparameters)
- throw ex("{0} Requers atleast {1} parameters.", expr.Command, requiredparameters);
- if (optionalparameters == -1)
- return;
- if (expr.Count > (requiredparameters + optionalparameters))
- throw ex("{0} has too many parameters specified, expecting no more than {1} parameters.", expr.Command, requiredparameters + optionalparameters);
- }
- public bool IsStandardFunction(ParsedElement expr)
- {
- if (mStandardFunctions.Contains(expr.Command))
- return true;
- return false;
- }
- #endregion
- #region helpers
- public bool IsResultVoid(object o)
- {
- if (object.ReferenceEquals(o, resultvoid))
- return true;
- return false;
- }
- Exception ex(string format, params object[] args)
- {
- return new EvaluatorException(string.Format(format, args));
- }
- #endregion
- }
- public class EvalFunctionRepository
- {
- Dictionary<string, functionmeta> mfunctions;
- public class functionmeta { public MethodInfo info; public object instance;}
- public EvalFunctionRepository()
- {
- mfunctions = new Dictionary<string, functionmeta>();
- }
- public void Clear()
- {
- mfunctions.Clear();
- }
- public void RegisterFunctions(object functionclass)
- {
- if (functionclass == null)
- throw new ArgumentNullException("functionclass");
- Type ctype = functionclass.GetType();
- MethodInfo[] funcs = ctype.GetMethods();
- foreach (var f in funcs)
- {
- RegisterFunction(f, functionclass);
- }
- }
- public void RegisterFunctions(Type functionclass)
- {
- if (functionclass == null)
- throw new ArgumentNullException("functionclass");
- MethodInfo[] funcs = functionclass.GetMethods();
- foreach (var f in funcs)
- {
- RegisterFunction(f, null);
- }
- }
- public void RegisterFunction(string functionname, object functionclass)
- {
- if (functionclass == null)
- throw new ArgumentNullException("functionclass");
- Type ctype = functionclass.GetType();
- MethodInfo func = ctype.GetMethod(functionname);
- if (func == null)
- ex("Function {0} coult not be found in type {1}", functionname, ctype);
- RegisterFunction(functionname, func, functionclass);
- }
- public void RegisterFunction(string functionname, Type functionclass)
- {
- if (functionclass == null)
- throw new ArgumentNullException("functionclass");
- MethodInfo func = functionclass.GetMethod(functionname);
- if (func == null)
- ex("Function {0} coult not be found in type {1}", functionname, functionclass);
- RegisterFunction(functionname, func, functionclass);
- }
- public void RegisterFunction(string name, string functionname, object functionclass)
- {
- if (functionclass == null)
- throw new ArgumentNullException("functionclass");
- Type ctype = functionclass.GetType();
- MethodInfo func = ctype.GetMethod(functionname);
- if (func == null)
- ex("Function {0} coult not be found in type {1}", functionname, ctype);
- RegisterFunction(name, func, functionclass);
- }
- public void RegisterFunction(string name, string functionname, Type functionclass)
- {
- if (functionclass == null)
- throw new ArgumentNullException("functionclass");
- MethodInfo func = functionclass.GetMethod(functionname);
- if (func == null)
- ex("Function {0} coult not be found in type {1}", functionname, functionclass);
- RegisterFunction(name, func, functionclass);
- }
- public void RegisterFunction(MethodInfo info, object instance)
- {
- RegisterFunction(info.Name, info, instance);
- }
- public void RegisterFunction(string name, MethodInfo info, object instance)
- {
- functionmeta meta = new functionmeta() { info = info, instance = instance };
- if (mfunctions.ContainsKey(name))
- ex("Function {0} is already registered.", name);
- mfunctions.Add(name, meta);
- }
- public void UnRegister(string name)
- {
- mfunctions.Remove(name);
- }
- public functionmeta Get(string name)
- {
- return getfunction(name);
- }
- functionmeta getfunction(string name)
- {
- if (mfunctions.ContainsKey(name))
- return mfunctions[name];
- throw ex("Function '{0}' not found, make sure spelling and case is correct.", name);
- }
- #region helpers
- Exception ex(string format, params object[] args)
- {
- return new EvaluatorException(string.Format(format, args));
- }
- #endregion
- }
- }