diff --git a/OpenRA.Game/Support/ConditionExpression.cs b/OpenRA.Game/Support/ConditionExpression.cs index 8fdb3cd35f..9ffd48ab29 100644 --- a/OpenRA.Game/Support/ConditionExpression.cs +++ b/OpenRA.Game/Support/ConditionExpression.cs @@ -111,6 +111,10 @@ namespace OpenRA.Support enum TokenType { + // fixed values + False, + True, + // varying values Number, Variable, @@ -198,6 +202,12 @@ namespace OpenRA.Support case TokenType.Invalid: yield return new TokenTypeInfo("()", Precedence.Invalid); continue; + case TokenType.False: + yield return new TokenTypeInfo("false", Precedence.Value); + continue; + case TokenType.True: + yield return new TokenTypeInfo("true", Precedence.Value); + continue; case TokenType.Number: yield return new TokenTypeInfo("()", Precedence.Value); continue; @@ -326,6 +336,20 @@ namespace OpenRA.Support return false; } + static TokenType VariableOrKeyword(string expression, int start, int length) + { + var i = start; + if (length == 4 && expression[i++] == 't' && expression[i++] == 'r' && expression[i++] == 'u' + && expression[i] == 'e') + return TokenType.True; + + if (length == 5 && expression[i++] == 'f' && expression[i++] == 'a' && expression[i++] == 'l' + && expression[i++] == 's' && expression[i] == 'e') + return TokenType.False; + + return TokenType.Variable; + } + public static TokenType GetNextType(string expression, ref int i, TokenType lastType = TokenType.Invalid) { var start = i; @@ -438,14 +462,14 @@ namespace OpenRA.Support 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++) + for (i = start; i < expression.Length; i++) { cc = CharClassOf(expression[i]); if (cc == CharClass.Whitespace || cc == CharClass.Operator) - return TokenType.Variable; + return VariableOrKeyword(expression, start, i - start); } - return TokenType.Variable; + return VariableOrKeyword(expression, start, i - start); } public static Token GetNext(string expression, ref int i, TokenType lastType = TokenType.Invalid) @@ -828,6 +852,18 @@ namespace OpenRA.Support continue; } + case TokenType.False: + { + ast.Push(False); + continue; + } + + case TokenType.True: + { + ast.Push(True); + continue; + } + case TokenType.Number: { ast.Push(Expressions.Expression.Constant(((NumberToken)t).Value)); diff --git a/OpenRA.Test/OpenRA.Game/ConditionExpressionTest.cs b/OpenRA.Test/OpenRA.Game/ConditionExpressionTest.cs index 1cb61887cb..66cc5faea7 100644 --- a/OpenRA.Test/OpenRA.Game/ConditionExpressionTest.cs +++ b/OpenRA.Test/OpenRA.Game/ConditionExpressionTest.cs @@ -23,8 +23,8 @@ namespace OpenRA.Test { IReadOnlyDictionary testValues = new ReadOnlyDictionary(new Dictionary() { - { "true", 1 }, - { "false", 0 } + { "one", 1 }, + { "five", 5 } }); void AssertFalse(string expression) @@ -66,6 +66,26 @@ namespace OpenRA.Test AssertValue("-12", -12); } + [TestCase(TestName = "Variables")] + public void TestVariables() + { + AssertValue("one", 1); + AssertValue("five", 5); + } + + [TestCase(TestName = "Boolean Constants")] + public void TestBoolConsts() + { + AssertValue(" true", 1); + AssertValue(" true ", 1); + AssertValue("true", 1); + AssertValue("false", 0); + AssertValue("tru", 0); + AssertValue("fals", 0); + AssertValue("tr", 0); + AssertValue("fal", 0); + } + [TestCase(TestName = "Booleans")] public void TestBooleans() { @@ -320,6 +340,8 @@ namespace OpenRA.Test public void TestUndefinedSymbols() { AssertFalse("undef1 || undef2"); + AssertValue("undef1", 0); + AssertValue("undef1 + undef2", 0); } } }