private static CanConsumeResult JoinCanConsumeNext(ParsingContext xoContext, Boolean xbIsPreconsumption = false) { SyntaxKind eKind = xoContext.List.Peek().ExpectedType; if (SyntaxKindFacts.IsIdentifier(eKind) || eKind == SyntaxKind.OpenParenthesisToken || eKind == SyntaxKind.OnKeyword || (xbIsPreconsumption && SyntaxKindFacts.IsJoinKeyword(eKind)) // Allow preconsumption to use JOIN keywods ) { return(CheckIfConsumptionIsAllowed(xoContext)); } // If we got another keyword (that we cant process) else if ( SyntaxKindFacts.IsTerminatingNode(eKind) || SyntaxKindFacts.IsKeyword(eKind) || eKind == SyntaxKind.CloseParenthesisToken) { // Post execution check if (xoContext.CurrentNode.Count != 3) { ResolutionGenerator.HandleIncompleteNode(xoContext); } return(CanConsumeResult.Complete); } CanConsumeResult eResult = DefaultCanConsumeNext(xoContext); return(DefaultCanConsumeNext(xoContext)); }
/// <summary> /// Used by WHERE and ON /// </summary> /// <param name="xoContext.CurrentNode"></param> /// <param name="xoContext.List"></param> /// <returns></returns> private static CanConsumeResult ExpressionCanConsumeNext(ParsingContext xoContext, Boolean xbIsPreconsumption = false) { SyntaxKind eKind = xoContext.List.Peek().ExpectedType; if ( SyntaxKindFacts.IsIdentifierOrExpression(eKind) || // Identifiers and Expressions are allowed here SyntaxKindFacts.IsAdjunctConditionalOperator(eKind) || // AND OR SyntaxKindFacts.IsConditionalOperator(eKind) || // = >= IN SyntaxKindFacts.IsUnaryOperator(eKind) || // NOT SyntaxKindFacts.IsFunction(eKind) || SyntaxKindFacts.IsArithmaticOperator(eKind)) { return(CheckIfConsumptionIsAllowed(xoContext)); } CanConsumeResult eResult = DefaultCanConsumeNext(xoContext); // Post execution check if (eResult == CanConsumeResult.Complete && xoContext.CurrentNode.Count != 1) { ResolutionGenerator.HandleIncompleteNode(xoContext); } return(eResult); }
private static CanConsumeResult BinaryExpressionCanConsumeNext(ParsingContext xoContext, Boolean xbIsPreconsumption = false) { // Intermediate var SyntaxKind eKind = xoContext.List.Peek().ExpectedType; // If we have something we are actually allowed to consume if ((xbIsPreconsumption && SyntaxKindFacts.IsAdjunctConditionalOperator(eKind)) || // Allow AND/OR in preconsump SyntaxKindFacts.IsIdentifierOrExpression(eKind) || // Identifiers and Expressions are allowed here SyntaxKindFacts.IsConditionalOperator(eKind) || // = >= IN SyntaxKindFacts.IsUnaryOperator(eKind) || // NOT SyntaxKindFacts.IsArithmaticOperator(eKind)) { CanConsumeResult eResult = CheckIfConsumptionIsAllowed(xoContext); switch (eResult) { // Possible erroroneous case CanConsumeResult.Unknown: // Definitely finished case CanConsumeResult.Complete: // Perform final checks break; // Break immediately case CanConsumeResult.Skip: case CanConsumeResult.Consume: return(eResult); } } // Closing condition if (xoContext.CurrentNode.IsFull() || SyntaxKindFacts.IsTerminatingNode(eKind) || SyntaxKindFacts.IsKeyword(eKind) || eKind == SyntaxKind.CloseParenthesisToken) { // Post execution check if (xoContext.CurrentNode.Count != 2) { ResolutionGenerator.HandleIncompleteNode(xoContext); } return(CanConsumeResult.Complete); } // return(DefaultCanConsumeNext(xoContext)); }
/// <summary> /// Postprocessing method that can be overriden if some activity needs to be /// done immediately after a node is constructed /// </summary> /// <param name="xoNode"></param> /// <param name="xoContext.List"></param> /// <returns></returns> private Boolean AddChildAndPostProcess(ParsingContext xoContext, Boolean xbIsPreconsumption = false) { // Is not a node, cannot be added if (!xoContext.List.Peek().IsNode()) { return(false); } SyntaxNode oNewNode = (SyntaxNode)xoContext.List.Pop(); // Do preconsumption here if (SyntaxKindFacts.IsBinaryConstruct(oNewNode.ExpectedType)) { // If there is nothing to preconsume if (xoContext.CurrentNode.Count == 0) { // Else we have an error to fix ResolutionGenerator.HandlePreconsumptionError(new ParsingContext(oNewNode, xoContext.List)); } // If there is something to preconsume else { int iSiblingPosition = xoContext.CurrentNode.Count - 1; SyntaxNode oPrevSibling = xoContext.CurrentNode[iSiblingPosition]; // Put the previous sibling back on the List to be consumed xoContext.List.Insert(oPrevSibling); // Check the eligibility of the previous node CanConsumeResult eEligibility = oNewNode.CanConsumeNode( new ParsingContext(oNewNode, xoContext.List), true); if (eEligibility == CanConsumeResult.Consume) { // Assign the parent oNewNode.Parent = xoContext.CurrentNode; // Pull off the last node from the parent oNewNode.Add((SyntaxNode)xoContext.List.Pop()); // Remove it too xoContext.CurrentNode.RemoveAt(iSiblingPosition); } else { // Else we have an error to fix ResolutionGenerator.HandlePreconsumptionError(new ParsingContext(oNewNode, xoContext.List)); } } } // If it is full if (xoContext.CurrentNode.IsFull()) { return(false); } else { // Add the child xoContext.CurrentNode.Add(oNewNode); // 2. Depth first traversal from the child if (oNewNode.TryConsumeFromContext(xoContext)) { // If it successfully consumed something } return(true); } }
/// <summary> /// This node will try and consume items from the list /// </summary> /// <param name="xoContext"></param> /// <returns></returns> public virtual Boolean TryConsumeFromContext(ParsingContext xoContext) { // Until we break while (true) { // Generate a new context every time ParsingContext oContext = new ParsingContext(this, xoContext.List); // Call the Consumption fn CanConsumeResult eResult = Strategy.EligibilityFn(oContext, false); // Switch based on the result of the attempt switch (eResult) { case CanConsumeResult.Consume: // Create a new node ISyntax oNew = Strategy.TryConsumeNextFn(oContext, false); // Append the new node to the list oContext.List.Insert(oNew); // Consume it if (AddChildAndPostProcess(oContext, false)) { // Set the variable once if (!bHasConsumedNodes) { bHasConsumedNodes = true; } } else { // Couldn't add the node for some reason this.Comments.Add(new StatusItem("Could not add:" + oNew.RawSQLText)); } break; case CanConsumeResult.Skip: //xoList.PopToken(); // Skip the next node break; case CanConsumeResult.Complete: // If post validation fails and we fixed the issue if (!Strategy.ValidationFn(oContext) && TryAndResolveIssues(oContext)) { // keep processing break; } // Else Terminating case return(bHasConsumedNodes); case CanConsumeResult.Unknown: // Try and fix any issues if (TryAndResolveIssues(oContext)) { // Found a solution, keep processing break; } // Else, fail and leave here return(bHasConsumedNodes); } } }