public ParseErrorExpression CallFunction(FunctionCallExpression functionCall, InterpreterScope scope) { var functionDefinition = scope.GetFunction(functionCall.FunctionName.Name); if (functionDefinition == null) { return(new UnknownVariableParseErrorExpression("Unknown function: " + functionCall.FunctionName.Name, functionCall.FunctionName)); } var triggerBuilderFunction = functionDefinition as FunctionDefinition; if (triggerBuilderFunction == null) { return(new ParseErrorExpression(functionCall.FunctionName.Name + " cannot be called from within a trigger clause", functionCall)); } var error = triggerBuilderFunction.BuildTrigger(this, scope, functionCall); if (error != null) { return(ParseErrorExpression.WrapError(error, "Function call failed.", functionCall)); } return(null); }
internal bool PopulateFromExpression(ExpressionBase expression, InterpreterScope scope, out ParseErrorExpression error) { var andedConditions = new List <ExpressionBase>(); var orConditions = new List <ExpressionBase>(); if (!SortConditions(expression, andedConditions, orConditions, out error)) { return(false); } if (orConditions.Count() > 1) { var altPart = CrossMultiplyOrConditions(orConditions); if (altPart.Type == ExpressionType.ParseError) { expression.CopyLocation(altPart); error = (ParseErrorExpression)altPart; return(false); } andedConditions.Add(altPart); } else if (orConditions.Count() == 1) { andedConditions.Add(orConditions[0]); } var context = new TriggerBuilderContext { Trigger = CoreRequirements }; var innerScope = new InterpreterScope(scope) { Context = context }; foreach (var condition in andedConditions) { error = ExecuteAchievementClause(condition, innerScope); if (error != null) { switch (condition.Type) { case ExpressionType.Comparison: case ExpressionType.Conditional: break; default: error = ParseErrorExpression.WrapError(error, "Invalid condition", condition); break; } return(false); } } return(true); }
private ParseErrorExpression ExecuteAchievementComparison(ComparisonExpression comparison, InterpreterScope scope) { var left = comparison.Left; var right = comparison.Right; if (left.Type == ExpressionType.Comparison || right.Type == ExpressionType.Comparison) { return(new ParseErrorExpression("comparison did not evaluate to a valid comparison", comparison)); } var context = scope.GetContext <TriggerBuilderContext>(); var op = GetRequirementOperator(comparison.Operation); var leftField = CreateFieldFromExpression(left); if (leftField.Type != FieldType.None) { var rightField = CreateFieldFromExpression(right); if (rightField.Type != FieldType.None) { // comparing two constants, convert to always_true or always_false var requirement = new Requirement { Left = leftField, Operator = op, Right = rightField, }; if (requirement.Evaluate() == true) { 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 = Requirement.GetReversedRequirementOperator(op); } var error = ExecuteAchievementExpression(left, scope); if (error != null) { return(ParseErrorExpression.WrapError(error, "Invalid value", left)); } if (right.Type == ExpressionType.IntegerConstant || right.Type == ExpressionType.FloatConstant) { var lastRequirement = context.LastRequirement; if (lastRequirement.Operator != RequirementOperator.None) { // try to rearrange so the last requirement doesn't have a modifier for (int i = context.Trigger.Count - 2; i >= 0; --i) { var requirement = context.Trigger.ElementAt(i); if (requirement.Type == RequirementType.AddSource && requirement.Operator == RequirementOperator.None) { context.Trigger.Remove(lastRequirement); context.Trigger.Add(new Requirement { Left = requirement.Left }); requirement.Left = lastRequirement.Left; requirement.Operator = lastRequirement.Operator; requirement.Right = lastRequirement.Right; lastRequirement = context.LastRequirement; break; } if (requirement.Type != RequirementType.AddSource && requirement.Type != RequirementType.SubSource && requirement.Type != RequirementType.AddAddress) { break; } } if (lastRequirement.Operator != RequirementOperator.None) { // last requirement still has a modifier, have to add a dummy condition. lastRequirement.Type = RequirementType.AddSource; context.Trigger.Add(new Requirement { Left = new Field { Size = lastRequirement.Left.Size, Type = FieldType.Value, Value = 0 } }); lastRequirement = context.LastRequirement; } } lastRequirement.Operator = op; lastRequirement.Right = CreateFieldFromExpression(right); } else { error = ExecuteAchievementExpression(right, scope); if (error != null) { return(ParseErrorExpression.WrapError(error, "Invalid value", right)); } var extraRequirement = context.LastRequirement; ((IList <Requirement>)context.Trigger).RemoveAt(context.Trigger.Count - 1); var requirement = context.LastRequirement; if (requirement != null) { if (requirement.Type == RequirementType.AddAddress) { return(HandleAddAddressComparison(comparison, (IList <Requirement>)context.Trigger, op, extraRequirement)); } else if (context.Trigger.Count > 1 && context.Trigger.ElementAt(context.Trigger.Count - 2).Type == RequirementType.AddAddress) { // if left side is an AddAddress chain, but right side is a not, we have to keep the // dummy condition to prevent the AddAddress from modifying the memory address on the // right side. integers are handled above. requirement.Type = RequirementType.AddSource; extraRequirement.Right = extraRequirement.Left; extraRequirement.Left = new Field { Type = FieldType.Value, Value = 0 }; extraRequirement.Operator = op; context.Trigger.Add(extraRequirement); } else if (requirement.Operator != RequirementOperator.None) { // if left side is a complex expression (a * 4), add a new dummy condition for the comparison requirement.Type = RequirementType.AddSource; extraRequirement.Right = extraRequirement.Left; extraRequirement.Left = new Field { Type = FieldType.Value, Value = 0 }; extraRequirement.Operator = op; context.Trigger.Add(extraRequirement); } else { // no AddAddress on either side, just merge the conditions requirement.Operator = op; requirement.Right = extraRequirement.Left; } } } return(null); }