1 // ***********************************************************************
2 // Copyright (c) 2015 Charlie Poole
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // ***********************************************************************
25 #define NUNIT_FRAMEWORK
33 #pragma warning disable 1591
36 namespace NUnit.Engine
38 namespace NUnit.Common
51 public Token(TokenKind kind) : this(kind, string.Empty) { }
53 public Token(TokenKind kind, char ch) : this(kind, ch.ToString()) { }
55 public Token(TokenKind kind, string text)
61 public TokenKind Kind { get; private set; }
63 public string Text { get; private set; }
65 public int Pos { get; set; }
67 #region Equality Overrides
69 public override bool Equals(object obj)
71 return obj is Token && this == (Token)obj;
74 public override int GetHashCode()
76 return Text.GetHashCode();
79 public override string ToString()
82 ? Kind.ToString() + ":" + Text
86 public static bool operator ==(Token t1, Token t2)
88 bool t1Null = ReferenceEquals(t1, null);
89 bool t2Null = ReferenceEquals(t2, null);
97 return t1.Kind == t2.Kind && t1.Text == t2.Text;
100 public static bool operator !=(Token t1, Token t2)
109 /// Tokenizer class performs lexical analysis for the TestSelectionParser.
110 /// It recognizes a very limited set of tokens: words, symbols and
111 /// quoted strings. This is sufficient for the simple DSL we use to
112 /// select which tests to run.
114 public class Tokenizer
116 private string _input;
119 private const char EOF_CHAR = '\0';
120 private const string WORD_BREAK_CHARS = "=!()&|";
121 private readonly string[] DOUBLE_CHAR_SYMBOLS = new string[] { "==", "=~", "!=", "!~", "&&", "||" };
123 private Token _lookahead;
125 public Tokenizer(string input)
128 throw new ArgumentNullException("input");
134 public Token LookAhead
138 if (_lookahead == null)
139 _lookahead = GetNextToken();
145 public Token NextToken()
147 Token result = _lookahead ?? GetNextToken();
152 private Token GetNextToken()
162 return new Token(TokenKind.Eof) { Pos = pos };
164 // Single char symbols
168 return new Token(TokenKind.Symbol, ch) { Pos = pos };
170 // Possible double char symbols
176 foreach(string dbl in DOUBLE_CHAR_SYMBOLS)
177 if (ch == dbl[0] && NextChar == dbl[1])
180 return new Token(TokenKind.Symbol, dbl) { Pos = pos };
183 return new Token(TokenKind.Symbol, ch);
195 private bool IsWordChar(char c)
197 if (char.IsWhiteSpace(c) || c == EOF_CHAR)
200 return WORD_BREAK_CHARS.IndexOf(c) < 0;
203 private Token GetWord()
205 var sb = new StringBuilder();
208 while (IsWordChar(NextChar))
209 sb.Append(GetChar());
211 return new Token(TokenKind.Word, sb.ToString()) { Pos = pos };
214 private Token GetString()
216 var sb = new StringBuilder();
219 char quote = GetChar(); // Save the initial quote char
221 while (NextChar != EOF_CHAR)
226 else if (ch == quote)
231 return new Token(TokenKind.String, sb.ToString()) { Pos = pos };
235 /// Get the next character in the input, consuming it.
237 /// <returns>The next char</returns>
238 private char GetChar()
240 return _index < _input.Length ? _input[_index++] : EOF_CHAR;
244 /// Peek ahead at the next character in input
246 private char NextChar
250 return _index < _input.Length ? _input[_index] : EOF_CHAR;
254 private void SkipBlanks()
256 while (char.IsWhiteSpace(NextChar))