예제 #1
0
        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);
        }