Example #1
0
        public void TestRebalanceAddString()
        {
            // "A" + B - C => "A" + (B - C)
            var str       = new StringConstantExpression("ban");
            var exprLeft  = new IntegerConstantExpression(6);
            var exprRight = new IntegerConstantExpression(2);
            var clause    = new MathematicExpression(exprLeft, MathematicOperation.Subtract, exprRight);
            var expr      = new MathematicExpression(str, MathematicOperation.Add, clause);

            var result = expr.Rebalance() as MathematicExpression;

            Assert.That(result, Is.Not.Null);
            Assert.That(result.Left, Is.EqualTo(str));
            Assert.That(result.Operation, Is.EqualTo(MathematicOperation.Add));
            Assert.That(result.Right, Is.EqualTo(clause));

            // A - B + "C" => (A - B) + "C"
            clause = new MathematicExpression(exprRight, MathematicOperation.Add, str);
            expr   = new MathematicExpression(exprLeft, MathematicOperation.Subtract, clause);

            result = expr.Rebalance() as MathematicExpression;
            Assert.That(result, Is.Not.Null);
            var expectedLeft = new MathematicExpression(exprLeft, MathematicOperation.Subtract, exprRight);

            Assert.That(result.Left, Is.EqualTo(expectedLeft));
            Assert.That(result.Operation, Is.EqualTo(MathematicOperation.Add));
            Assert.That(result.Right, Is.EqualTo(str));
        }
Example #2
0
        public void TestRebalanceMathematic(MathematicOperation op1, MathematicOperation op2, bool rebalanceExpected)
        {
            // parser will result in a right-weighted tree: A * B + C => A * {B + C}
            // if the left operator is a multiply or divide and the right is an add or subtract,
            // the left operator takes precedence and tree should be rebalanced.
            //
            //   A * B + C => {A * B} + C   rebalanced
            //   A + B * C => A + {B * C}   not rebalanced
            //
            var variable1 = new VariableExpression("variable1");
            var variable2 = new VariableExpression("variable2");
            var value     = new IntegerConstantExpression(99);
            var clause    = new MathematicExpression(variable2, op2, value);
            var expr      = new MathematicExpression(variable1, op1, clause);

            var result = expr.Rebalance() as MathematicExpression;

            Assert.That(result, Is.Not.Null);
            if (rebalanceExpected)
            {
                var expectedLeft = new MathematicExpression(variable1, op1, variable2);
                Assert.That(result.Left, Is.EqualTo(expectedLeft));
                Assert.That(result.Operation, Is.EqualTo(op2));
                Assert.That(result.Right, Is.EqualTo(value));
            }
            else
            {
                Assert.That(result.Left, Is.EqualTo(expr.Left));
                Assert.That(result.Operation, Is.EqualTo(expr.Operation));
                Assert.That(result.Right, Is.EqualTo(expr.Right));
            }
        }
Example #3
0
            public override bool Evaluate(InterpreterScope scope, out ExpressionBase result)
            {
                var left       = GetIntegerParameter(scope, "left", out result);
                var right      = GetIntegerParameter(scope, "right", out result);
                var mathematic = new MathematicExpression(left, MathematicOperation.Add, right);

                return(mathematic.ReplaceVariables(scope, out result));
            }
Example #4
0
        public void TestRebalanceComplex()
        {
            //   var1 * 2 + 3 + 4 => {{var1 * 2} + 3} + 4
            //
            // initial parsing will create a right-weighted tree
            //
            //        *
            //   var1     +
            //          2     +
            //              3   4
            //
            // recursive rebalancing while parsing will update the lower tree first (test builds the tree in this state)
            //
            //        *
            //   var1         +
            //            +     4
            //          2   3
            //
            // so when we rebalance the upper tree, we need to pull the 2 all the way up
            //
            //            +
            //        *       +
            //   var1   2   3   4
            //
            // then rebalance the new upper tree
            //
            //                +
            //            +      4
            //        *     3
            //   var1   2

            var variable1 = new VariableExpression("variable1");
            var variable2 = new VariableExpression("variable2");
            var value2    = new IntegerConstantExpression(2);
            var value3    = new IntegerConstantExpression(3);
            var value4    = new IntegerConstantExpression(4);
            var clause2   = new MathematicExpression(value2, MathematicOperation.Add, value3);
            var clause1   = new MathematicExpression(clause2, MathematicOperation.Add, value4);
            var expr      = new MathematicExpression(variable1, MathematicOperation.Multiply, clause1);

            var result = expr.Rebalance() as MathematicExpression;

            Assert.That(result, Is.Not.Null);
            Assert.That(result.Operation, Is.EqualTo(MathematicOperation.Add));
            Assert.That(result.Right, Is.InstanceOf <IntegerConstantExpression>());
            var expectedLeft = result.Left as MathematicExpression;

            Assert.That(expectedLeft, Is.Not.Null);
            Assert.That(expectedLeft.Operation, Is.EqualTo(MathematicOperation.Add));
            Assert.That(expectedLeft.Right, Is.InstanceOf <IntegerConstantExpression>());
            var expectedLeftLeft = expectedLeft.Left as MathematicExpression;

            Assert.That(expectedLeftLeft, Is.Not.Null);
            Assert.That(expectedLeftLeft.Operation, Is.EqualTo(MathematicOperation.Multiply));
            Assert.That(expectedLeftLeft.Left, Is.InstanceOf <VariableExpression>());
            Assert.That(expectedLeftLeft.Right, Is.InstanceOf <IntegerConstantExpression>());
        }
Example #5
0
        public void TestAppendString(MathematicOperation op, string expected)
        {
            var variable = new VariableExpression("variable");
            var value    = new IntegerConstantExpression(99);
            var expr     = new MathematicExpression(variable, op, value);

            var builder = new StringBuilder();

            expr.AppendString(builder);
            Assert.That(builder.ToString(), Is.EqualTo(expected));
        }
Example #6
0
        protected override ExpressionBase Combine(ExpressionBase left, ExpressionBase right)
        {
            if (left == null)
            {
                return(right);
            }

            var combined = new MathematicExpression(left, MathematicOperation.Add, right);

            return(combined.MergeOperands());
        }
Example #7
0
        public void TestBitwiseAndZero()
        {
            var left  = new IntegerConstantExpression(0xCF);
            var right = new IntegerConstantExpression(0);
            var expr  = new MathematicExpression(left, MathematicOperation.BitwiseAnd, right);
            var scope = new InterpreterScope();

            ExpressionBase result;

            Assert.That(expr.ReplaceVariables(scope, out result), Is.True);
            Assert.That(result, Is.InstanceOf <IntegerConstantExpression>());
            Assert.That(((IntegerConstantExpression)result).Value, Is.EqualTo(0));
        }
Example #8
0
        public void TestRebalance()
        {
            var variable = new VariableExpression("variable");
            var value    = new IntegerConstantExpression(99);
            var expr     = new MathematicExpression(variable, MathematicOperation.Add, value);

            var result = expr.Rebalance() as MathematicExpression;

            Assert.That(result, Is.Not.Null);
            Assert.That(result.Left, Is.EqualTo(expr.Left));
            Assert.That(result.Operation, Is.EqualTo(expr.Operation));
            Assert.That(result.Right, Is.EqualTo(expr.Right));
        }
Example #9
0
        public void TestAddStrings()
        {
            var left  = new StringConstantExpression("ban");
            var right = new StringConstantExpression("ana");
            var expr  = new MathematicExpression(left, MathematicOperation.Add, right);
            var scope = new InterpreterScope();

            ExpressionBase result;

            Assert.That(expr.ReplaceVariables(scope, out result), Is.True);
            Assert.That(result, Is.InstanceOf <StringConstantExpression>());
            Assert.That(((StringConstantExpression)result).Value, Is.EqualTo("banana"));
        }
        public void TestGetModificationsUpdateSelf()
        {
            var variable   = new VariableExpression("variable1");
            var value      = new IntegerConstantExpression(1);
            var mathematic = new MathematicExpression(variable, MathematicOperation.Add, value);
            var expr       = new AssignmentExpression(variable, mathematic);

            var modifications = new HashSet <string>();

            ((INestedExpressions)expr).GetModifications(modifications);

            Assert.That(modifications.Count, Is.EqualTo(1));
            Assert.That(modifications.Contains("variable1"));
        }
        public void TestGetDependenciesUpdateSelf()
        {
            var variable   = new VariableExpression("variable1");
            var value      = new IntegerConstantExpression(1);
            var mathematic = new MathematicExpression(variable, MathematicOperation.Add, value);
            var expr       = new AssignmentExpression(variable, mathematic);

            var dependencies = new HashSet <string>();

            ((INestedExpressions)expr).GetDependencies(dependencies);

            Assert.That(dependencies.Count, Is.EqualTo(1));
            Assert.That(dependencies.Contains("variable1")); // variable1 is read from before it's assigned
        }
Example #12
0
        private bool ReplaceVariablesMathematic(MathematicExpression mathematic, InterpreterScope scope, out ExpressionBase result)
        {
            // assert: left/right already expanded by calling function
            var left = mathematic.Left;

            var mathematicLeft = left as MathematicExpression;

            if (mathematicLeft != null)
            {
                if (!ReplaceVariablesMathematic(mathematicLeft, scope, out result))
                {
                    return(false);
                }

                left = result;
            }
            else if (left.Type != ExpressionType.IntegerConstant)
            {
                if (!WrapMemoryAccessor(left, scope, out result))
                {
                    return(false);
                }
                left = result;
            }

            var right           = mathematic.Right;
            var mathematicRight = right as MathematicExpression;

            if (mathematicRight != null)
            {
                if (!ReplaceVariablesMathematic(mathematicRight, scope, out result))
                {
                    return(false);
                }

                right = result;
            }
            else if (right.Type != ExpressionType.IntegerConstant)
            {
                if (!WrapMemoryAccessor(right, scope, out result))
                {
                    return(false);
                }
                right = result;
            }

            result = new MathematicExpression(left, mathematic.Operation, right);
            CopyLocation(result);
            return(true);
        }
Example #13
0
        public void TestAddZero()
        {
            var left  = new FunctionCallExpression("byte", new[] { new IntegerConstantExpression(0) });
            var right = new IntegerConstantExpression(0);
            var expr  = new MathematicExpression(left, MathematicOperation.Add, right);
            var scope = new InterpreterScope();

            scope.Context = new TriggerBuilderContext();
            scope.AddFunction(new MemoryAccessorFunction("byte", FieldSize.Byte));

            ExpressionBase result;

            Assert.That(expr.ReplaceVariables(scope, out result), Is.True);
            Assert.That(result.ToString(), Is.EqualTo(left.ToString()));
        }
Example #14
0
        public void TestModulusZero()
        {
            var left  = new FunctionCallExpression("byte", new[] { new IntegerConstantExpression(0) });
            var right = new IntegerConstantExpression(0);
            var expr  = new MathematicExpression(left, MathematicOperation.Modulus, right);
            var scope = new InterpreterScope();

            scope.Context = new TriggerBuilderContext();
            scope.AddFunction(new MemoryAccessorFunction("byte", FieldSize.Byte));

            ExpressionBase result;

            Assert.That(expr.ReplaceVariables(scope, out result), Is.False);
            Assert.That(((ParseErrorExpression)result).Message, Is.EqualTo("Division by zero"));
        }
Example #15
0
        public void TestReplaceVariablesAppendMathematic()
        {
            var variable = new VariableExpression("variable");
            var value    = new IntegerConstantExpression(1);
            var append   = new MathematicExpression(variable, MathematicOperation.Add, value);
            var expr     = new AssignmentExpression(variable, append);

            var scope = new InterpreterScope();

            // variable doesn't have a current value, addition not supported
            ExpressionBase result;

            Assert.That(expr.ReplaceVariables(scope, out result), Is.False);
            Assert.That(result, Is.InstanceOf <ParseErrorExpression>());
            Assert.That(((ParseErrorExpression)result).Message, Is.EqualTo("Unknown variable: variable"));
        }
Example #16
0
        public void TestRebalanceMathematical()
        {
            // "A < B + C" => "A < (B + C)"
            var variable1   = new VariableExpression("variable1");
            var variable2   = new VariableExpression("variable2");
            var value       = new IntegerConstantExpression(99);
            var conditional = new MathematicExpression(value, MathematicOperation.Add, variable2);
            var expr        = new ComparisonExpression(variable1, ComparisonOperation.LessThan, conditional);

            var result = expr.Rebalance() as ComparisonExpression;

            Assert.That(result, Is.Not.Null);
            Assert.That(result.Left, Is.EqualTo(expr.Left));
            Assert.That(result.Operation, Is.EqualTo(expr.Operation));
            Assert.That(result.Right, Is.EqualTo(expr.Right));
        }
Example #17
0
        public void TestRebalanceCondition()
        {
            // A + B && C => (A + B) && C
            var variable1 = new VariableExpression("variable1");
            var variable2 = new VariableExpression("variable2");
            var value     = new IntegerConstantExpression(99);
            var clause    = new ConditionalExpression(variable2, ConditionalOperation.And, value);
            var expr      = new MathematicExpression(variable1, MathematicOperation.Add, clause);

            var result = expr.Rebalance() as ConditionalExpression;

            Assert.That(result, Is.Not.Null);
            var expectedLeft = new MathematicExpression(variable1, MathematicOperation.Add, variable2);

            Assert.That(result.Left, Is.EqualTo(expectedLeft));
            Assert.That(result.Operation, Is.EqualTo(clause.Operation));
            Assert.That(result.Right, Is.EqualTo(value));
        }
Example #18
0
        public void TestAddVariables()
        {
            var value1 = new IntegerConstantExpression(1);
            var value2 = new IntegerConstantExpression(2);
            var left   = new VariableExpression("left");
            var right  = new VariableExpression("right");
            var expr   = new MathematicExpression(left, MathematicOperation.Add, right);
            var scope  = new InterpreterScope();

            scope.AssignVariable(left, value1);
            scope.AssignVariable(right, value2);

            ExpressionBase result;

            Assert.That(expr.ReplaceVariables(scope, out result), Is.True);
            Assert.That(result, Is.InstanceOf <IntegerConstantExpression>());
            Assert.That(((IntegerConstantExpression)result).Value, Is.EqualTo(3));
        }
Example #19
0
        public void TestReplaceVariablesIndexMathematical()
        {
            var variable = new VariableExpression("variable");
            var key      = new IntegerConstantExpression(6);
            var index    = new MathematicExpression(new IntegerConstantExpression(2), MathematicOperation.Add, new IntegerConstantExpression(4));
            var value    = new IntegerConstantExpression(99);
            var dict     = new DictionaryExpression();

            dict.Add(key, value);
            var expr = new IndexedVariableExpression(variable, index);

            var scope = new InterpreterScope();

            scope.AssignVariable(variable, dict);

            ExpressionBase result;

            Assert.That(expr.ReplaceVariables(scope, out result), Is.True);
            Assert.That(result, Is.InstanceOf <IntegerConstantExpression>());
            Assert.That(((IntegerConstantExpression)result).Value, Is.EqualTo(99));
        }
Example #20
0
        private static bool MergeFields(Field field, Term term, MathematicOperation operation)
        {
            ExpressionBase right;

            if (field.Type == FieldType.Value)
            {
                right = new IntegerConstantExpression((int)field.Value);
            }
            else if (field.Type == FieldType.Float)
            {
                right = new FloatConstantExpression(field.Float);
            }
            else
            {
                return(false);
            }

            ExpressionBase left = null;

            if (term.multiplier == 1.0)
            {
                if (term.field.Type == FieldType.Value)
                {
                    left = new IntegerConstantExpression((int)term.field.Value);
                }
                else if (term.field.Type == FieldType.Float)
                {
                    left = new FloatConstantExpression(term.field.Float);
                }
            }

            if (left == null)
            {
                FloatConstantExpression floatRight;
                switch (operation)
                {
                case MathematicOperation.Multiply:
                    floatRight = FloatConstantExpression.ConvertFrom(right) as FloatConstantExpression;
                    if (floatRight == null)
                    {
                        return(false);
                    }

                    term.multiplier *= floatRight.Value;
                    return(true);

                case MathematicOperation.Divide:
                    floatRight = FloatConstantExpression.ConvertFrom(right) as FloatConstantExpression;
                    if (floatRight == null)
                    {
                        return(false);
                    }

                    term.multiplier /= floatRight.Value;
                    return(true);

                default:
                    return(false);
                }
            }

            var mathematicExpression = new MathematicExpression(left, operation, right);

            term.field = AchievementBuilder.CreateFieldFromExpression(mathematicExpression.MergeOperands());
            return(true);
        }
Example #21
0
        private ParseErrorExpression ExecuteAchievementComparison(ComparisonExpression comparison, InterpreterScope scope)
        {
            _equalityModifiers.Clear();

            var context     = scope.GetContext <TriggerBuilderContext>();
            var insertIndex = context.Trigger.Count;

            var left  = comparison.Left;
            var right = comparison.Right;

            var op = GetRequirementOperator(comparison.Operation);

            if (left.Type == ExpressionType.IntegerConstant)
            {
                if (right.Type == ExpressionType.IntegerConstant)
                {
                    // comparing two constants, convert to always_true or always_false
                    var requirement = new Requirement
                    {
                        Left = new Field {
                            Type = FieldType.Value, Value = (uint)((IntegerConstantExpression)left).Value
                        },
                        Operator = op,
                        Right    = new Field {
                            Type = FieldType.Value, Value = (uint)((IntegerConstantExpression)right).Value
                        },
                    };

                    if (Evaluate(requirement))
                    {
                        context.Trigger.Add(AlwaysTrueFunction.CreateAlwaysTrueRequirement());
                    }
                    else
                    {
                        context.Trigger.Add(AlwaysFalseFunction.CreateAlwaysFalseRequirement());
                    }

                    return(null);
                }

                // swap the operands and operator so the constant is on the right
                var temp = left;
                left  = right;
                right = temp;

                op = GetReversedRequirementOperator(op);
            }

            var error = ExecuteAchievementExpression(left, scope);

            if (error != null)
            {
                return(error);
            }

            var integerRight = right as IntegerConstantExpression;

            if (integerRight != null)
            {
                int newValue = integerRight.Value;

                // SubSource of a memory accessor may cause overflow - if comparing for less than,
                // modifiers should not be merged into the compare target
                if (_equalityModifiers.Count > 0 &&
                    (op == RequirementOperator.LessThan || op == RequirementOperator.LessThanOrEqual))
                {
                    bool hasSubSource = false;
                    for (int i = context.Trigger.Count - 2; i >= 0; i++)
                    {
                        var requirementType = context.Trigger.ElementAt(i).Type;
                        if (requirementType == RequirementType.SubSource)
                        {
                            hasSubSource = true;
                            break;
                        }
                        else if (requirementType != RequirementType.AddSource &&
                                 requirementType != RequirementType.AddHits)
                        {
                            break;
                        }
                    }

                    if (hasSubSource)
                    {
                        var last = context.Trigger.Last();
                        context.Trigger.Remove(last);
                        foreach (var modifier in _equalityModifiers)
                        {
                            if (modifier.Operation != MathematicOperation.Subtract && modifier.Operation != MathematicOperation.Add)
                            {
                                return(new ParseErrorExpression("Cannot normalize expression containing SubSource", left));
                            }

                            context.Trigger.Add(new Requirement
                            {
                                Type = (modifier.Operation == MathematicOperation.Subtract) ? RequirementType.AddSource : RequirementType.SubSource,
                                Left = new Field {
                                    Type = FieldType.Value, Value = (uint)modifier.Amount
                                },
                                Operator = RequirementOperator.None,
                                Right    = new Field()
                            });
                        }
                        context.Trigger.Add(last);

                        _equalityModifiers.Clear();
                    }
                }

                while (_equalityModifiers.Count > 0)
                {
                    var originalValue = newValue;
                    var modifier      = _equalityModifiers.Pop();
                    newValue = modifier.Apply(newValue);

                    var restoredValue = modifier.Remove(newValue);
                    switch (op)
                    {
                    case RequirementOperator.Equal:
                        if (restoredValue != originalValue)
                        {
                            return(new ParseErrorExpression("Result can never be true using integer math", comparison));
                        }
                        break;

                    case RequirementOperator.NotEqual:
                        if (restoredValue != originalValue)
                        {
                            return(new ParseErrorExpression("Result is always true using integer math", comparison));
                        }
                        break;

                    case RequirementOperator.GreaterThanOrEqual:
                        if (restoredValue != originalValue)
                        {
                            op = RequirementOperator.GreaterThan;
                        }
                        break;
                    }
                }

                var requirement = context.LastRequirement;
                requirement.Operator = op;
                requirement.Right    = new Field {
                    Size = requirement.Left.Size, Type = FieldType.Value, Value = (uint)newValue
                };
            }
            else
            {
                var leftModifiers = new Stack <ValueModifier>(_equalityModifiers.Reverse());
                _equalityModifiers.Clear();

                error = ExecuteAchievementExpression(right, scope);
                if (error != null)
                {
                    return(error);
                }

                if (leftModifiers.Count > 0 || _equalityModifiers.Count > 0)
                {
                    var rightValue = 1234567;
                    var leftValue  = rightValue;
                    while (leftModifiers.Count > 0)
                    {
                        var modifier = leftModifiers.Pop();
                        leftValue = ValueModifier.Apply(leftValue, MathematicExpression.GetOppositeOperation(modifier.Operation), modifier.Amount);
                    }

                    while (_equalityModifiers.Count > 0)
                    {
                        var modifier = _equalityModifiers.Pop();
                        rightValue = ValueModifier.Apply(rightValue, MathematicExpression.GetOppositeOperation(modifier.Operation), modifier.Amount);
                    }

                    var diff = leftValue - rightValue;
                    if (diff != 0)
                    {
                        var modifier = new Requirement();

                        if (diff < 0)
                        {
                            modifier.Left = new Field {
                                Type = FieldType.Value, Value = (uint)(-diff)
                            };
                            modifier.Type = RequirementType.SubSource;
                        }
                        else
                        {
                            modifier.Left = new Field {
                                Type = FieldType.Value, Value = (uint)diff
                            };
                            modifier.Type = RequirementType.AddSource;
                        }

                        ((IList <Requirement>)context.Trigger).Insert(insertIndex, modifier);
                    }
                }

                var extraRequirement = context.LastRequirement;
                context.Trigger.Remove(extraRequirement);

                var requirement = context.LastRequirement;
                if (requirement != null)
                {
                    requirement.Operator = op;
                    requirement.Right    = extraRequirement.Left;
                }
            }

            return(null);
        }
Example #22
0
        private static bool ProcessValueExpression(ExpressionBase expression, InterpreterScope scope, List <Term> terms, out ExpressionBase result)
        {
            var functionCall = expression as FunctionCallExpression;

            if (functionCall != null)
            {
                var requirements = new List <Requirement>();
                var context      = new ValueBuilderContext()
                {
                    Trigger = requirements
                };
                var valueScope = new InterpreterScope(scope)
                {
                    Context = context
                };
                var error = context.CallFunction(functionCall, valueScope);
                if (error != null)
                {
                    result = error;
                    return(false);
                }

                SetImpliedMeasuredTarget(requirements);
                return(ProcessMeasuredValue(requirements, expression, terms, out result));
            }

            var field = AchievementBuilder.CreateFieldFromExpression(expression);

            if (field.Type != FieldType.None)
            {
                terms.Last().field = field;
                result = null;
                return(true);
            }

            var mathematic = expression as MathematicExpression;

            if (mathematic != null)
            {
                if (mathematic.Operation == MathematicOperation.Multiply || mathematic.Operation == MathematicOperation.Divide)
                {
                    var mathematicLeft = mathematic.Left as MathematicExpression;
                    if (mathematicLeft != null && MathematicExpression.GetPriority(mathematicLeft.Operation) == MathematicPriority.Add)
                    {
                        var newLeft  = new MathematicExpression(mathematicLeft.Left, mathematic.Operation, mathematic.Right);
                        var newRight = new MathematicExpression(mathematicLeft.Right, mathematic.Operation, mathematic.Right);
                        mathematic = new MathematicExpression(newLeft, mathematicLeft.Operation, newRight);
                    }
                }

                if (!ProcessValueExpression(mathematic.Left, scope, terms, out result))
                {
                    return(false);
                }

                field = AchievementBuilder.CreateFieldFromExpression(mathematic.Right);
                if (MergeFields(field, terms.Last(), mathematic.Operation))
                {
                    return(true);
                }

                switch (mathematic.Operation)
                {
                case MathematicOperation.Add:
                    terms.Add(new Term {
                        multiplier = 1.0
                    });
                    return(ProcessValueExpression(mathematic.Right, scope, terms, out result));

                case MathematicOperation.Subtract:
                    terms.Add(new Term {
                        multiplier = -1.0
                    });
                    return(ProcessValueExpression(mathematic.Right, scope, terms, out result));

                case MathematicOperation.Multiply:
                case MathematicOperation.Divide:
                    return(ProcessValueExpression(WrapInMeasured(expression), scope, terms, out result));
                }
            }

            var conditionalExpression = expression as ConditionalExpression;

            if (conditionalExpression != null)
            {
                ParseErrorExpression parseError;
                var achievement = new ScriptInterpreterAchievementBuilder();
                if (!achievement.PopulateFromExpression(expression, scope, out parseError))
                {
                    result = parseError;
                    return(false);
                }

                SetImpliedMeasuredTarget(achievement.CoreRequirements);
                foreach (var alt in achievement.AlternateRequirements)
                {
                    SetImpliedMeasuredTarget(alt);
                }

                var message = achievement.Optimize();
                if (message != null)
                {
                    result = new ParseErrorExpression(message, expression);
                    return(false);
                }

                if (achievement.AlternateRequirements.Any())
                {
                    result = new ParseErrorExpression("Alt groups not supported in value expression", expression);
                    return(false);
                }

                return(ProcessMeasuredValue(achievement.CoreRequirements, expression, terms, out result));
            }

            result = new ParseErrorExpression("Value must be a constant or a memory accessor", expression);
            return(false);
        }
Example #23
0
        private ParseErrorExpression ExecuteAchievementMathematic(MathematicExpression mathematic, InterpreterScope scope)
        {
            var left      = mathematic.Left;
            var operation = mathematic.Operation;
            var context   = scope.GetContext <TriggerBuilderContext>();
            ParseErrorExpression error;

            ExpressionBase right;

            if (!mathematic.Right.ReplaceVariables(scope, out right))
            {
                return((ParseErrorExpression)right);
            }

            if (operation == MathematicOperation.Subtract && (right is FunctionCallExpression || right is MathematicExpression))
            {
                // if subtracting a non-integer, swap the order to perform a SubSource
                var newEqualityModifiers = new Stack <ValueModifier>();
                var oldEqualityModifiers = _equalityModifiers;
                _equalityModifiers = newEqualityModifiers;

                var requirements = new List <Requirement>();
                var innerContext = new TriggerBuilderContext()
                {
                    Trigger = requirements
                };
                var innerScope = new InterpreterScope(scope)
                {
                    Context = innerContext
                };

                // generate the condition for the right side
                error = ExecuteAchievementExpression(right, innerScope);
                _equalityModifiers = oldEqualityModifiers;
                if (error != null)
                {
                    return(error);
                }

                foreach (var requirement in requirements)
                {
                    switch (requirement.Type)
                    {
                    case RequirementType.None:
                    case RequirementType.AddSource:
                        requirement.Type = RequirementType.SubSource;
                        break;

                    case RequirementType.SubSource:
                        requirement.Type = RequirementType.AddSource;
                        break;

                    default:
                        return(new ParseErrorExpression("Cannot normalize expression for negation", mathematic));
                    }

                    context.Trigger.Add(requirement);
                }

                foreach (var modifier in newEqualityModifiers)
                {
                    switch (modifier.Operation)
                    {
                    case MathematicOperation.Add:
                        _equalityModifiers.Push(new ValueModifier(MathematicOperation.Subtract, modifier.Amount));
                        break;

                    case MathematicOperation.Subtract:
                        _equalityModifiers.Push(new ValueModifier(MathematicOperation.Add, modifier.Amount));
                        break;

                    default:
                        return(new ParseErrorExpression("Cannot normalize expression for negation", mathematic));
                    }
                }

                right     = mathematic.Left;
                operation = MathematicOperation.Add;
            }
            else
            {
                // generate the condition for the first expression
                error = ExecuteAchievementExpression(left, scope);
                if (error != null)
                {
                    return(error);
                }
            }

            var integerOperand = right as IntegerConstantExpression;

            if (integerOperand != null)
            {
                var oppositeOperation = MathematicExpression.GetOppositeOperation(operation);
                if (oppositeOperation == MathematicOperation.None)
                {
                    return(new ParseErrorExpression(String.Format("Cannot normalize expression to eliminate {0}", MathematicExpression.GetOperatorType(mathematic.Operation)), mathematic));
                }

                var priority = MathematicExpression.GetPriority(mathematic.Operation);
                if (priority != MathematicPriority.Add)
                {
                    if (context.Trigger.Count > 1)
                    {
                        var previousRequirementType = context.Trigger.ElementAt(context.Trigger.Count - 2).Type;
                        if (previousRequirementType == RequirementType.AddSource || previousRequirementType == RequirementType.SubSource)
                        {
                            return(new ParseErrorExpression(String.Format("Cannot normalize expression to eliminate {0}", MathematicExpression.GetOperatorType(mathematic.Operation)), mathematic));
                        }
                    }

                    if (_equalityModifiers.Any(e => MathematicExpression.GetPriority(e.Operation) != priority))
                    {
                        return(new ParseErrorExpression(String.Format("Cannot normalize expression to eliminate {0}", MathematicExpression.GetOperatorType(mathematic.Operation)), mathematic));
                    }
                }

                _equalityModifiers.Push(new ValueModifier(oppositeOperation, integerOperand.Value));
                return(null);
            }

            if (operation == MathematicOperation.Add)
            {
                foreach (var modifier in _equalityModifiers)
                {
                    if (MathematicExpression.GetPriority(modifier.Operation) != MathematicPriority.Add)
                    {
                        return(new ParseErrorExpression(String.Format("Cannot normalize expression to eliminate {0}", MathematicExpression.GetOperatorType(MathematicExpression.GetOppositeOperation(modifier.Operation))), mathematic));
                    }
                }

                // adding two memory accessors - make sure previous is AddSource or SubSource
                if (context.LastRequirement.Type != RequirementType.SubSource)
                {
                    context.LastRequirement.Type     = RequirementType.AddSource;
                    context.LastRequirement.Operator = RequirementOperator.None;
                    context.LastRequirement.Right    = new Field();
                }
            }
            else
            {
                return(new ParseErrorExpression(String.Format("Cannot normalize expression to eliminate {0}", MathematicExpression.GetOperatorType(mathematic.Operation)), mathematic));
            }

            // generate the condition for the second expression
            error = ExecuteAchievementExpression(right, scope);
            if (error != null)
            {
                error = new ParseErrorExpression(error.Message, mathematic);
            }
            return(error);
        }
        private ParseErrorExpression ExecuteAchievementMathematic(MathematicExpression mathematic, InterpreterScope scope)
        {
            ParseErrorExpression error;
            var context = scope.GetContext <TriggerBuilderContext>();

            var operation = mathematic.Operation;

            switch (operation)
            {
            case MathematicOperation.Add:
            case MathematicOperation.Subtract:
                break;

            case MathematicOperation.Multiply:
            case MathematicOperation.Divide:
            case MathematicOperation.BitwiseAnd:
                // generate the condition for the right side
                Field operand = CreateFieldFromExpression(mathematic.Right);
                if (operand.Type == FieldType.None)
                {
                    var requirements = new List <Requirement>();
                    var innerContext = new TriggerBuilderContext()
                    {
                        Trigger = requirements
                    };
                    var innerScope = new InterpreterScope(scope)
                    {
                        Context = innerContext
                    };

                    error = ExecuteAchievementExpression(mathematic.Right, innerScope);
                    if (error != null)
                    {
                        return(error);
                    }
                    if (requirements.Count > 1)
                    {
                        return(new ParseErrorExpression("Multiplication by complex value not supported", mathematic));
                    }

                    operand = requirements[0].Left;
                }

                // generate the conditions for the left side
                error = ExecuteAchievementExpression(mathematic.Left, scope);
                if (error != null)
                {
                    return(error);
                }

                if (context.LastRequirement.Operator != RequirementOperator.None)
                {
                    return(new ParseErrorExpression("Cannot generate condition using both " + context.LastRequirement.Operator + " and " + operation));
                }

                switch (operation)
                {
                case MathematicOperation.Multiply:
                    context.LastRequirement.Operator = RequirementOperator.Multiply;
                    break;

                case MathematicOperation.Divide:
                    context.LastRequirement.Operator = RequirementOperator.Divide;
                    break;

                case MathematicOperation.BitwiseAnd:
                    context.LastRequirement.Operator = RequirementOperator.BitwiseAnd;
                    break;
                }

                context.LastRequirement.Right = operand;
                return(null);

            default:
                return(new ParseErrorExpression("Cannot normalize expression to eliminate " + MathematicExpression.GetOperatorType(operation), mathematic));
            }

            var left = mathematic.Left;

            ExpressionBase right;

            if (!mathematic.Right.ReplaceVariables(scope, out right))
            {
                return((ParseErrorExpression)right);
            }

            Field field = CreateFieldFromExpression(right);

            if (field.Type != FieldType.None)
            {
                context.Trigger.Add(new Requirement
                {
                    Type     = (operation == MathematicOperation.Add) ? RequirementType.AddSource : RequirementType.SubSource,
                    Left     = field,
                    Operator = RequirementOperator.None,
                    Right    = new Field()
                });
            }

            if (operation == MathematicOperation.Subtract && (right is FunctionCallExpression || right is MathematicExpression))
            {
                // if subtracting a non-integer, swap the order to perform a SubSource
                var requirements = new List <Requirement>();
                var innerContext = new TriggerBuilderContext()
                {
                    Trigger = requirements
                };
                var innerScope = new InterpreterScope(scope)
                {
                    Context = innerContext
                };

                // generate the condition for the right side
                error = ExecuteAchievementExpression(right, innerScope);
                if (error != null)
                {
                    return(error);
                }

                foreach (var requirement in requirements)
                {
                    switch (requirement.Type)
                    {
                    case RequirementType.None:
                    case RequirementType.AddSource:
                        requirement.Type = RequirementType.SubSource;
                        break;

                    case RequirementType.SubSource:
                        requirement.Type = RequirementType.AddSource;
                        break;

                    case RequirementType.AddAddress:
                        // AddAddress is allowed as long as it's not the last requirement
                        if (ReferenceEquals(requirement, requirements.Last()))
                        {
                            return(new ParseErrorExpression("Cannot normalize expression for negation", mathematic));
                        }
                        break;

                    default:
                        return(new ParseErrorExpression("Cannot normalize expression for negation", mathematic));
                    }

                    context.Trigger.Add(requirement);
                }

                right     = mathematic.Left;
                operation = MathematicOperation.Add;
            }
            else
            {
                // generate the condition for the first expression
                error = ExecuteAchievementExpression(left, scope);
                if (error != null)
                {
                    return(error);
                }
            }

            if (field.Type != FieldType.None)
            {
                return(null);
            }

            if (operation == MathematicOperation.Add)
            {
                // adding two memory accessors - make sure previous is AddSource or SubSource
                var lastRequirement = context.LastRequirement;
                if (lastRequirement.Type != RequirementType.SubSource)
                {
                    lastRequirement.Type = RequirementType.AddSource;
                    if (lastRequirement.IsComparison)
                    {
                        lastRequirement.Operator = RequirementOperator.None;
                        lastRequirement.Right    = new Field();
                    }
                }
            }
            else
            {
                return(new ParseErrorExpression(String.Format("Cannot normalize expression to eliminate {0}", MathematicExpression.GetOperatorType(mathematic.Operation)), mathematic));
            }

            field = CreateFieldFromExpression(right);
            if (field.Type != FieldType.None)
            {
                context.Trigger.Add(new Requirement
                {
                    Type     = RequirementType.None,
                    Left     = field,
                    Operator = RequirementOperator.None,
                    Right    = new Field()
                });
                return(null);
            }

            // generate the condition for the second expression
            error = ExecuteAchievementExpression(right, scope);
            if (error != null)
            {
                error = new ParseErrorExpression(error.Message, mathematic);
            }

            // make sure the mathematic expression doesn't result in a comparison
            {
                var lastRequirement = context.LastRequirement;
                if (lastRequirement.IsComparison)
                {
                    lastRequirement.Operator = RequirementOperator.None;
                    lastRequirement.Right    = new Field();
                }
            }

            return(error);
        }
Example #25
0
        public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result)
        {
            if (!IsInTriggerClause(scope, out result))
            {
                return(false);
            }

            var parameter = GetParameter(scope, "accessor", out result);

            if (parameter == null)
            {
                return(false);
            }

            if (!parameter.ReplaceVariables(scope, out result))
            {
                return(false);
            }
            parameter = result;

            var mathematic = parameter as MathematicExpression;

            if (mathematic != null)
            {
                var left = mathematic.Left;
                if (!(left is IntegerConstantExpression))
                {
                    left = new FunctionCallExpression(Name.Name, new ExpressionBase[] { mathematic.Left });
                    if (!left.ReplaceVariables(scope, out result))
                    {
                        return(false);
                    }
                    left = result;
                }

                var right = mathematic.Right;
                if (!(right is IntegerConstantExpression))
                {
                    right = new FunctionCallExpression(Name.Name, new ExpressionBase[] { mathematic.Right });
                    if (!right.ReplaceVariables(scope, out result))
                    {
                        return(false);
                    }
                    right = result;
                }

                result = new MathematicExpression(left, mathematic.Operation, right);
                return(true);
            }

            var functionCall = parameter as FunctionCallExpression;

            if (functionCall == null)
            {
                result = new ParseErrorExpression("accessor did not evaluate to a memory accessor", parameter);
                return(false);
            }

            var functionDefinition = scope.GetFunction(functionCall.FunctionName.Name);
            var memoryAccessor     = functionDefinition as MemoryAccessorFunction;

            if (memoryAccessor == null)
            {
                result = new ParseErrorExpression("accessor did not evaluate to a memory accessor", parameter);
                return(false);
            }

            result = new FunctionCallExpression(Name.Name, new ExpressionBase[] { functionCall });
            return(true);
        }