/// <summary> /// Constant terms are negated immediately. /// </summary> private ExpressionTreeNode <TIn> _VisitNegate <TIn>(ExpressionTreeNode <TIn> left) { // Always apply Negate to path values if (left is PathValueExpression <TIn> ) { return new NegateExpression <TIn> { Root = left } } ; if (left is ValueExpression <TIn> value && value.Value != null) { // Fold. var negatedValue = _Negate(value.Value); if (negatedValue != null) { return(new ValueExpression <TIn> { Value = negatedValue }); } } // Always apply Negate to anything other than a negatable value return(new NegateExpression <TIn> { Root = left }); }
/// <summary> /// Generates the contents (properties and methods) for the class that defines the parser rule. /// </summary> /// <param name="match">Current parse tree node</param> private void EnterRuleBody(ITextParseTreeNode match) { ruleBodyExpression = new SequenceExpression(); output.WriteLine(" : TextProductionRule"); output.WriteLine("{"); WriteExcludedGlobalRules(); WriteRuleNameProperty(); output.WriteLine("protected override IParserRule<char> GetBody()"); output.WriteLine("{"); base.Enter(match); output.WriteLine("return"); ruleBodyExpression.Visit( new CodeGenVisitor(grammarName, output)); output.WriteLine(";"); output.WriteLine("}"); }
/// <summary> /// Adds alternate expression (Rule1 | Rule2) to the expression tree for the current rule. /// </summary> /// <param name="match">Current parse tree node</param> private void EnterAlternate(ITextParseTreeNode match) { /* Alternate expressions are parsed like this: * * Rule1 | Rule2 | Rule3 * * RuleName (Rule1) * AlternateExpression * -RuleName (Rule2) * -AlternateExpression * --RuleName (Rule3) */ if (ruleBodyExpression is OneOfExpression) { // Already alternating, just add to children base.Enter(match); } else { // Start new alternate with previous expression var previousExpression = ruleBodyExpression.RemoveLastChild(); var alternateExpression = new OneOfExpression(); alternateExpression.AddChild(previousExpression); ruleBodyExpression.AddChild(alternateExpression); ruleBodyExpression = alternateExpression; base.Enter(match); ruleBodyExpression = ruleBodyExpression.Parent; } }
private void SetSelectedExpression(ExpressionTreeNode selectedExpression) { var comparisonNode = selectedExpression as ComparisonOperatorNode; if (comparisonNode != null) { var fieldLeaf = comparisonNode.Left as ExpressionTreeFieldLeaf; if (fieldLeaf != null) { var foundFieldDescr = FilterableArguments.FirstOrDefault( prop => prop.BoundProperty.Equals(fieldLeaf.PropertyDescription)); if (foundFieldDescr != null) { var newAvailableComparisonOperators = new LocalizableEnumItemsSource(); newAvailableComparisonOperators.Initialize(typeof(ComparisonOperators), foundFieldDescr.AvailableOperators.Cast <object>()); AvailableComparisonOperators = newAvailableComparisonOperators; //Set available values for expression if (foundFieldDescr.HasAvailableValues) { var valueLeaf = comparisonNode.Right as ExpressionTreeValueLeaf; if (valueLeaf != null) { valueLeaf.AvailableValues = _filterableCollection.GetExpressionAvailableValues(foundFieldDescr.BoundProperty); } } } } SelectedComparisonOperator = comparisonNode.Operator; } }
public bool TryCreateExpressionTreeNode <TIn>([NotNullWhen(true)] out ExpressionTreeNode <TIn> root, [NotNullWhen(false)] out string errorMessage) { if (Output.Count != 1) { root = null !; errorMessage = "No expression to parse."; return(false); } if (Operators.Count > 0) { root = null !; errorMessage = "Unbalanced expression."; return(false); } var first = Output.Pop(); if (first == null) { root = null !; errorMessage = "No expression found."; return(false); } var node = _Visit <TIn>(first); root = _MakeHasPropertyIfNameExpression(node); errorMessage = null !; return(true); }
/// <summary> /// Converts specified Token Stack into an expression tree. /// </summary> /// <param name="tokens">Token representation of a logical expression.</param> /// <returns></returns> public ExpressionTreeNode BuildExpressionTree(Stack <IToken> tokens) { Stack <IToken> reverseTokens = new Stack <IToken>(tokens); ExpressionTreeNode root = GenerateNode(reverseTokens); return(root); }
private static void Evaluate(ExpressionTreeNode node, OperandStack operandStack, IBackingStore backingStore) { var token = node.Token; if (token.TokenType == TokenType.Operand) { operandStack.Push((IOperand)token); } else { var op = ((OperatorWrapper)token).WrappedOperator; if (op.ShortCircuit == ShortCircuitMode.LogicalAnd) { Evaluate(node.Children[1], operandStack, backingStore); var thing = OperatorActions.PeekAndResolve(operandStack, backingStore); if ((bool)thing.GetValue() == false) { // The operator has done its work, discard it. operandStack.Pop(); operandStack.Push(new Operand(OperandType.Bool, false)); return; } else { Evaluate(node.Children[0], operandStack, backingStore); } } else if (op.ShortCircuit == ShortCircuitMode.LogicalOr) { Evaluate(node.Children[1], operandStack, backingStore); var thing = OperatorActions.PeekAndResolve(operandStack, backingStore); if ((bool)thing.GetValue() == true) { // The operator has done its work, discard it. operandStack.Pop(); operandStack.Push(new Operand(OperandType.Bool, true)); return; } else { Evaluate(node.Children[0], operandStack, backingStore); } } else { // TODO: Build it backwards so we can just foreach here. for (int c = node.Children.Count - 1; c >= 0; c--) { Evaluate(node.Children[c], operandStack, backingStore); } } op.DoOperation(operandStack, backingStore, token.ParserPosition); } }
/// <summary> /// Adds simple expression to the expression tree for the current rule. /// There are some expressions that don't require any special handling /// and just need to be added to the expression tree at the point where /// they are met in the parse tree. /// </summary> /// <param name="match">Current parse tree node</param> private void EnterSimpleExpression <TExpression>(ITextParseTreeNode match) where TExpression : ExpressionTreeNode, new() { var newExpression = new TExpression(); ruleBodyExpression.AddChild(newExpression); ruleBodyExpression = newExpression; base.Enter(match); ruleBodyExpression = ruleBodyExpression.Parent; }
/// <summary>Обработка очередного добавляемого в дерево узла</summary> /// <param name="NewNode">Новый добавляемый узел дерева выражения</param> protected virtual void OnNewNodeAdded([NotNull] ref ExpressionTreeNode NewNode) { ProcessNewNode(ref NewNode); var e = new EventArgs <ExpressionTreeNode>(NewNode); NewNodeAdded?.Invoke(this, e); if (!ReferenceEquals(e.Argument, NewNode)) { NewNode = e.Argument; } }
public void CreateTree(ExpressionTreeNode <TEntity> node) { string logic = AND; node.Query = REGEX_AND.Replace(node.Query, "#", 1, 0); var list = node.Query.Split("#"); if (list.Length == 1) { int endAt = 0; if (list[0][0] == '(') { node.Query = list[0].Substring(1, list[0].Length - 2); IsValid(node.Query, out endAt); } logic = Regex.Match(node.Query.Substring(endAt, node.Query.Length - 1 - endAt), AND_OR).Value; node.Query = REGEX_AND_OR.Replace(node.Query, "#", 1, endAt); list = node.Query.Split("#"); if (list.Length == 1) { var data = REGEX_OPERATOR.Split(node.Query); var cond = new UserCondition { Key = data[0], Value = data[2], Operator = data[1] }; node.Data = GetCriterion(cond); return; } } node.LogicalOperator = logic; var left = new ExpressionTreeNode <TEntity>() { Query = list[0] }; node.Left = left; CreateTree(node.Left); var right = new ExpressionTreeNode <TEntity>() { Query = list[1] }; node.Right = right; CreateTree(node.Right); if (node.LogicalOperator == "AND") { node.Data = new AndCriterion <TEntity>(left.Data, right.Data); } else { node.Data = new OrCriterion <TEntity>(left.Data, right.Data); } }
private List <int> SearchInTree(ExpressionTreeNode node, bool notCompareWithAll = false) { if (node == null) { throw new Exception("Invalid expression tree"); } if (!string.IsNullOrEmpty(node.Term)) { return(_index.Find(node.Term)); } var result = new List <int>(); if (node.Operation == "AND") { if (node.Child2.Operation == "NOT") { return(SearchInTree(node.Child1).Except(SearchInTree(node.Child2, true)).ToList()); } return(SearchInTree(node.Child1).Intersect(SearchInTree(node.Child2)).ToList()); } if (node.Operation == "OR") { return(SearchInTree(node.Child1).Concat(SearchInTree(node.Child2)).ToList()); } if (node.Operation == "NOT") { if (notCompareWithAll) { return(SearchInTree(node.Child1).ToList()); } return(_dataSource.GetAllIds().Except(SearchInTree(node.Child1)).ToList()); } if (node.Operation == "ALL") { return(_dataSource.GetAllIds()); } if (node.Operation == "ZERO") { return(new List <int>()); } throw new Exception("Invalid expression tree"); }
public void And_ExpressionTree() { // Arrange string expression = "1 && 2"; Stack <IToken> postfixTokens = _postFixer.ConvertToStack(expression); // Act ExpressionTreeNode root = _expressionTreeBuilder.BuildExpressionTree(postfixTokens); // Assert ExpressionTreeNode expected = new ExpressionTreeNode(Operators.And, 1, 2); root.Should().BeEquivalentTo(expected); }
//query string interpretor public async Task <IQueryable <TEntity> > QueryByConditions(string queryString, IQueryable <TEntity> query) { queryString = queryString.Replace(" ", ""); //var query = GetQueryable(); if (!string.IsNullOrEmpty(queryString)) { var head = new ExpressionTreeNode <TEntity> { Query = queryString }; CreateTree(head); query = head.Data.HandleQueryable(query); } return(query); }
public void OrAndNot_ExpressionTree() { // Arrange string expression = "1 || 2 && !3"; Stack <IToken> postfixTokens = _postFixer.ConvertToStack(expression); // Act ExpressionTreeNode root = _expressionTreeBuilder.BuildExpressionTree(postfixTokens); // Assert ExpressionTreeNode expected = new ExpressionTreeNode(Operators.Or, 1, new ExpressionTreeNode(Operators.And, 2, new ExpressionTreeNode(Operators.Not, 3))); root.Should().BeEquivalentTo(expected); }
public string CreateExpressionTreeNode <TIn>(out ExpressionTreeNode <TIn> root) { root = null; if (Output.Count != 1) { return("No expression to parse."); } if (Operators.Count > 0) { return("Unbalanced expression."); } root = _MakeHasPropertyIfNameExpression(_Visit <TIn>(Output.Pop())); return(null); }
/// <summary> /// Converts <paramref name="left"/> and <paramref name="right"/> to <see cref="HasPropertyExpression{T}"/> /// nodes if either are <see cref="NameExpression{T}"/> nodes being used in boolean contexts. Otherwise, /// it leaves the nodes as-is. /// </summary> /// <typeparam name="TIn">Type of the resulting JSON expression.</typeparam> /// <param name="op">Operator applied to <paramref name="left"/> and <paramref name="right"/>.</param> /// <param name="left">Left hand side of <paramref name="op"/>.</param> /// <param name="right">Right hand side of <paramref name="op"/>.</param> private void _CheckAndReplaceIfHasPropertyNeeded <TIn>(JsonPathOperator op, ref ExpressionTreeNode <TIn> left, ref ExpressionTreeNode <TIn> right) { if (!(left is NameExpression <TIn>) && !(right is NameExpression <TIn>)) { return; } var namedLeft = left as NameExpression <TIn>; var namedRight = right as NameExpression <TIn>; switch (op) { case JsonPathOperator.And: case JsonPathOperator.Or: case JsonPathOperator.Not: // Explicit boolean context, convert one or both sides // as necessary. left = _MakeHasPropertyIfNameExpression(left); right = _MakeHasPropertyIfNameExpression(right); break; case JsonPathOperator.Equal: case JsonPathOperator.NotEqual: // Convert only if one side is a named expression and the other // is a boolean expression tree, but not if both are named // expressions. // // Why? If we've got == or != with two named expressions // we're comparing their values and should not convert both // to HasPropertyExpression's. if (namedLeft == null ^ namedRight == null) { var isBoolean = namedLeft == null ? _IsBooleanResult(left) : _IsBooleanResult(right); if (isBoolean) { // We've evaluated that the context of our Equal/NotEqual // operands is boolean. Convert whichever side is a // named expression to a HasProperty expression. left = _MakeHasPropertyIfNameExpression(left); right = _MakeHasPropertyIfNameExpression(right); } } break; } }
private bool EvaluateNode <T>(ExpressionTreeNode node, T target, IEnumerable <IValidationCondition> validationConditions) { if (!node.Token.IsOperatorToken()) { IIdentifier identifier = (IIdentifier)node.Token; IValidationCondition validationCondition = validationConditions.FirstOrDefault(r => r.ValidationConditionID == identifier.ID); return(EvaluateValidationCondition(target, validationCondition)); } else { IOperator op = (IOperator)node.Token; return(op.Evaluate(() => EvaluateNode(node.Left, target, validationConditions), () => EvaluateNode(node.Right, target, validationConditions))); } }
static void Main(string[] args) { var p1 = Expression.Parameter(typeof(int), "num"); var lam1 = Expression.Lambda <Func <int, bool> >( Expression.LessThan( p1, Expression.Constant(5) ), p1 ); Console.WriteLine(lam1.Compile()(3)); //Expression<Func<int, bool>> lambda = num => num < 5; Expression <Func <int?, bool> > lambda = num => (num ?? 3) < 5; ExperimentalDump(lambda); var node = new ExpressionTreeNode(lambda); Dump(node); }
public List <ValidationError> Validate <T>(T target, IEnumerable <IValidation> validations, IEnumerable <IValidationCondition> validationConditions) { List <ValidationError> errors = new List <ValidationError>(); // Evaluate validation conditions foreach (var validation in validations) { Stack <IToken> postfixTokens = _postfixConverter.ConvertToStack(validation.Expression); ExpressionTreeNode root = _treeBuilder.BuildExpressionTree(postfixTokens); if (EvaluateNode(root, target, validationConditions)) { errors.Add(new ValidationError() { ErrorMessage = validation.ErrorMessage, ErrorCode = validation.ErrorCode }); } } return(errors); }
/// <summary> /// Iterates over specified tokens to recursively build an expression tree node. /// </summary> /// <param name="tokens">Token representation of a logical expression.</param> /// <returns></returns> private ExpressionTreeNode GenerateNode(Stack <IToken> tokens) { ExpressionTreeNode treeNode = new ExpressionTreeNode(); IToken currentToken = tokens.Pop(); if (currentToken.IsOperatorToken()) { treeNode.Token = currentToken; if (currentToken.GetType() != typeof(NotOperator)) { treeNode.Right = GenerateNode(tokens); } treeNode.Left = GenerateNode(tokens); } else { treeNode.Token = currentToken; } return(treeNode); }
/// <summary> /// Generates rule class stub. /// </summary> /// <param name="match">Current parse tree node</param> private void EnterRule(ITextParseTreeNode match) { output.Write("public partial class "); ruleBodyExpression = null; excludedGlobalRules = null; base.Enter(match); if (ruleBodyExpression == null) { // Rules without a body treated as terminals. // There are basically two types of rules - production and terminal. All productions // can be expressed through the grammar. If there was no body defined, then most likely // it was meant to be a light-weight terminal rule. output.WriteLine(" : TerminalParserRule<char>"); output.WriteLine("{"); WriteRuleNameProperty(); } output.WriteLine("}"); }
private static bool _IsBooleanResult <TIn>(ExpressionTreeNode <TIn> node) { if (node == null) { return(false); } // Boolean values are a boolean result. if (node is ValueExpression <TIn> value && value.Value is bool) { return(true); } // NotExpressions are always a boolean result. if (node is NotExpression <TIn> ) { return(true); } if (node is ExpressionTreeBranch <TIn> branch) { // Any subexpression returning a boolean // value is obviously a boolean result. return(branch is AndExpression <TIn> || branch is OrExpression <TIn> || branch is IsEqualExpression <TIn> || branch is IsNotEqualExpression <TIn> || branch is IsGreaterThanEqualExpression <TIn> || branch is IsGreaterThanExpression <TIn> || branch is IsLessThanEqualExpression <TIn> || branch is IsLessThanExpression <TIn>); } // All other expressions do not have boolean results. return(false); }
/// <summary>Обработка нового узла дерева выражения</summary> /// <param name="NewNode">Новый добавляемый узел</param> protected virtual void ProcessNewNode([NotNull] ref ExpressionTreeNode NewNode) { switch (NewNode) { case CharNode char_node: { switch (char_node.Value) { case '.' when NewNode.Parent is CharNode { Value: '.' } : var value_node = NewNode[n => n.Parent].Last(n => !(n is OperatorNode) || n.Left is null); (NewNode["./."] ?? throw new InvalidOperationException("NewNode/. is null")).Right = null; var parent = value_node.Parent; var interval_node = new IntervalNode(value_node); if (parent != null) { parent.Right = interval_node; } NewNode = interval_node; break; } break; }
private static ExpressionTreeNode <TIn> _MakeHasPropertyIfNameExpression <TIn>(ExpressionTreeNode <TIn> node) { if (node is NameExpression <TIn> named) { return(new HasPropertyExpression <TIn> { Path = named.Path, IsLocal = named.IsLocal, Name = named.Name }); } return(node); }
static string Convert(ExpressionTreeNode n) => n?.ToString() ?? string.Empty;
public ExpressionTreeNode(char op) { this.val = new ExpressionOperator(op); this.left = null; this.right = null; }
public void SetExpression(string key, string value, Calculator calc) { m_key = key; m_expression = value; if (calc != null) { m_tree = ExpressionTreeNode.Parse(m_expression, calc); } m_bufferSet = false; //Find variable on forehand to make calculation faster. int propIndex = m_key.LastIndexOf(Calculator.PROPERTY_CHAR); string varName; if (propIndex != -1) { varName = m_key.Substring(0, propIndex); } else { varName = m_key; } if (calc != null) { m_variable = calc.Variable(varName); if (m_variable == null) throw new System.Exception("Invalid variable key: " + key); } m_propName = m_key.Substring(propIndex + 1); }