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); }
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); }