diff --git a/src/Generator/Library.cs b/src/Generator/Library.cs
index 8317cede..a720e382 100644
--- a/src/Generator/Library.cs
+++ b/src/Generator/Library.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
+using CodingSeb.ExpressionEvaluator;
using CppSharp.AST;
using CppSharp.Generators;
using CppSharp.Passes;
diff --git a/src/Generator/Utils/ExpressionEvaluator.cs b/src/Generator/Utils/ExpressionEvaluator.cs
index b0fdb8bb..4e6937a0 100644
--- a/src/Generator/Utils/ExpressionEvaluator.cs
+++ b/src/Generator/Utils/ExpressionEvaluator.cs
@@ -1,1468 +1,4250 @@
-using System;
+/******************************************************************************************************
+ Title : ExpressionEvaluator (https://github.com/codingseb/ExpressionEvaluator)
+ Version : 1.4.16.0
+ (if last digit (the forth) is not a zero, the version is an intermediate version and can be unstable)
+
+ Author : Coding Seb
+ Licence : MIT (https://github.com/codingseb/ExpressionEvaluator/blob/master/LICENSE.md)
+*******************************************************************************************************/
+
+using System;
+using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
+using System.Dynamic;
using System.Globalization;
using System.Linq;
using System.Reflection;
-using System.Runtime.Serialization;
-using System.Security.Permissions;
+using System.Runtime.InteropServices;
+using System.Text;
using System.Text.RegularExpressions;
-///
-/// This class allow to evaluate a string math or pseudo C# expression
-///
-internal class ExpressionEvaluator
+namespace CodingSeb.ExpressionEvaluator
{
- private static Regex varOrFunctionRegEx = new Regex(@"^(?(?[?])?\.)?(?[a-zA-Z_][a-zA-Z0-9_]*)\s*(?[(])?", RegexOptions.IgnoreCase);
- private static Regex numberRegex = new Regex(@"^(?[+-])?\d+(?\.?\d+(e[+-]?\d+)?)?(?ul|[fdulm])?", RegexOptions.IgnoreCase);
- private static Regex stringBeginningRegex = new Regex("^(?[$])?(?[@])?[\"]");
- private static Regex castRegex = new Regex(@"^\(\s*(?[a-zA-Z_][a-zA-Z0-9_\.\[\]<>]*[?]?)\s*\)");
- private static Regex indexingBeginningRegex = new Regex(@"^[?]?\[");
- private static Regex primaryTypesRegex = new Regex(@"(?<=^|[^a-zA-Z_])(?object|string|bool[?]?|byte[?]?|char[?]?|decimal[?]?|double[?]?|short[?]?|int[?]?|long[?]?|sbyte[?]?|float[?]?|ushort[?]?|uint[?]?|void)(?=[^a-zA-Z_]|$)");
- private static Regex endOfStringWithDollar = new Regex("^[^\"{]*[\"{]");
- private static Regex endOfStringWithoutDollar = new Regex("^[^\"]*[\"]");
- private static Regex endOfStringInterpolationRegex = new Regex("^[^}\"]*[}\"]");
- private static Regex stringBeginningForEndBlockRegex = new Regex("[$]?[@]?[\"]$");
- private static Regex lambdaExpressionRegex = new Regex(@"^\s*(?(\s*[(]\s*([a-zA-Z_][a-zA-Z0-9_]*\s*([,]\s*[a-zA-Z_][a-zA-Z0-9_]*\s*)*)?[)])|[a-zA-Z_][a-zA-Z0-9_]*)\s*=>(?.*)$");
- private static Regex lambdaArgRegex = new Regex(@"[a-zA-Z_][a-zA-Z0-9_]*");
-
- private static BindingFlags instanceBindingFlag = (BindingFlags.Default | BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
- private static BindingFlags staticBindingFlag = (BindingFlags.Default | BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Static);
-
- private static Dictionary PrimaryTypesDict = new Dictionary()
- {
- { "object", typeof(object) },
- { "string", typeof(string) },
- { "bool", typeof(bool) },
- { "bool?", typeof(bool?) },
- { "byte", typeof(byte) },
- { "byte?", typeof(byte?) },
- { "char", typeof(char) },
- { "char?", typeof(char?) },
- { "decimal", typeof(decimal) },
- { "decimal?", typeof(decimal?) },
- { "double", typeof(double) },
- { "double?", typeof(double?) },
- { "short", typeof(short) },
- { "short?", typeof(short?) },
- { "int", typeof(int) },
- { "int?", typeof(int?) },
- { "long", typeof(long) },
- { "long?", typeof(long?) },
- { "sbyte", typeof(sbyte) },
- { "sbyte?", typeof(sbyte?) },
- { "float", typeof(float) },
- { "float?", typeof(float?) },
- { "ushort", typeof(ushort) },
- { "ushort?", typeof(ushort?) },
- { "uint", typeof(uint) },
- { "uint?", typeof(uint?) },
- { "ulong", typeof(ulong) },
- { "ulong?", typeof(ulong?) },
- { "void", typeof(void) }
- };
-
- private static Dictionary> numberSuffixToParse = new Dictionary>()
- {
- { "f", number => float.Parse(number, NumberStyles.Any, CultureInfo.InvariantCulture) },
- { "d", number => double.Parse(number, NumberStyles.Any, CultureInfo.InvariantCulture) },
- { "u", number => uint.Parse(number, NumberStyles.Any, CultureInfo.InvariantCulture) },
- { "l", number => long.Parse(number, NumberStyles.Any, CultureInfo.InvariantCulture) },
- { "ul", number => ulong.Parse(number, NumberStyles.Any, CultureInfo.InvariantCulture) },
- { "m", number => decimal.Parse(number, NumberStyles.Any, CultureInfo.InvariantCulture) }
- };
-
- private static Dictionary stringEscapedCharDict = new Dictionary()
- {
- { '\\', @"\" },
- { '"', "\"" },
- { '0', "\0" },
- { 'a', "\a" },
- { 'b', "\b" },
- { 'f', "\f" },
- { 'n', "\n" },
- { 'r', "\r" },
- { 't', "\t" },
- { 'v', "\v" }
- };
-
- private enum ExpressionOperator
- {
- Plus,
- Minus,
- Multiply,
- Divide,
- Modulo,
- Lower,
- Greater,
- Equal,
- LowerOrEqual,
- GreaterOrEqual,
- Is,
- NotEqual,
- LogicalNegation,
- ConditionalAnd,
- ConditionalOr,
- LogicalAnd,
- LogicalOr,
- LogicalXor,
- ShiftBitsLeft,
- ShiftBitsRight,
- NullCoalescing,
- Cast,
- Indexing,
- IndexingWithNullConditional,
- }
-
- private static Dictionary operatorsDictionary = new Dictionary(StringComparer.OrdinalIgnoreCase)
- {
- { "+", ExpressionOperator.Plus },
- { "-", ExpressionOperator.Minus },
- { "*", ExpressionOperator.Multiply },
- { "/", ExpressionOperator.Divide },
- { "%", ExpressionOperator.Modulo },
- { "<", ExpressionOperator.Lower },
- { ">", ExpressionOperator.Greater },
- { "<=", ExpressionOperator.LowerOrEqual },
- { ">=", ExpressionOperator.GreaterOrEqual },
- { "is", ExpressionOperator.Is },
- { "==", ExpressionOperator.Equal },
- { "<>", ExpressionOperator.NotEqual },
- { "!=", ExpressionOperator.NotEqual },
- { "&&", ExpressionOperator.ConditionalAnd },
- { "||", ExpressionOperator.ConditionalOr },
- { "!", ExpressionOperator.LogicalNegation },
- { "&", ExpressionOperator.LogicalAnd },
- { "|", ExpressionOperator.LogicalOr },
- { "^", ExpressionOperator.LogicalXor },
- { "<<", ExpressionOperator.ShiftBitsLeft },
- { ">>", ExpressionOperator.ShiftBitsRight },
- { "??", ExpressionOperator.NullCoalescing },
- };
-
- private static Dictionary leftOperandOnlyOperatorsEvaluationDictionary = new Dictionary()
+ ///
+ /// This class allow to evaluate a string math or pseudo C# expression
+ ///
+ public partial class ExpressionEvaluator
{
- };
+ #region Regex declarations
+
+ protected const string primaryTypesRegexPattern = @"(?<=^|[^\p{L}_])(?object|string|bool[?]?|byte[?]?|char[?]?|decimal[?]?|double[?]?|short[?]?|int[?]?|long[?]?|sbyte[?]?|float[?]?|ushort[?]?|uint[?]?|ulong[?]?|void)(?=[^a-zA-Z_]|$)";
+
+ protected static readonly Regex varOrFunctionRegEx = new Regex(@"^((?[+-])|(?[+][+]|--)|(?var)\s+|(?dynamic)\s+|(?(?[?])?\.)?)(?[\p{L}_](?>[\p{L}_0-9]*))(?>\s*)((?(?[+\-*/%&|^]|<<|>>|\?\?)?=(?![=>]))|(?([+][+]|--)(?![\p{L}_0-9]))|((?[<](?>([\p{L}_](?>[\p{L}_0-9]*)|(?>\s+)|[,\.])+|(?[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?(?[(])?))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
+
+ protected const string numberRegexOrigPattern = @"^(?[+-])?([0-9][0-9_{1}]*[0-9]|\d)(?{0}?([0-9][0-9_]*[0-9]|\d)(e[+-]?([0-9][0-9_]*[0-9]|\d))?)?(?ul|[fdulm])?";
+ protected string numberRegexPattern;
+
+ protected static readonly Regex otherBasesNumberRegex = new Regex("^(?[+-])?(?0(?x)([0-9a-f][0-9a-f_]*[0-9a-f]|[0-9a-f])|0(?b)([01][01_]*[01]|[01]))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
+ protected static readonly Regex stringBeginningRegex = new Regex("^(?[$])?(?[@])?[\"]", RegexOptions.Compiled);
+ protected static readonly Regex internalCharRegex = new Regex(@"^['](\\[\\'0abfnrtv]|[^'])[']", RegexOptions.Compiled);
+ protected static readonly Regex indexingBeginningRegex = new Regex(@"^[?]?\[", RegexOptions.Compiled);
+ protected static readonly Regex assignationOrPostFixOperatorRegex = new Regex(@"^(?>\s*)((?[+\-*/%&|^]|<<|>>|\?\?)?=(?![=>])|(?([+][+]|--)(?![\p{L}_0-9])))");
+ protected static readonly Regex genericsDecodeRegex = new Regex("(?[^,<>]+)(?[<](?>[^<>]+|(?[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?", RegexOptions.Compiled);
+ protected static readonly Regex genericsEndOnlyOneTrim = new Regex(@"(?>\s*)[>](?>\s*)$", RegexOptions.Compiled);
+
+ protected static readonly Regex endOfStringWithDollar = new Regex("^([^\"{\\\\]|\\\\[\\\\\"0abfnrtv])*[\"{]", RegexOptions.Compiled);
+ protected static readonly Regex endOfStringWithoutDollar = new Regex("^([^\"\\\\]|\\\\[\\\\\"0abfnrtv])*[\"]", RegexOptions.Compiled);
+ protected static readonly Regex endOfStringWithDollarWithAt = new Regex("^[^\"{]*[\"{]", RegexOptions.Compiled);
+ protected static readonly Regex endOfStringWithoutDollarWithAt = new Regex("^[^\"]*[\"]", RegexOptions.Compiled);
+ protected static readonly Regex endOfStringInterpolationRegex = new Regex("^('\"'|[^}\"])*[}\"]", RegexOptions.Compiled);
+ protected static readonly Regex stringBeginningForEndBlockRegex = new Regex("[$]?[@]?[\"]$", RegexOptions.Compiled);
+ protected static readonly Regex lambdaExpressionRegex = new Regex(@"^(?>\s*)(?((?>\s*)[(](?>\s*)([\p{L}_](?>[\p{L}_0-9]*)(?>\s*)([,](?>\s*)[\p{L}_][\p{L}_0-9]*(?>\s*))*)?[)])|[\p{L}_](?>[\p{L}_0-9]*))(?>\s*)=>(?.*)$", RegexOptions.Singleline | RegexOptions.Compiled);
+ protected static readonly Regex lambdaArgRegex = new Regex(@"[\p{L}_](?>[\p{L}_0-9]*)", RegexOptions.Compiled);
+ protected static readonly Regex initInNewBeginningRegex = new Regex(@"^(?>\s*){", RegexOptions.Compiled);
+
+ // Depending on OptionInlineNamespacesEvaluationActive. Initialized in constructor
+ protected string InstanceCreationWithNewKeywordRegexPattern { get { return @"^new(?>\s*)((?[{{])|((?[\p{L}_][\p{L}_0-9"+ (OptionInlineNamespacesEvaluationActive ? @"\." : string.Empty) + @"]*)(?>\s*)(?[<](?>[^<>]+|(?[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?(?>\s*)((?[(])|(?\[)|(?[{{]))?))"; } }
+ protected string CastRegexPattern { get { return @"^\((?>\s*)(?[\p{L}_][\p{L}_0-9"+ (OptionInlineNamespacesEvaluationActive ? @"\." : string.Empty) + @"\[\]<>]*[?]?)(?>\s*)\)"; } }
+
+ // To remove comments in scripts based on https://stackoverflow.com/questions/3524317/regex-to-strip-line-comments-from-c-sharp/3524689#3524689
+ protected const string blockComments = @"/\*(.*?)\*/";
+ protected const string lineComments = @"//[^\r\n]*";
+ protected const string stringsIgnore = @"""((\\[^\n]|[^""\n])*)""";
+ protected const string verbatimStringsIgnore = @"@(""[^""]*"")+";
+ protected static readonly Regex removeCommentsRegex = new Regex($"{blockComments}|{lineComments}|{stringsIgnore}|{verbatimStringsIgnore}", RegexOptions.Singleline | RegexOptions.Compiled);
+ protected static readonly Regex newLineCharsRegex = new Regex(@"\r\n|\r|\n", RegexOptions.Compiled);
+
+ // For script only
+ protected static readonly Regex blockKeywordsBeginningRegex = new Regex(@"^(?>\s*)(?while|for|foreach|if|else(?>\s*)if|catch)(?>\s*)[(]", RegexOptions.IgnoreCase | RegexOptions.Compiled);
+ protected static readonly Regex foreachParenthisEvaluationRegex = new Regex(@"^(?>\s*)(?[\p{L}_](?>[\p{L}_0-9]*))(?>\s*)(?in)(?>\s*)(?.*)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
+ protected static readonly Regex blockKeywordsWithoutParenthesesBeginningRegex = new Regex(@"^(?>\s*)(?else|do|try|finally)(?![\p{L}_0-9])", RegexOptions.IgnoreCase | RegexOptions.Compiled);
+ protected static readonly Regex blockBeginningRegex = new Regex(@"^(?>\s*)[{]", RegexOptions.Compiled);
+ protected static readonly Regex returnKeywordRegex = new Regex(@"^return((?>\s*)|\()", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
+ protected static readonly Regex nextIsEndOfExpressionRegex = new Regex(@"^(?>\s*)[;]", RegexOptions.Compiled);
+
+ #endregion
+
+ #region enums (if else blocks states)
+
+ protected enum IfBlockEvaluatedState
+ {
+ NoBlockEvaluated,
+ If,
+ ElseIf
+ }
- private static Dictionary rightOperandOnlyOperatorsEvaluationDictionary = new Dictionary()
- {
- {ExpressionOperator.LogicalNegation, true }
- };
+ protected enum TryBlockEvaluatedState
+ {
+ NoBlockEvaluated,
+ Try,
+ Catch
+ }
- private static List>> operatorsEvaluations =
- new List>>()
- {
- new Dictionary>()
- {
- {ExpressionOperator.Indexing, (dynamic left, dynamic right) => left[right] },
- {ExpressionOperator.IndexingWithNullConditional, (dynamic left, dynamic right) => left?[right] },
- },
- new Dictionary>()
- {
- {ExpressionOperator.LogicalNegation, (dynamic left, dynamic right) => !right },
- {ExpressionOperator.Cast, (dynamic left, dynamic right) => ChangeType(right, left) },
- },
- new Dictionary>()
- {
- {ExpressionOperator.Multiply, (dynamic left, dynamic right) => left * right },
- {ExpressionOperator.Divide, (dynamic left, dynamic right) => left / right },
- {ExpressionOperator.Modulo, (dynamic left, dynamic right) => left % right },
- },
- new Dictionary>()
- {
- {ExpressionOperator.Plus, (dynamic left, dynamic right) => left + right },
- {ExpressionOperator.Minus, (dynamic left, dynamic right) => left - right },
- },
- new Dictionary>()
- {
- {ExpressionOperator.ShiftBitsLeft, (dynamic left, dynamic right) => left << right },
- {ExpressionOperator.ShiftBitsRight, (dynamic left, dynamic right) => left >> right },
- },
- new Dictionary>()
- {
- {ExpressionOperator.Lower, (dynamic left, dynamic right) => left < right },
- {ExpressionOperator.Greater, (dynamic left, dynamic right) => left > right },
- {ExpressionOperator.LowerOrEqual, (dynamic left, dynamic right) => left <= right },
- {ExpressionOperator.GreaterOrEqual, (dynamic left, dynamic right) => left >= right },
- {ExpressionOperator.Is, (dynamic left, dynamic right) => ((Type)right).IsAssignableFrom(left.GetType()) },
- },
- new Dictionary>()
- {
- {ExpressionOperator.Equal, (dynamic left, dynamic right) => left == right },
- {ExpressionOperator.NotEqual, (dynamic left, dynamic right) => left != right },
- },
- new Dictionary>()
- {
- {ExpressionOperator.LogicalAnd, (dynamic left, dynamic right) => left & right },
- },
- new Dictionary>()
- {
- {ExpressionOperator.LogicalXor, (dynamic left, dynamic right) => left ^ right },
- },
- new Dictionary>()
- {
- {ExpressionOperator.LogicalOr, (dynamic left, dynamic right) => left | right },
- },
- new Dictionary>()
- {
- {ExpressionOperator.ConditionalAnd, (dynamic left, dynamic right) => left && right },
- },
- new Dictionary>()
- {
- {ExpressionOperator.ConditionalOr, (dynamic left, dynamic right) => left || right },
- },
- new Dictionary>()
- {
- {ExpressionOperator.NullCoalescing, (dynamic left, dynamic right) => left ?? right },
- },
- };
-
- private static Dictionary defaultVariables = new Dictionary(StringComparer.OrdinalIgnoreCase)
- {
- { "pi", Math.PI },
- { "e", Math.E },
- { "null", null},
- { "true", true },
- { "false", false },
- };
-
- private static Dictionary> simpleDoubleMathFuncsDictionary = new Dictionary>()
- {
- { "abs", Math.Abs },
- { "acos", Math.Acos },
- { "asin", Math.Asin },
- { "atan", Math.Atan },
- { "ceiling", Math.Ceiling },
- { "cos", Math.Cos },
- { "cosh", Math.Cosh },
- { "exp", Math.Exp },
- { "floor", Math.Floor },
- { "log10", Math.Log10 },
- { "sin", Math.Sin },
- { "sinh", Math.Sinh },
- { "sqrt", Math.Sqrt },
- { "tan", Math.Tan },
- { "tanh", Math.Tanh },
- { "truncate", Math.Truncate },
- };
-
- private static Dictionary> doubleDoubleMathFuncsDictionary = new Dictionary>()
- {
- { "atan2", Math.Atan2 },
- { "ieeeremainder", Math.IEEERemainder },
- { "log", Math.Log },
- { "pow", Math.Pow },
- };
+ #endregion
- private static Dictionary, object>> complexStandardFuncsDictionary = new Dictionary, object>>()
- {
- { "array", (self, args) => args.ConvertAll(arg => self.Evaluate(arg)).ToArray() },
- { "avg", (self, args) => args.ConvertAll(arg => Convert.ToDouble(self.Evaluate(arg))).Sum() / args.Count },
- { "default", (self, args) => { Type type = (self.Evaluate(args[0]) as Type);
- return(type != null && type.IsValueType ? Activator.CreateInstance(type): null); } },
- { "if", (self, args) => (bool)self.Evaluate(args[0]) ? self.Evaluate(args[1]) : self.Evaluate(args[2]) },
- { "in", (self, args) => args.Skip(1).ToList().ConvertAll(arg => self.Evaluate(arg)).Contains(self.Evaluate(args[0])) },
- { "list", (self, args) => args.ConvertAll(arg => self.Evaluate(arg)) },
- { "max", (self, args) => args.ConvertAll(arg => Convert.ToDouble(self.Evaluate(arg))).Max() },
- { "min", (self, args) => args.ConvertAll(arg => Convert.ToDouble(self.Evaluate(arg))).Min() },
- { "new", (self, args) => { List