private static void _GetRequiredChildrenFromOutput(JsonPathExpressionContext context, OperatorExpression expr) { if (expr.IsBinary) { var second = context.Output.Pop(); var first = context.Output.Pop(); expr.Children.Add(first); expr.Children.Add(second); } else // unary { expr.Children.Add(context.Output.Pop()); } }
private static string _Parse <TIn>(string source, ref int index, out ExpressionTreeNode <TIn> root) { root = null; var context = new JsonPathExpressionContext(); while (index < source.Length) { var errorMessage = source.SkipWhiteSpace(ref index, source.Length, out _); if (errorMessage != null) { return(errorMessage); } IJsonPathExpressionParser foundParser = null; foreach (var parser in _parsers) { if (parser.Handles(source, index)) { foundParser = parser; break; } } if (foundParser == null) { return("Unrecognized JSON Path Expression element."); } errorMessage = foundParser.TryParse <TIn>(source, ref index, out var expression); if (errorMessage != null) { return(errorMessage); } if (expression == null) { break; } // // Implements the Shunting-yard Algorithm // if (expression is ValueExpression value) { // Values go immediately onto the output stack context.Output.Push(value); } else if (expression is OperatorExpression op) { if (op.Operator == JsonPathOperator.GroupStart) { // Push open parenthesis onto the operator stack context.Operators.Push(new OperatorExpression { Operator = JsonPathOperator.GroupStart }); } else if (op.Operator == JsonPathOperator.GroupEnd) { // Resolve all operators from the closing parenthesis // back to the matching open parenthesis. // While: // 1. We have operators // 2. and, they are not the open parentheses... while (context.Operators.Count > 0 && context.Operators.Peek().Operator != JsonPathOperator.GroupStart) { // Get the operator... var expr = context.Operators.Pop(); // ...pop its children from the stack... _GetRequiredChildrenFromOutput(context, expr); // ...and push the completed operator sub-tree onto the output stack context.Output.Push(expr); } if (context.Operators.Count == 0 || context.Operators.Pop().Operator != JsonPathOperator.GroupStart) { return("Unbalanced parentheses."); } } else { if (op.Operator == JsonPathOperator.Subtract) { // Check if we need to switch this to a negation operator if (context.LastExpression is OperatorExpression lastOp && lastOp.Operator != JsonPathOperator.GroupEnd) { // ...if the prior expression is an operator, // but not the end of a grouping expression // then this subtraction is actually a negation // of the next term. op.Operator = JsonPathOperator.Negate; } } // For all other operators, resolve any operators // of greater (or equal right-assoc) precedence // before pushing ourselves onto the operator stack while (context.Operators.Count > 0) { var top = context.Operators.Peek(); // While: // 1. There is an op with greater precedence // 2. or, the operator has equal and is left-assoc // 3. and, it is not group start... var precedence = _Compare(op, top); if ((precedence < 0 || precedence == 0 && !_IsRightAssociative(top.Operator)) && top.Operator != JsonPathOperator.GroupStart) { // Get the operator... var expr = context.Operators.Pop(); // ...pop its children from the stack... _GetRequiredChildrenFromOutput(context, expr); // ...and push the completed operator sub-tree onto the output stack context.Output.Push(expr); } else { break; } } context.Operators.Push(op); } } context.LastExpression = expression; } // Convert the expression into an ExpressionTreeNode return(context.CreateExpressionTreeNode(out root)); }