2
// ConditionTokenizer.cs
5
// Marek Sieradzki (marek.sieradzki@gmail.com)
6
// Jaroslaw Kowalski <jaak@jkowalski.net>
8
// (C) 2006 Marek Sieradzki
9
// (C) 2004-2006 Jaroslaw Kowalski
11
// Permission is hereby granted, free of charge, to any person obtaining
12
// a copy of this software and associated documentation files (the
13
// "Software"), to deal in the Software without restriction, including
14
// without limitation the rights to use, copy, modify, merge, publish,
15
// distribute, sublicense, and/or sell copies of the Software, and to
16
// permit persons to whom the Software is furnished to do so, subject to
17
// the following conditions:
19
// The above copyright notice and this permission notice shall be
20
// included in all copies or substantial portions of the Software.
22
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
using System.Collections;
32
using System.Collections.Generic;
33
using System.Collections.Specialized;
36
namespace Microsoft.Build.BuildEngine {
38
internal sealed class ConditionTokenizer {
40
string inputString = null;
42
int tokenPosition = 0;
47
// bool ignoreWhiteSpace = true;
49
static TokenType[] charIndexToTokenType = new TokenType[128];
50
static Dictionary <string, TokenType> keywords = new Dictionary <string, TokenType> (StringComparer.InvariantCultureIgnoreCase);
52
static ConditionTokenizer ()
54
for (int i = 0; i < 128; i++)
55
charIndexToTokenType [i] = TokenType.Invalid;
57
foreach (CharToTokenType cht in charToTokenType)
58
charIndexToTokenType [(int) cht.ch] = cht.tokenType;
60
keywords.Add ("and", TokenType.And);
61
keywords.Add ("or", TokenType.Or);
64
public ConditionTokenizer ()
66
// this.ignoreWhiteSpace = true;
69
public void Tokenize (string s)
72
throw new ArgumentNullException ("s");
76
this.token = new Token (null, TokenType.BOF);
81
void SkipWhiteSpace ()
85
while ((ch = PeekChar ()) != -1) {
86
if (!Char.IsWhiteSpace ((char)ch))
94
if (position < inputString.Length)
95
return (int) inputString [position];
102
if (position < inputString.Length)
103
return (int) inputString [position++];
108
public void Expect (TokenType type)
110
if (token.Type != type)
111
throw new ExpressionParseException ("Expected token type of type: " + type + ", got " + token.Type +
112
" (" + token.Value + ") .");
119
return token.Type == TokenType.EOF;
122
public bool IsNumber ()
124
return token.Type == TokenType.Number;
127
public bool IsToken (TokenType type)
129
return token.Type == type;
132
public bool IsPunctation ()
134
return (token.Type >= TokenType.FirstPunct && token.Type < TokenType.LastPunct);
138
public void Putback (Token token)
143
public void GetNextToken ()
145
if (putback != null) {
151
if (token.Type == TokenType.EOF)
152
throw new ExpressionParseException ("Cannot read past the end of stream.");
156
tokenPosition = position;
158
// int i = PeekChar ();
162
token = new Token (null, TokenType.EOF);
169
// FIXME: looks like a hack: if '-' is here '->' won't be tokenized
170
// maybe we should treat item reference as a token
171
if (ch == '-' && PeekChar () == '>') {
173
token = new Token ("->", TokenType.Transform);
174
} else if (Char.IsDigit (ch) || ch == '-') {
175
StringBuilder sb = new StringBuilder ();
179
while ((i = PeekChar ()) != -1) {
182
if (Char.IsDigit (ch) || ch == '.')
183
sb.Append ((char) ReadChar ());
188
token = new Token (sb.ToString (), TokenType.Number);
189
} else if (ch == '\'') {
190
StringBuilder sb = new StringBuilder ();
194
bool is_itemref = (PeekChar () == '@');
195
int num_open_braces = 0;
196
bool in_literal = false;
198
while ((i = PeekChar ()) != -1) {
200
if (ch == '(' && !in_literal && is_itemref)
202
if (ch == ')' && !in_literal && is_itemref)
205
sb.Append ((char) ReadChar ());
208
if (num_open_braces == 0)
210
in_literal = !in_literal;
214
temp = sb.ToString ();
216
token = new Token (temp.Substring (1, temp.Length - 2), TokenType.String);
218
} else if (ch == '_' || Char.IsLetter (ch)) {
219
StringBuilder sb = new StringBuilder ();
221
sb.Append ((char) ch);
223
while ((i = PeekChar ()) != -1) {
224
if ((char) i == '_' || Char.IsLetterOrDigit ((char) i))
225
sb.Append ((char) ReadChar ());
230
string temp = sb.ToString ();
232
if (keywords.ContainsKey (temp))
233
token = new Token (temp, keywords [temp]);
235
token = new Token (temp, TokenType.String);
237
} else if (ch == '!' && PeekChar () == (int) '=') {
238
token = new Token ("!=", TokenType.NotEqual);
240
} else if (ch == '<' && PeekChar () == (int) '=') {
241
token = new Token ("<=", TokenType.LessOrEqual);
243
} else if (ch == '>' && PeekChar () == (int) '=') {
244
token = new Token (">=", TokenType.GreaterOrEqual);
246
} else if (ch == '=' && PeekChar () == (int) '=') {
247
token = new Token ("==", TokenType.Equal);
249
} else if (ch >= 32 && ch < 128) {
250
if (charIndexToTokenType [ch] != TokenType.Invalid) {
251
token = new Token (new String (ch, 1), charIndexToTokenType [ch]);
254
throw new ExpressionParseException (String.Format ("Invalid punctuation: {0}", ch));
256
throw new ExpressionParseException (String.Format ("Invalid token: {0}", ch));
259
public int TokenPosition {
260
get { return tokenPosition; }
264
get { return token; }
268
public bool IgnoreWhiteSpace {
269
get { return ignoreWhiteSpace; }
270
set { ignoreWhiteSpace = value; }
274
struct CharToTokenType {
276
public TokenType tokenType;
278
public CharToTokenType (char ch, TokenType tokenType)
281
this.tokenType = tokenType;
285
static CharToTokenType[] charToTokenType = {
286
new CharToTokenType ('<', TokenType.Less),
287
new CharToTokenType ('>', TokenType.Greater),
288
new CharToTokenType ('=', TokenType.Equal),
289
new CharToTokenType ('(', TokenType.LeftParen),
290
new CharToTokenType (')', TokenType.RightParen),
291
new CharToTokenType ('.', TokenType.Dot),
292
new CharToTokenType (',', TokenType.Comma),
293
new CharToTokenType ('!', TokenType.Not),
294
new CharToTokenType ('@', TokenType.Item),
295
new CharToTokenType ('$', TokenType.Property),
296
new CharToTokenType ('%', TokenType.Metadata),
297
new CharToTokenType ('\'', TokenType.Apostrophe),