ConditionExpression: move lexing to Token class.

This commit is contained in:
atlimit8
2017-02-14 00:42:03 -06:00
parent 4537c3c7d0
commit 8e6436d71c

View File

@@ -109,8 +109,11 @@ namespace OpenRA.Support
enum TokenType enum TokenType
{ {
// varying values
Number, Number,
Variable, Variable,
// operators
OpenParen, OpenParen,
CloseParen, CloseParen,
Not, Not,
@@ -118,6 +121,7 @@ namespace OpenRA.Support
Or, Or,
Equals, Equals,
NotEquals, NotEquals,
Invalid Invalid
} }
@@ -232,6 +236,126 @@ namespace OpenRA.Support
Type = type; Type = type;
Index = index; Index = index;
} }
public static TokenType GetNextType(string expression, ref int i)
{
var start = i;
switch (expression[i])
{
case '!':
i++;
if (i < expression.Length && expression[i] == '=')
{
i++;
return TokenType.NotEquals;
}
return TokenType.Not;
case '=':
i++;
if (i < expression.Length && expression[i] == '=')
{
i++;
return TokenType.Equals;
}
throw new InvalidDataException("Unexpected character '=' at index {0} - should it be `==`?".F(start));
case '&':
i++;
if (i < expression.Length && expression[i] == '&')
{
i++;
return TokenType.And;
}
throw new InvalidDataException("Unexpected character '&' at index {0} - should it be `&&`?".F(start));
case '|':
i++;
if (i < expression.Length && expression[i] == '|')
{
i++;
return TokenType.Or;
}
throw new InvalidDataException("Unexpected character '|' at index {0} - should it be `||`?".F(start));
case '(':
i++;
return TokenType.OpenParen;
case ')':
i++;
return TokenType.CloseParen;
}
var cc = CharClassOf(expression[start]);
// Scan forwards until we find an non-digit character
if (expression[start] == '-' || cc == CharClass.Digit)
{
i++;
for (; i < expression.Length; i++)
{
cc = CharClassOf(expression[i]);
if (cc != CharClass.Digit)
{
if (cc != CharClass.Whitespace && cc != CharClass.Operator)
throw new InvalidDataException("Number {0} and variable merged at index {1}".F(
int.Parse(expression.Substring(start, i - start)), start));
return TokenType.Number;
}
}
return TokenType.Number;
}
if (cc != CharClass.Id)
throw new InvalidDataException("Invalid character '{0}' at index {1}".F(expression[i], start));
// Scan forwards until we find an invalid name character
for (; i < expression.Length; i++)
{
cc = CharClassOf(expression[i]);
if (cc == CharClass.Whitespace || cc == CharClass.Operator)
return TokenType.Variable;
}
// Take the rest of the string
return TokenType.Variable;
}
public static Token GetNext(string expression, ref int i)
{
if (i == expression.Length)
return null;
// Ignore whitespace
while (CharClassOf(expression[i]) == CharClass.Whitespace)
{
if (++i == expression.Length)
return null;
}
var start = i;
var type = GetNextType(expression, ref i);
switch (type)
{
case TokenType.Number:
return new NumberToken(start, expression.Substring(start, i - start));
case TokenType.Variable:
return new VariableToken(start, expression.Substring(start, i - start));
default:
return new Token(type, start);
}
}
} }
class VariableToken : Token class VariableToken : Token
@@ -264,16 +388,12 @@ namespace OpenRA.Support
var openParens = 0; var openParens = 0;
var closeParens = 0; var closeParens = 0;
var tokens = new List<Token>(); var tokens = new List<Token>();
for (var i = 0; i < expression.Length;) for (var i = 0;;)
{ {
// Ignore whitespace var token = Token.GetNext(expression, ref i);
if (CharClassOf(expression[i]) == CharClass.Whitespace) if (token == null)
{ break;
i++;
continue;
}
var token = ParseSymbol(expression, ref i);
switch (token.Type) switch (token.Type)
{ {
case TokenType.OpenParen: case TokenType.OpenParen:
@@ -331,111 +451,6 @@ namespace OpenRA.Support
postfix = ToPostfix(tokens).ToArray(); postfix = ToPostfix(tokens).ToArray();
} }
static Token ParseSymbol(string expression, ref int i)
{
var start = i;
// Parse operators
switch (expression[start])
{
case '!':
{
i++;
if (i < expression.Length && expression[start + 1] == '=')
{
i++;
return new Token(TokenType.NotEquals, start);
}
return new Token(TokenType.Not, start);
}
case '=':
{
i++;
if (i < expression.Length && expression[start + 1] == '=')
{
i++;
return new Token(TokenType.Equals, start);
}
throw new InvalidDataException("Unexpected character '=' at index {0} - should it be `==`?".F(start));
}
case '&':
{
i++;
if (i < expression.Length && expression[start + 1] == '&')
{
i++;
return new Token(TokenType.And, start);
}
throw new InvalidDataException("Unexpected character '&' at index {0} - should it be `&&`?".F(start));
}
case '|':
{
i++;
if (i < expression.Length && expression[start + 1] == '|')
{
i++;
return new Token(TokenType.Or, start);
}
throw new InvalidDataException("Unexpected character '|' at index {0} - should it be `||`?".F(start));
}
case '(':
{
i++;
return new Token(TokenType.OpenParen, start);
}
case ')':
{
i++;
return new Token(TokenType.CloseParen, start);
}
}
var cc = CharClassOf(expression[start]);
// Scan forwards until we find an non-digit character
if (expression[start] == '-' || cc == CharClass.Digit)
{
i++;
for (; i < expression.Length; i++)
{
cc = CharClassOf(expression[i]);
if (cc != CharClass.Digit)
{
if (cc != CharClass.Whitespace && cc != CharClass.Operator)
throw new InvalidDataException("Number {0} and variable merged at index {1}".F(
int.Parse(expression.Substring(start, i - start)), start));
return new NumberToken(start, expression.Substring(start, i - start));
}
}
return new NumberToken(start, expression.Substring(start));
}
if (cc != CharClass.Id)
throw new InvalidDataException("Invalid character '{0}' at index {1}".F(expression[i], start));
// Scan forwards until we find an invalid name character
for (; i < expression.Length; i++)
{
cc = CharClassOf(expression[i]);
if (cc == CharClass.Whitespace || cc == CharClass.Operator)
return new VariableToken(start, expression.Substring(start, i - start));
}
// Take the rest of the string
return new VariableToken(start, expression.Substring(start));
}
static int ParseSymbol(VariableToken t, IReadOnlyDictionary<string, int> symbols) static int ParseSymbol(VariableToken t, IReadOnlyDictionary<string, int> symbols)
{ {
int value; int value;