1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5

6
namespace TurnerSoftware.RobotsExclusionTools.Tokenization
7
{
8
	public abstract class TokenPatternValidatorBase : ITokenPatternValidator
9
	{
10
		protected abstract IEnumerable<TokenPattern> LookupTokenPatterns(TokenType tokenType);
11

12
		public TokenValidationResult Validate(IEnumerable<Token> tokens)
13 1
		{
14 1
			var errors = new List<TokenValidationError>();
15

16 1
			var preceedingTokens = new Stack<TokenType>(tokens.Count());
17 1
			var succeedingTokens = new Queue<TokenType>(tokens.Select(t => t.TokenType).ToArray());
18

19 1
			var currentToken = TokenType.NotDefined;
20 1
			var lineNumber = 1;
21

22 1
			while (succeedingTokens.Any())
23 1
			{
24 1
				currentToken = succeedingTokens.Dequeue();
25

26 1
				var tokenValidation = ValidateToken(lineNumber, currentToken, preceedingTokens, succeedingTokens);
27 1
				if (tokenValidation != null)
28 1
				{
29 1
					errors.Add(tokenValidation);
30 1
				}
31

32 1
				preceedingTokens.Push(currentToken);
33

34 1
				if (currentToken == TokenType.NewLine)
35 1
				{
36 1
					lineNumber++;
37 1
				}
38 1
			}
39

40 1
			return new TokenValidationResult(errors);
41 1
		}
42
		
43
		private TokenValidationError ValidateToken(int lineNumber, TokenType tokenType, Stack<TokenType> preceeding, Queue<TokenType> succeeding)
44 1
		{
45 1
			var tokenPatterns = LookupTokenPatterns(tokenType);
46

47 1
			TokenValidationError lastError = null;
48
			
49 1
			foreach (var tokenPattern in tokenPatterns)
50 1
			{
51 1
				var tokenPatternError = ValidateTokenPattern(lineNumber, tokenPattern, preceeding, succeeding);
52 1
				if (tokenPatternError == null)
53 1
				{
54 1
					return null;
55
				}
56

57 1
				lastError = tokenPatternError;
58 1
			}
59

60 1
			return lastError;
61 1
		}
62

63
		private TokenValidationError ValidateTokenPattern(int lineNumber, TokenPattern tokenPattern, Stack<TokenType> preceeding, Queue<TokenType> succeeding)
64 1
		{
65 1
			if (tokenPattern.Preceeding.Count > 0)
66 1
			{
67 1
				if (!PatternMatch(tokenPattern.Preceeding, preceeding))
68 1
				{
69 1
					return new TokenValidationError(lineNumber, $"Preceeding tokens did not match the pattern for token {tokenPattern.Token}", tokenPattern.Preceeding, preceeding);
70
				}
71 1
			}
72

73 1
			if (tokenPattern.Succeeding.Count > 0)
74 1
			{
75 1
				if (!PatternMatch(tokenPattern.Succeeding, succeeding))
76 0
				{
77 0
					return new TokenValidationError(lineNumber, $"Succeeding tokens did not match the pattern for token {tokenPattern.Token}", tokenPattern.Succeeding, succeeding);
78
				}
79 1
			}
80

81 1
			return null;
82 1
		}
83

84
		private bool PatternMatch(IReadOnlyCollection<TokenType> initialTokens, IReadOnlyCollection<TokenType> comparisonTokens)
85 1
		{
86
			//Check number of tokens match (though ignore required new lines)
87
			//This effectively allows "NewLine" tokens to be optional when there are no proceeding tokens (eg. at the start of the file)
88 1
			if (initialTokens.Count(t => t != TokenType.NewLine) > comparisonTokens.Count)
89 1
			{
90 1
				return false;
91
			}
92

93 1
			var index = 0;
94 1
			var length = Math.Min(initialTokens.Count, comparisonTokens.Count);
95 1
			var initialTokensArray = (TokenType[])initialTokens;
96

97 1
			foreach (var comparisonToken in comparisonTokens)
98 1
			{
99 1
				if (index >= length)
100 1
				{
101 1
					break;
102
				}
103

104 1
				if (initialTokensArray[index] != comparisonToken)
105 1
				{
106 1
					return false;
107
				}
108

109 1
				index++;
110 1
			}
111

112 1
			return true;
113 1
		}
114
	}
115
}

Read our documentation on viewing source code .

Loading