diff --git a/OpenRA.Game/FieldLoader.cs b/OpenRA.Game/FieldLoader.cs
index 6a725c02c0..ac753db0cc 100644
--- a/OpenRA.Game/FieldLoader.cs
+++ b/OpenRA.Game/FieldLoader.cs
@@ -398,13 +398,29 @@ namespace OpenRA
return InvalidValueAction(value, fieldType, fieldName);
}
- else if (fieldType == typeof(ConditionExpression))
+ else if (fieldType == typeof(BooleanExpression))
{
if (value != null)
{
try
{
- return new ConditionExpression(value);
+ return new BooleanExpression(value);
+ }
+ catch (InvalidDataException e)
+ {
+ throw new YamlException(e.Message);
+ }
+ }
+
+ return InvalidValueAction(value, fieldType, fieldName);
+ }
+ else if (fieldType == typeof(IntegerExpression))
+ {
+ if (value != null)
+ {
+ try
+ {
+ return new IntegerExpression(value);
}
catch (InvalidDataException e)
{
diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj
index e02b9ba75e..29f884cd7c 100644
--- a/OpenRA.Game/OpenRA.Game.csproj
+++ b/OpenRA.Game/OpenRA.Game.csproj
@@ -259,7 +259,7 @@
-
+
diff --git a/OpenRA.Game/Support/ConditionExpression.cs b/OpenRA.Game/Support/VariableExpression.cs
similarity index 94%
rename from OpenRA.Game/Support/ConditionExpression.cs
rename to OpenRA.Game/Support/VariableExpression.cs
index 03af2d6f47..ff56b090a6 100644
--- a/OpenRA.Game/Support/ConditionExpression.cs
+++ b/OpenRA.Game/Support/VariableExpression.cs
@@ -18,14 +18,12 @@ using Expressions = System.Linq.Expressions;
namespace OpenRA.Support
{
- public class ConditionExpression
+ public abstract class VariableExpression
{
public readonly string Expression;
readonly HashSet variables = new HashSet();
public IEnumerable Variables { get { return variables; } }
- readonly Func, int> asFunction;
-
enum CharClass { Whitespace, Operator, Mixed, Id, Digit }
static CharClass CharClassOf(char c)
@@ -525,15 +523,19 @@ namespace OpenRA.Support
}
}
- public ConditionExpression(string expression)
+ public VariableExpression(string expression)
{
Expression = expression;
+ }
+
+ Expression Build(ExpressionType resultType)
+ {
var tokens = new List();
var currentOpeners = new Stack();
Token lastToken = null;
for (var i = 0;;)
{
- var token = Token.GetNext(expression, ref i, lastToken != null ? lastToken.Type : TokenType.Invalid);
+ var token = Token.GetNext(Expression, ref i, lastToken != null ? lastToken.Type : TokenType.Invalid);
if (token == null)
{
// Sanity check parsed tree
@@ -591,7 +593,20 @@ namespace OpenRA.Support
if (currentOpeners.Count > 0)
throw new InvalidDataException("Unclosed opening parenthesis at index {0}".F(currentOpeners.Peek().Index));
- asFunction = new Compiler().Compile(ToPostfix(tokens).ToArray());
+ return new Compiler().Build(ToPostfix(tokens).ToArray(), resultType);
+ }
+
+ protected Func, T> Compile()
+ {
+ ExpressionType resultType;
+ if (typeof(T) == typeof(int))
+ resultType = ExpressionType.Int;
+ else if (typeof(T) == typeof(bool))
+ resultType = ExpressionType.Bool;
+ else
+ throw new InvalidCastException("Variable expressions can only be int or bool.");
+
+ return Expressions.Expression.Lambda, T>>(Build(resultType), SymbolsParam).Compile();
}
static int ParseSymbol(string symbol, IReadOnlyDictionary symbols)
@@ -712,7 +727,7 @@ namespace OpenRA.Support
{
readonly AstStack ast = new AstStack();
- public Func, int> Compile(Token[] postfix)
+ public Expression Build(Token[] postfix, ExpressionType resultType)
{
foreach (var t in postfix)
{
@@ -877,10 +892,34 @@ namespace OpenRA.Support
}
}
- return Expressions.Expression.Lambda, int>>(
- ast.Pop(ExpressionType.Int), SymbolsParam).Compile();
+ return ast.Pop(resultType);
}
}
+ }
+
+ public class BooleanExpression : VariableExpression
+ {
+ readonly Func, bool> asFunction;
+
+ public BooleanExpression(string expression) : base(expression)
+ {
+ asFunction = Compile();
+ }
+
+ public bool Evaluate(IReadOnlyDictionary symbols)
+ {
+ return asFunction(symbols);
+ }
+ }
+
+ public class IntegerExpression : VariableExpression
+ {
+ readonly Func, int> asFunction;
+
+ public IntegerExpression(string expression) : base(expression)
+ {
+ asFunction = Compile();
+ }
public int Evaluate(IReadOnlyDictionary symbols)
{
diff --git a/OpenRA.Mods.Common/Lint/LintExts.cs b/OpenRA.Mods.Common/Lint/LintExts.cs
index a8b1ee57fa..c6f770ee62 100644
--- a/OpenRA.Mods.Common/Lint/LintExts.cs
+++ b/OpenRA.Mods.Common/Lint/LintExts.cs
@@ -29,13 +29,13 @@ namespace OpenRA.Mods.Common.Lint
if (typeof(IEnumerable).IsAssignableFrom(type))
return fieldInfo.GetValue(ruleInfo) as IEnumerable;
- if (type == typeof(ConditionExpression))
+ if (type == typeof(BooleanExpression) || type == typeof(IntegerExpression))
{
- var expr = (ConditionExpression)fieldInfo.GetValue(ruleInfo);
+ var expr = (VariableExpression)fieldInfo.GetValue(ruleInfo);
return expr != null ? expr.Variables : Enumerable.Empty();
}
- throw new InvalidOperationException("Bad type for reference on {0}.{1}. Supported types: string, IEnumerable, BooleanExpression"
+ throw new InvalidOperationException("Bad type for reference on {0}.{1}. Supported types: string, IEnumerable, BooleanExpression, IntegerExpression"
.F(ruleInfo.GetType().Name, fieldInfo.Name));
}
@@ -48,13 +48,13 @@ namespace OpenRA.Mods.Common.Lint
if (typeof(IEnumerable).IsAssignableFrom(type))
return (IEnumerable)propertyInfo.GetValue(ruleInfo);
- if (type == typeof(ConditionExpression))
+ if (type == typeof(BooleanExpression) || type == typeof(IntegerExpression))
{
- var expr = (ConditionExpression)propertyInfo.GetValue(ruleInfo);
+ var expr = (VariableExpression)propertyInfo.GetValue(ruleInfo);
return expr != null ? expr.Variables : Enumerable.Empty();
}
- throw new InvalidOperationException("Bad type for reference on {0}.{1}. Supported types: string, IEnumerable, BooleanExpression"
+ throw new InvalidOperationException("Bad type for reference on {0}.{1}. Supported types: string, IEnumerable, BooleanExpression, IntegerExpression"
.F(ruleInfo.GetType().Name, propertyInfo.Name));
}
}
diff --git a/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs b/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs
index 3f197345b0..0e7e8986fa 100644
--- a/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs
+++ b/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs
@@ -23,7 +23,7 @@ namespace OpenRA.Mods.Common.Traits
[ConsumedConditionReference]
[Desc("Boolean expression defining the condition to enable this trait.")]
- public readonly ConditionExpression RequiresCondition = null;
+ public readonly BooleanExpression RequiresCondition = null;
public abstract object Create(ActorInitializer init);
@@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.Traits
public virtual void RulesetLoaded(Ruleset rules, ActorInfo ai)
{
- EnabledByDefault = RequiresCondition != null ? RequiresCondition.Evaluate(NoConditions) > 0 : true;
+ EnabledByDefault = RequiresCondition == null || RequiresCondition.Evaluate(NoConditions);
}
}
@@ -83,7 +83,7 @@ namespace OpenRA.Mods.Common.Traits
return;
var wasDisabled = IsTraitDisabled;
- IsTraitDisabled = Info.RequiresCondition.Evaluate(conditions) <= 0;
+ IsTraitDisabled = !Info.RequiresCondition.Evaluate(conditions);
if (IsTraitDisabled != wasDisabled)
{
diff --git a/OpenRA.Mods.Common/Traits/Pluggable.cs b/OpenRA.Mods.Common/Traits/Pluggable.cs
index 16f23af230..60a937b748 100644
--- a/OpenRA.Mods.Common/Traits/Pluggable.cs
+++ b/OpenRA.Mods.Common/Traits/Pluggable.cs
@@ -30,7 +30,7 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Requirements for accepting a plug type.",
"Key is the plug type that the requirements applies to.",
"Value is the condition expression defining the requirements to place the plug.")]
- public readonly Dictionary Requirements = new Dictionary();
+ public readonly Dictionary Requirements = new Dictionary();
[GrantedConditionReference]
public IEnumerable LinterConditions { get { return Conditions.Values; } }
@@ -119,7 +119,7 @@ namespace OpenRA.Mods.Common.Traits
void IConditionConsumer.ConditionsChanged(Actor self, IReadOnlyDictionary conditions)
{
foreach (var req in Info.Requirements)
- plugTypesAvailability[req.Key] = req.Value.Evaluate(conditions) != 0;
+ plugTypesAvailability[req.Key] = req.Value.Evaluate(conditions);
}
}
diff --git a/OpenRA.Test/OpenRA.Game/ConditionExpressionTest.cs b/OpenRA.Test/OpenRA.Game/VariableExpressionTest.cs
similarity index 94%
rename from OpenRA.Test/OpenRA.Game/ConditionExpressionTest.cs
rename to OpenRA.Test/OpenRA.Game/VariableExpressionTest.cs
index 14cb0475ee..9be3c411d4 100644
--- a/OpenRA.Test/OpenRA.Game/ConditionExpressionTest.cs
+++ b/OpenRA.Test/OpenRA.Game/VariableExpressionTest.cs
@@ -19,7 +19,7 @@ using OpenRA.Support;
namespace OpenRA.Test
{
[TestFixture]
- public class ConditionExpressionTest
+ public class VariableExpressionTest
{
IReadOnlyDictionary testValues = new ReadOnlyDictionary(new Dictionary()
{
@@ -29,28 +29,28 @@ namespace OpenRA.Test
void AssertFalse(string expression)
{
- Assert.False(new ConditionExpression(expression).Evaluate(testValues) > 0, expression);
+ Assert.False(new BooleanExpression(expression).Evaluate(testValues), expression);
}
void AssertTrue(string expression)
{
- Assert.True(new ConditionExpression(expression).Evaluate(testValues) > 0, expression);
+ Assert.True(new BooleanExpression(expression).Evaluate(testValues), expression);
}
void AssertValue(string expression, int value)
{
- Assert.AreEqual(value, new ConditionExpression(expression).Evaluate(testValues), expression);
+ Assert.AreEqual(value, new IntegerExpression(expression).Evaluate(testValues), expression);
}
void AssertParseFailure(string expression)
{
- Assert.Throws(typeof(InvalidDataException), () => new ConditionExpression(expression).Evaluate(testValues), expression);
+ Assert.Throws(typeof(InvalidDataException), () => new IntegerExpression(expression).Evaluate(testValues), expression);
}
void AssertParseFailure(string expression, string errorMessage)
{
var actualErrorMessage = Assert.Throws(typeof(InvalidDataException),
- () => new ConditionExpression(expression).Evaluate(testValues),
+ () => new IntegerExpression(expression).Evaluate(testValues),
expression).Message;
Assert.AreEqual(errorMessage, actualErrorMessage, expression + " ===> " + actualErrorMessage);
}
diff --git a/OpenRA.Test/OpenRA.Test.csproj b/OpenRA.Test/OpenRA.Test.csproj
index b9df93b6ab..e451d7c9fd 100644
--- a/OpenRA.Test/OpenRA.Test.csproj
+++ b/OpenRA.Test/OpenRA.Test.csproj
@@ -55,7 +55,7 @@
-
+