示例#1
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);
        }
示例#2
0
        private static ParseResult IsTokenValid(ParseContext context, SqlGrammarRuleSequenceTerminal terminalReference, int level, int tokenOffset, ReservedWordScope scope)
        {
            var tokenIsValid = false;
            IList <StatementGrammarNode> nodes = null;

            var terminalId = terminalReference.Id;

            if (context.TokenBuffer.Count > tokenOffset)
            {
                var currentToken = context.TokenBuffer[tokenOffset];

                var terminal       = terminalReference.Terminal;
                var isReservedWord = false;
                if (String.IsNullOrEmpty(terminal.RegexValue))
                {
                    var tokenValue = currentToken.UpperInvariantValue;
                    tokenIsValid   = String.Equals(terminal.Value, tokenValue) || (terminal.AllowQuotedNotation && tokenValue.Length == terminal.Value.Length + 2 && tokenValue[0] == '"' && tokenValue[tokenValue.Length - 1] == '"' && String.Equals(tokenValue.Substring(1, tokenValue.Length - 2), terminal.Value));
                    isReservedWord = tokenIsValid && (scope == ReservedWordScope.Sql ? terminal.ReservedWord == ReservedWordType.Sql : terminal.ReservedWord > 0);
                }
                else
                {
                    tokenIsValid = terminal.RegexMatcher.IsMatch(currentToken.Value);
                    if (tokenIsValid && !terminalReference.AllowReservedWord)
                    {
                        var isNotReservedWord = !OracleGrammarDescription.ReservedWordsSql.Contains(currentToken.UpperInvariantValue);

                        if (isNotReservedWord && scope == ReservedWordScope.PlSqlBody)
                        {
                            var effectiveReservedWords = context.PlSqlStatementTokenIndex.Count == 0 || context.PlSqlStatementTokenIndex.Peek() == tokenOffset
                                                                ? OracleGrammarDescription.ReservedWordsPlSqlBody
                                                                : OracleGrammarDescription.ReservedWordsPlSql;

                            isNotReservedWord = !effectiveReservedWords.Contains(currentToken.UpperInvariantValue);
                        }

                        if (isNotReservedWord && scope == ReservedWordScope.PlSqlDeclaration)
                        {
                            isNotReservedWord = !OracleGrammarDescription.ReservedWordsPlSqlDeclaration.Contains(currentToken.UpperInvariantValue);
                        }

                        tokenIsValid &= isNotReservedWord;
                    }
                }

                if (tokenIsValid)
                {
                    var terminalNode =
                        new StatementGrammarNode(NodeType.Terminal, context.Statement, currentToken)
                    {
                        Id             = terminalId,
                        Level          = level,
                        IsRequired     = terminalReference.IsRequired,
                        IsReservedWord = isReservedWord
                    };

                    nodes = new[] { terminalNode };
                }
            }

            return
                (new ParseResult
            {
                NodeId = terminalId,
                Status = tokenIsValid ? ParseStatus.Success : ParseStatus.SequenceNotFound,
                Nodes = nodes
            });
        }
示例#3
0
 public static bool IsValidIdentifier(string identifier, ReservedWordScope scope = ReservedWordScope.Sql)
 {
     return(IdentifierMatcher.IsMatch(identifier) && !identifier.IsReservedWord(scope));
 }
示例#4
0
		private static ParseResult IsTokenValid(ParseContext context, SqlGrammarRuleSequenceTerminal terminalReference, int level, int tokenOffset, ReservedWordScope scope)
		{
			var tokenIsValid = false;
			IList<StatementGrammarNode> nodes = null;

			var terminalId = terminalReference.Id;
			if (context.TokenBuffer.Count > tokenOffset)
			{
				var currentToken = context.TokenBuffer[tokenOffset];

				var terminal = terminalReference.Terminal;
				var isReservedWord = false;
				if (String.IsNullOrEmpty(terminal.RegexValue))
				{
					var tokenValue = currentToken.UpperInvariantValue;
					tokenIsValid = String.Equals(terminal.Value, tokenValue) || (terminal.AllowQuotedNotation && tokenValue.Length == terminal.Value.Length + 2 && tokenValue[0] == '"' && tokenValue[tokenValue.Length - 1] == '"' && String.Equals(tokenValue.Substring(1, tokenValue.Length - 2), terminal.Value));
					isReservedWord = tokenIsValid && (scope == ReservedWordScope.Sql ? terminal.ReservedWord == ReservedWordType.Sql : terminal.ReservedWord > 0);
				}
				else
				{
					tokenIsValid = terminal.RegexMatcher.IsMatch(currentToken.Value);
					if (tokenIsValid && !terminalReference.AllowReservedWord)
					{
						var isNotReservedWord = !OracleGrammarDescription.ReservedWordsSql.Contains(currentToken.UpperInvariantValue);

						if (isNotReservedWord && scope == ReservedWordScope.PlSqlBody)
						{
							var effectiveReservedWords = context.PlSqlStatementTokenIndex.Count == 0 || context.PlSqlStatementTokenIndex.Peek() == tokenOffset
								? OracleGrammarDescription.ReservedWordsPlSqlBody
								: OracleGrammarDescription.ReservedWordsPlSql;

							isNotReservedWord = !effectiveReservedWords.Contains(currentToken.UpperInvariantValue);
						}

						if (isNotReservedWord && scope == ReservedWordScope.PlSqlDeclaration)
						{
							isNotReservedWord = !OracleGrammarDescription.ReservedWordsPlSqlDeclaration.Contains(currentToken.UpperInvariantValue);
						}

						tokenIsValid &= isNotReservedWord;
					}
				}

				if (tokenIsValid)
				{
					var terminalNode =
						new StatementGrammarNode(NodeType.Terminal, context.Statement, currentToken)
						{
							Id = terminalId,
							Level = level,
							IsRequired = terminalReference.IsRequired,
							IsReservedWord = isReservedWord
						};

					nodes = new[] { terminalNode };
				}
			}

			return
				new ParseResult
				{
					NodeId = terminalId,
					Status = tokenIsValid ? ParseStatus.Success : ParseStatus.SequenceNotFound,
					Nodes = nodes
				};
		}
示例#5
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;
		}
示例#6
0
		public static bool IsValidIdentifier(string identifier, ReservedWordScope scope = ReservedWordScope.Sql)
		{
			return IdentifierMatcher.IsMatch(identifier) && !identifier.IsReservedWord(scope);
		}
示例#7
0
		public static bool IsReservedWord(this string value, ReservedWordScope scope = ReservedWordScope.Sql)
		{
			var invariantString = value.ToUpperInvariant();
			var isSqlReserved = ReservedWordsSql.Contains(invariantString);
			return isSqlReserved ||
				   (scope == ReservedWordScope.PlSqlDeclaration && ReservedWordsPlSqlDeclaration.Contains(invariantString)) ||
				   (scope == ReservedWordScope.PlSqlBody && ReservedWordsPlSqlBody.Contains(invariantString));
		}