-
Notifications
You must be signed in to change notification settings - Fork 99
Advanced Customization and Hacking
From version 1.4.0.0 ExpressionEvaluator allow some deeper customizations of the parsing process. It is mostly available by inheritance. Most of the ExpressionEvaluator class is now in protected visibility in place of private and the majority of init and parsing methods are now virtual.
This section show some of these hacks.
Warning : all uses of these inheritance hacks are at your own risk.
It's your responsability to avoid unwanted conflicts between the different parts of the parsing and evaluating process.
Also be aware that these stuff will be more sensitive to future versions changes of ExpressionEvaluator than the other parts of this wiki
For left only, right only and 2 operands operators. (For more advanced stuff look how to redefine parsing process)
The following example show how to replace the C# logical operators &&
and ||
by the corresponding literals operators and
and or
:
Inherits ExpressionEvaluator
public class XExpressionEvaluator : ExpressionEvaluator
{
protected override void Init()
{
operatorsDictionary.Add("and", ExpressionOperator.ConditionalAnd);
operatorsDictionary.Add("or", ExpressionOperator.ConditionalOr);
operatorsDictionary.Remove("&&");
operatorsDictionary.Remove("||");
}
}
And use it like this
ExpressionEvaluator evaluator = new XExpressionEvaluator();
evaluator.Evaluate(expression);
Results :
true and true
true
true and false
false
false and true
true
false and false
false
true && true
throw an exception
true or true
true
true or false
true
false or true
true
false or false
false
true || true
throw an exception
Remark : Some operators need to be parsed an other way and are not in operatorsDictionary
so they can't be redefined this way.
No exaustive examples condition ? expIfTrue : expIfFalse
, (Type)variableToCast
or nullVariable ?? other variable
For left only, right only and 2 operands operators. (For more advanced stuff look how to redefine parsing process)
The following example show how to add 2 new operators :
- A
#
operator to apply after a numerical value that elevate to the power of minus itself. - A
love
operator that do a binary or (|
) of 2 values and and a 1 binary left shift<<
Inherits ExpressionOperator to define new operators
public class XExpressionOperator : ExpressionOperator
{
public static readonly ExpressionOperator Sharp = new XExpressionOperator();
public static readonly ExpressionOperator Love = new XExpressionOperator();
}
Inherits ExpressionEvaluator to define operators priorities and implementation
public class XExpressionEvaluator : ExpressionEvaluator
{
protected new static readonly IList<ExpressionOperator> leftOperandOnlyOperatorsEvaluationDictionary =
ExpressionEvaluator.leftOperandOnlyOperatorsEvaluationDictionary
.ToList()
.FluidAdd(XExpressionOperator.Sharp);
//protected new static readonly IList<ExpressionOperator> rightOperandOnlyOperatorsEvaluationDictionary =
// ExpressionEvaluator.rightOperandOnlyOperatorsEvaluationDictionary
// .ToList();
protected new static readonly IList<IDictionary<ExpressionOperator, Func<dynamic, dynamic, object>>> operatorsEvaluations =
ExpressionEvaluator.operatorsEvaluations
.Copy()
.AddOperatorEvaluationAtNewLevelAfter(XExpressionOperator.Sharp, (left, _) => Math.Pow(left, -left), ExpressionOperator.UnaryPlus)
.AddOperatorEvaluationAtLevelOf(XExpressionOperator.Love, (left, right) => (left | right) << 1, ExpressionOperator.ShiftBitsLeft);
protected override IList<ExpressionOperator> LeftOperandOnlyOperatorsEvaluationDictionary => leftOperandOnlyOperatorsEvaluationDictionary;
// protected override IList<ExpressionOperator> RightOperandOnlyOperatorsEvaluationDictionary => rightOperandOnlyOperatorsEvaluationDictionary;
protected override IList<IDictionary<ExpressionOperator, Func<dynamic, dynamic, object>>> OperatorsEvaluations => operatorsEvaluations;
protected override void Init()
{
operatorsDictionary.Add("#", XExpressionOperator.Sharp);
operatorsDictionary.Add("love", XExpressionOperator.Love);
}
}
And use it like this
ExpressionEvaluator evaluator = new XExpressionEvaluator();
evaluator.Evaluate(expression);
Results :
1#
1
2#
0.25
-4# - 6
250
1 love 2
6
1 love 2 >> 1
3
The following example show how to add 2 new complex operators (or syntax) :
- A ternary operator that do a
string.Replace
likeinput ° replace @ replacement
- A syntax to declare inline
DateTime
objects like#year-month-day
->2019-08-15
Inherits ExpressionEvaluator to implement some parsing methods and add them to the ParsingMethods
List
public class XExpressionEvaluator : ExpressionEvaluator
{
protected override void Init()
{
ParsingMethods.Insert(0, EvaluateDateTimeSyntax);
ParsingMethods.Add(EvaluateSpecialTernaryOperator);
}
/// <summary>
/// To evaluate DateTimes objects with #year-month-day syntax (#2019-05-28)
/// </summary>
protected virtual bool EvaluateDateTimeSyntax(string expression, Stack<object> stack, ref int i)
{
Match match = Regex.Match(expression.Substring(i), @"^\s*#(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})");
if(match.Success)
{
int year = int.Parse(match.Groups["year"].Value);
int month = int.Parse(match.Groups["month"].Value);
int day = int.Parse(match.Groups["day"].Value);
DateTime dateTime = new DateTime(year,month, day);
stack.Push(dateTime);
i += match.Length - 1;
return true;
}
return false;
}
/// <summary>
/// To evaluate a string replace with custom ternary indicator
/// </summary>
protected virtual bool EvaluateSpecialTernaryOperator(string expression, Stack<object> stack, ref int i)
{
if (expression.Substring(i, 1).Equals("°"))
{
string input = (string)ProcessStack(stack);
string restOfExpression = expression.Substring(i + 1);
for (int j = 0; j < restOfExpression.Length; j++)
{
string s2 = restOfExpression.Substring(j, 1);
Match internalStringMatch = stringBeginningRegex.Match(restOfExpression.Substring(j));
if (internalStringMatch.Success)
{
string innerString = internalStringMatch.Value + GetCodeUntilEndOfString(restOfExpression.Substring(j + internalStringMatch.Length), internalStringMatch);
j += innerString.Length - 1;
}
else if (s2.Equals("("))
{
j++;
GetExpressionsBetweenParenthesesOrOtherImbricableBrackets(restOfExpression, ref j, false);
}
else if (s2.Equals("@"))
{
stack.Clear();
stack.Push(input.Replace(Evaluate<string>(restOfExpression.Substring(1, j - 1)), Evaluate<string>(restOfExpression.Substring(j + 1))));
i = expression.Length;
return true;
}
}
}
return false;
}
}
And use it like this
ExpressionEvaluator evaluator = new XExpressionEvaluator();
evaluator.Evaluate(expression);
Results :
"A sentence where a word must be replaced where it is" ° "replaced" @ "kept"
A sentence where a word must be kept where it is
#1985-09-11.Year
1985
#1985-09-11.Month
9
#1985-09-11.Day
11
#1985-09-11.Equals(new DateTime(1985,9,11))
true
- Getting Started
- Variables and Functions
- Operators and Keywords
- C# Types Management
- ExpandoObject
- Code Comments Management
- Advanced Customization and Hacking
- Caching
-
Options
- CultureInfoForNumberParsing
- OptionCaseSensitiveEvaluationActive
- OptionVariablesPersistenceCustomComparer
- OptionFluidPrefixingActive
- OptionForceIntegerNumbersEvaluationsAsDoubleByDefault
- OptionNumberParsingDecimalSeparator
- OptionNumberParsingThousandSeparator
- OptionFunctionArgumentsSeparator
- OptionInitializersSeparator
- OptionInlineNamespacesEvaluationRule
- OptionNewFunctionEvaluationActive
- OptionNewKeywordEvaluationActive
- OptionStaticMethodsCallActive
- OptionStaticProperiesGetActive
- OptionInstanceMethodsCallActive
- OptionInstanceProperiesGetActive
- OptionIndexingActive
- OptionStringEvaluationActive
- OptionCharEvaluationActive
- OptionEvaluateFunctionActive
- OptionVariableAssignationActive
- OptionPropertyOrFieldSetActive
- OptionIndexingAssignationActive
- OptionScriptEvaluateFunctionActive
- OptionOnNoReturnKeywordFoundInScriptAction
- OptionScriptNeedSemicolonAtTheEndOfLastExpression
- OptionAllowNonPublicMembersAccess
- Todo List