in MySQL.Data/src/X/Protocol/X/ExprParser.cs [258:478]
void Lex()
{
for (int i = 0; i < this.stringValue.Length; ++i)
{
int start = i; // for routines that consume more than one char
char c = this.stringValue[i];
if (Char.IsWhiteSpace(c))
{
// ignore
}
else if (Char.IsDigit(c))
{
if (i != stringValue.Length - 1)
{
if (!Char.IsLetter(stringValue[i + 1]) || NextCharEquals(i, 'e')) i = LexNumber(i);
else Identifier(ref i, start);
}
else i = LexNumber(i);
}
else if (!(c == '_' || Char.IsLetter(c)))
{
// non-identifier, e.g. operator or quoted literal
switch (c)
{
case ':':
this.tokens.Add(new Token(TokenType.COLON, c));
break;
case '+':
this.tokens.Add(new Token(TokenType.PLUS, c));
break;
case '-':
if (NextCharEquals(i, '>'))
{
i++;
if (NextCharEquals(i, '>'))
{
i++;
this.tokens.Add(new Token(TokenType.DOUBLE_ARROW, "->>"));
}
else
{
this.tokens.Add(new Token(TokenType.ARROW, "->"));
}
}
else
{
this.tokens.Add(new Token(TokenType.MINUS, c));
}
break;
case '*':
if (NextCharEquals(i, '*'))
{
i++;
this.tokens.Add(new Token(TokenType.DOUBLESTAR, "**"));
}
else
{
this.tokens.Add(new Token(TokenType.STAR, c));
}
break;
case '/':
this.tokens.Add(new Token(TokenType.SLASH, c));
break;
case '$':
this.tokens.Add(new Token(TokenType.AT, c));
break;
case '%':
this.tokens.Add(new Token(TokenType.MOD, c));
break;
case '=':
if (NextCharEquals(i, '='))
{
i++;
}
this.tokens.Add(new Token(TokenType.EQ, "=="));
break;
case '&':
if (NextCharEquals(i, '&'))
{
i++;
this.tokens.Add(new Token(TokenType.ANDAND, "&&"));
}
else
{
this.tokens.Add(new Token(TokenType.BITAND, c));
}
break;
case '|':
if (NextCharEquals(i, '|'))
{
i++;
this.tokens.Add(new Token(TokenType.OROR, "||"));
}
else
{
this.tokens.Add(new Token(TokenType.BITOR, c));
}
break;
case '^':
this.tokens.Add(new Token(TokenType.BITXOR, c));
break;
case '(':
this.tokens.Add(new Token(TokenType.LPAREN, c));
break;
case ')':
this.tokens.Add(new Token(TokenType.RPAREN, c));
break;
case '[':
this.tokens.Add(new Token(TokenType.LSQBRACKET, c));
break;
case ']':
this.tokens.Add(new Token(TokenType.RSQBRACKET, c));
break;
case '{':
this.tokens.Add(new Token(TokenType.LCURLY, c));
break;
case '}':
this.tokens.Add(new Token(TokenType.RCURLY, c));
break;
case '~':
this.tokens.Add(new Token(TokenType.NEG, c));
break;
case ',':
this.tokens.Add(new Token(TokenType.COMMA, c));
break;
case '!':
if (NextCharEquals(i, '='))
{
i++;
this.tokens.Add(new Token(TokenType.NE, "!="));
}
else
{
this.tokens.Add(new Token(TokenType.BANG, c));
}
break;
case '?':
this.tokens.Add(new Token(TokenType.EROTEME, c));
break;
case '<':
if (NextCharEquals(i, '<'))
{
i++;
this.tokens.Add(new Token(TokenType.LSHIFT, "<<"));
}
else if (NextCharEquals(i, '='))
{
i++;
this.tokens.Add(new Token(TokenType.LE, "<="));
}
else
{
this.tokens.Add(new Token(TokenType.LT, c));
}
break;
case '>':
if (NextCharEquals(i, '>'))
{
i++;
this.tokens.Add(new Token(TokenType.RSHIFT, ">>"));
}
else if (NextCharEquals(i, '='))
{
i++;
this.tokens.Add(new Token(TokenType.GE, ">="));
}
else
{
this.tokens.Add(new Token(TokenType.GT, c));
}
break;
case '.':
if (NextCharEquals(i, '*'))
{
i++;
this.tokens.Add(new Token(TokenType.DOTSTAR, ".*"));
}
else if (i + 1 < this.stringValue.Length && Char.IsDigit(this.stringValue[i + 1]))
{
i = LexNumber(i);
}
else
{
this.tokens.Add(new Token(TokenType.DOT, c));
}
break;
case '"':
case '\'':
case '`':
char quoteChar = c;
StringBuilder val = new StringBuilder();
try
{
for (c = this.stringValue[++i]; c != quoteChar || (i + 1 < this.stringValue.Length && this.stringValue[i + 1] == quoteChar);
c = this.stringValue[++i])
{
if (c == '\\' || c == quoteChar)
{
++i;
}
val.Append(this.stringValue[i]);
}
}
catch (IndexOutOfRangeException)
{
throw new ArgumentException("Unterminated string starting at " + start);
}
var value = val.ToString();
this.tokens.Add(new Token(quoteChar == '`' ? TokenType.IDENT : TokenType.LSTRING, value == string.Empty ? "" : value));
break;
default:
throw new ArgumentException("Can't parse at pos: " + i);
}
}
else
{
// otherwise, it's an identifier
Identifier(ref i, start);
}
}
}