예제 #1
0
        private void GatherCandidatesFromNonterminal(SqlGrammarRuleSequenceNonTerminal nonTerminal, ICollection <TerminalCandidate> candidates)
        {
            foreach (var sequence in nonTerminal.TargetRule.Sequences)
            {
                foreach (ISqlGrammarRuleSequenceItem item in sequence.Items)
                {
                    GatherCandidatesFromGrammarItem(item, candidates);

                    if (item.IsRequired)
                    {
                        break;
                    }
                }
            }
        }
예제 #2
0
        private static ParseResult ProceedNonTerminal(ParseContext context, SqlGrammarRuleSequenceNonTerminal nonTerminal, int level, int tokenStartOffset, bool tokenReverted, ReservedWordScope scope)
        {
            if (nonTerminal.TargetRule.Scope != ReservedWordScope.Inherit)
            {
                scope = nonTerminal.TargetRule.Scope;
            }

            var bestCandidateNodes = new List <StatementGrammarNode>();
            var workingNodes       = new List <StatementGrammarNode>();
            var nonTerminalId      = nonTerminal.Id;
            var result             =
                new ParseResult
            {
                NodeId         = nonTerminalId,
                Nodes          = workingNodes,
                BestCandidates = bestCandidateNodes,
            };

            var workingTerminalCount       = 0;
            var bestCandidateTerminalCount = 0;
            var totalTokenCount            = context.TokenBuffer.Count;

            var isPlSqlStatement = String.Equals(nonTerminalId, OracleGrammarDescription.NonTerminals.PlSqlStatementType);

            if (isPlSqlStatement)
            {
                context.PlSqlStatementTokenIndex.Push(tokenStartOffset);
            }

            foreach (var sequence in nonTerminal.TargetRule.Sequences)
            {
                context.CancellationToken.ThrowIfCancellationRequested();

                result.Status = ParseStatus.Success;
                workingNodes.Clear();
                workingTerminalCount = 0;

                var bestCandidatesCompatible = false;
                var isSequenceValid          = true;

                foreach (ISqlGrammarRuleSequenceItem item in sequence.Items)
                {
                    var tokenOffset    = tokenStartOffset + workingTerminalCount;
                    var isNodeRequired = item.IsRequired;
                    if (tokenOffset >= totalTokenCount && !isNodeRequired)
                    {
                        continue;
                    }

                    var childNodeId = item.Id;
                    if (!isNodeRequired && workingTerminalCount == 0 && String.Equals(childNodeId, nonTerminalId))
                    {
                        continue;
                    }

                    var bestCandidateOffset = tokenStartOffset + bestCandidateTerminalCount;
                    var tryBestCandidates   = bestCandidatesCompatible && !tokenReverted && bestCandidateTerminalCount > workingTerminalCount;
                    if (item is SqlGrammarRuleSequenceNonTerminal childNonTerminal)
                    {
                        var nestedResult = ProceedNonTerminal(context, childNonTerminal, level + 1, tokenOffset, false, scope);

                        var optionalTokenReverted = TryRevertOptionalToken(optionalTerminalCount => ProceedNonTerminal(context, childNonTerminal, level + 1, tokenOffset - optionalTerminalCount, true, scope), ref nestedResult, workingNodes);
                        workingTerminalCount -= optionalTokenReverted;

                        TryParseInvalidGrammar(tryBestCandidates, () => ProceedNonTerminal(context, childNonTerminal, level + 1, bestCandidateOffset, false, scope), ref nestedResult, workingNodes, bestCandidateNodes, ref workingTerminalCount);

                        var isNestedNodeValid = nestedResult.Status == ParseStatus.Success;
                        if (isNodeRequired || isNestedNodeValid)
                        {
                            result.Status = nestedResult.Status;
                        }

                        var nestedNode =
                            new StatementGrammarNode(NodeType.NonTerminal, context.Statement, null)
                        {
                            Id             = childNodeId,
                            Level          = level,
                            IsRequired     = isNodeRequired,
                            IsGrammarValid = isNestedNodeValid
                        };

                        var alternativeNode = nestedNode.Clone();

                        int currentTerminalCount;
                        if (nestedResult.BestCandidates.Count > 0 &&
                            ((currentTerminalCount = workingTerminalCount + nestedResult.BestCandidateTerminalCount) > bestCandidateTerminalCount ||
                             (currentTerminalCount == bestCandidateTerminalCount && isNestedNodeValid)))
                        {
                            alternativeNode.AddChildNodes(ResolveAlternativeNodes(nestedResult));

                            if (optionalTokenReverted > 0 || !isNestedNodeValid || workingNodes.Count != bestCandidateNodes.Count)
                            {
                                bestCandidateTerminalCount = CreateNewNodeList(workingNodes, bestCandidateNodes);
                            }

                            bestCandidateNodes.Add(alternativeNode);
                            bestCandidateTerminalCount += alternativeNode.TerminalCount;

                            bestCandidatesCompatible = true;
                        }

                        if (isNestedNodeValid && nestedResult.Nodes.Count > 0)
                        {
                            nestedNode.AddChildNodes(nestedResult.Nodes);
                            workingNodes.Add(nestedNode);
                            workingTerminalCount += nestedResult.TerminalCount;
                        }

                        if (result.Status == ParseStatus.SequenceNotFound)
                        {
                            if (workingNodes.Count == 0)
                            {
                                break;
                            }

                            isSequenceValid = false;
                            workingNodes.Add(alternativeNode.Clone());
                            workingTerminalCount += alternativeNode.TerminalCount;
                        }
                    }
                    else
                    {
                        var terminalReference = (SqlGrammarRuleSequenceTerminal)item;

                        var terminalResult = IsTokenValid(context, terminalReference, level, tokenOffset, scope);

                        TryParseInvalidGrammar(tryBestCandidates && isNodeRequired, () => IsTokenValid(context, terminalReference, level, bestCandidateOffset, scope), ref terminalResult, workingNodes, bestCandidateNodes, ref workingTerminalCount);

                        if (terminalResult.Status == ParseStatus.SequenceNotFound)
                        {
                            if (isNodeRequired)
                            {
                                result.Status = ParseStatus.SequenceNotFound;
                                break;
                            }

                            continue;
                        }

                        workingTerminalCount++;
                        bestCandidateTerminalCount++;
                        var terminalNode = terminalResult.Nodes[0];

                        workingNodes.Add(terminalNode);
                        bestCandidateNodes.Add(terminalNode.Clone());
                    }
                }

                if (result.Status == ParseStatus.Success)
                {
                    #region CASE WHEN issue
                    if (bestCandidateTerminalCount > workingTerminalCount)
                    {
                        var currentTerminalCount = bestCandidateNodes.SelectMany(n => n.Terminals).TakeWhile(t => !t.Id.IsIdentifierOrAlias() && !t.Id.IsLiteral()).Count();
                        if (currentTerminalCount > workingTerminalCount && workingNodes.FirstOrDefault()?.FirstTerminalNode.Id.IsIdentifierOrAlias() == true)
                        {
                            workingNodes.ForEach(n => n.IsGrammarValid = false);
                        }
                    }
                    #endregion

                    if (isSequenceValid)
                    {
                        break;
                    }
                }
            }

            if (isPlSqlStatement)
            {
                context.PlSqlStatementTokenIndex.Pop();
            }

            result.BestCandidates             = bestCandidateNodes;
            result.TerminalCount              = workingTerminalCount;
            result.BestCandidateTerminalCount = bestCandidateTerminalCount;

            return(result);
        }
예제 #3
0
		private static ParseResult ProceedNonTerminal(ParseContext context, SqlGrammarRuleSequenceNonTerminal nonTerminal, int level, int tokenStartOffset, bool tokenReverted, ReservedWordScope scope)
		{
			if (nonTerminal.TargetRule.Scope != ReservedWordScope.Inherit)
			{
				scope = nonTerminal.TargetRule.Scope;
			}

			var bestCandidateNodes = new List<StatementGrammarNode>();
			var workingNodes = new List<StatementGrammarNode>();
			var nonTerminalId = nonTerminal.Id;
			var result =
				new ParseResult
				{
					NodeId = nonTerminalId,
					Nodes = workingNodes,
					BestCandidates = bestCandidateNodes,
				};

			var workingTerminalCount = 0;
			var bestCandidateTerminalCount = 0;

			var isPlSqlStatement = String.Equals(nonTerminalId, OracleGrammarDescription.NonTerminals.PlSqlStatementType);
			if (isPlSqlStatement)
			{
				context.PlSqlStatementTokenIndex.Push(tokenStartOffset);
			}

			foreach (var sequence in nonTerminal.TargetRule.Sequences)
			{
				context.CancellationToken.ThrowIfCancellationRequested();

				result.Status = ParseStatus.Success;
				workingNodes.Clear();
				workingTerminalCount = 0;

				var bestCandidatesCompatible = false;
				var isSequenceValid = true;

				foreach (ISqlGrammarRuleSequenceItem item in sequence.Items)
				{
					var tokenOffset = tokenStartOffset + workingTerminalCount;
					var isNodeRequired = item.IsRequired;
					if (tokenOffset >= context.TokenBuffer.Count && !isNodeRequired)
					{
						continue;
					}

					var childNodeId = item.Id;
					if (!isNodeRequired && workingTerminalCount == 0 && String.Equals(childNodeId, nonTerminalId))
					{
						continue;
					}

					var bestCandidateOffset = tokenStartOffset + bestCandidateTerminalCount;
					var tryBestCandidates = bestCandidatesCompatible && !tokenReverted && bestCandidateTerminalCount > workingTerminalCount;
					var childNonTerminal = item as SqlGrammarRuleSequenceNonTerminal;
					if (childNonTerminal != null)
					{
						var nestedResult = ProceedNonTerminal(context, childNonTerminal, level + 1, tokenOffset, false,  scope);

						var optionalTokenReverted = TryRevertOptionalToken(optionalTerminalCount => ProceedNonTerminal(context, childNonTerminal, level + 1, tokenOffset - optionalTerminalCount, true, scope), ref nestedResult, workingNodes);
						workingTerminalCount -= optionalTokenReverted;

						TryParseInvalidGrammar(tryBestCandidates, () => ProceedNonTerminal(context, childNonTerminal, level + 1, bestCandidateOffset, false, scope), ref nestedResult, workingNodes, bestCandidateNodes, ref workingTerminalCount);

						var isNestedNodeValid = nestedResult.Status == ParseStatus.Success;
						if (isNodeRequired || isNestedNodeValid)
						{
							result.Status = nestedResult.Status;
						}

						var nestedNode =
							new StatementGrammarNode(NodeType.NonTerminal, context.Statement, null)
							{
								Id = childNodeId,
								Level = level,
								IsRequired = isNodeRequired,
								IsGrammarValid = isNestedNodeValid
							};

						var alternativeNode = nestedNode.Clone();

						int currentTerminalCount;
						if (nestedResult.BestCandidates.Count > 0 &&
							((currentTerminalCount = workingTerminalCount + nestedResult.BestCandidateTerminalCount) > bestCandidateTerminalCount ||
							 (currentTerminalCount == bestCandidateTerminalCount && isNestedNodeValid)))
						{
							var bestCandidatePosition = new Dictionary<int, StatementGrammarNode>();

							// Candidate nodes can be multiplied or terminals can be spread among different nonterminals,
							// therefore we fetch the node with most terminals or the later (when nodes contain same terminals).
							foreach (var candidate in nestedResult.BestCandidates)
							{
								StatementGrammarNode storedNode;
								if (!bestCandidatePosition.TryGetValue(candidate.SourcePosition.IndexStart, out storedNode) ||
									storedNode.SourcePosition.IndexEnd <= candidate.SourcePosition.IndexEnd)
								{
									bestCandidatePosition[candidate.SourcePosition.IndexStart] = candidate;
								}
							}

							alternativeNode.AddChildNodes(bestCandidatePosition.Values);

							if (optionalTokenReverted > 0 || !isNestedNodeValid || workingNodes.Count != bestCandidateNodes.Count)
							{
								bestCandidateTerminalCount = CreateNewNodeList(workingNodes, bestCandidateNodes);
							}

							bestCandidateNodes.Add(alternativeNode);
							bestCandidateTerminalCount += alternativeNode.TerminalCount;
							
							bestCandidatesCompatible = true;
						}

						if (isNestedNodeValid && nestedResult.Nodes.Count > 0)
						{
							nestedNode.AddChildNodes(nestedResult.Nodes);
							workingNodes.Add(nestedNode);
							workingTerminalCount += nestedResult.TerminalCount;
						}

						if (result.Status == ParseStatus.SequenceNotFound)
						{
							if (workingNodes.Count == 0)
							{
								break;
							}

							isSequenceValid = false;
							workingNodes.Add(alternativeNode.Clone());
							workingTerminalCount += alternativeNode.TerminalCount;
						}
					}
					else
					{
						var terminalReference = (SqlGrammarRuleSequenceTerminal)item;

						var terminalResult = IsTokenValid(context, terminalReference, level, tokenOffset, scope);

						TryParseInvalidGrammar(tryBestCandidates && isNodeRequired, () => IsTokenValid(context, terminalReference, level, bestCandidateOffset, scope), ref terminalResult, workingNodes, bestCandidateNodes, ref workingTerminalCount);

						if (terminalResult.Status == ParseStatus.SequenceNotFound)
						{
							if (isNodeRequired)
							{
								result.Status = ParseStatus.SequenceNotFound;
								break;
							}

							continue;
						}

						workingTerminalCount++;
						bestCandidateTerminalCount++;
						var terminalNode = terminalResult.Nodes[0];

						workingNodes.Add(terminalNode);
						bestCandidateNodes.Add(terminalNode.Clone());
					}
				}

				if (result.Status == ParseStatus.Success)
				{
					#region CASE WHEN issue
					if (bestCandidateTerminalCount > workingTerminalCount)
					{
						var currentTerminalCount = bestCandidateNodes.SelectMany(n => n.Terminals).TakeWhile(t => !t.Id.IsIdentifierOrAlias() && !t.Id.IsLiteral()).Count();
						if (currentTerminalCount > workingTerminalCount && workingNodes.FirstOrDefault()?.FirstTerminalNode.Id.IsIdentifierOrAlias() == true)
						{
							workingNodes.ForEach(n => n.IsGrammarValid = false);
						}
					}
					#endregion

					if (isSequenceValid)
					{
						break;
					}
				}
			}

			if (isPlSqlStatement)
			{
				context.PlSqlStatementTokenIndex.Pop();
			}

			result.BestCandidates = bestCandidateNodes;
			result.TerminalCount = workingTerminalCount;
			result.BestCandidateTerminalCount = bestCandidateTerminalCount;

			return result;
		}
예제 #4
0
		private void GatherCandidatesFromNonterminal(SqlGrammarRuleSequenceNonTerminal nonTerminal, ICollection<TerminalCandidate> candidates)
		{
			foreach (var sequence in nonTerminal.TargetRule.Sequences)
			{
				foreach (ISqlGrammarRuleSequenceItem item in sequence.Items)
				{
					GatherCandidatesFromGrammarItem(item, candidates);

					if (item.IsRequired)
					{
						break;
					}
				}
			}
		}