public void TestGetConditionString(string input, string expected)
        {
            ExpressionBase   error;
            InterpreterScope scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            scope.Context = new TriggerBuilderContext();

            var expression = Parse(input);

            ExpressionBase processed;

            Assert.That(expression.ReplaceVariables(scope, out processed), Is.True);

            var result = TriggerBuilderContext.GetConditionString(processed, scope, out error);

            if (error != null)
            {
                Assert.That(((ParseErrorExpression)error).InnermostError.Message, Is.EqualTo(expected));
            }
            else
            {
                Assert.That(error, Is.Null);
                Assert.That(result, Is.EqualTo(expected));
            }
        }
        public static bool ContainsMemoryAccessor(ExpressionBase expression)
        {
            var funcCall = expression as FunctionCallExpression;

            if (funcCall != null)
            {
                var func = AchievementScriptInterpreter.GetGlobalScope().GetFunction(funcCall.FunctionName.Name);
                if (func is MemoryAccessorFunction)
                {
                    return(true);
                }

                foreach (var parameter in funcCall.Parameters)
                {
                    if (ContainsMemoryAccessor(parameter))
                    {
                        return(true);
                    }
                }

                return(false);
            }

            var leftRightExpression = expression as LeftRightExpressionBase;

            if (leftRightExpression != null)
            {
                return(ContainsMemoryAccessor(leftRightExpression.Left) || ContainsMemoryAccessor(leftRightExpression.Right));
            }

            return(false);
        }
Beispiel #3
0
        public void TestFunctionReference()
        {
            string input = "once(f)";

            var requirements = new List <Requirement>();
            var funcDef      = new OnceFunction();

            var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input)));

            Assert.That(expression, Is.InstanceOf <FunctionCallExpression>());
            var funcCall = (FunctionCallExpression)expression;

            var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            scope.AssignVariable(new VariableExpression("f"), new FunctionReferenceExpression("f2"));

            ExpressionBase error;

            scope = funcCall.GetParameters(funcDef, scope, out error);
            var context = new TriggerBuilderContext {
                Trigger = requirements
            };

            scope.Context = context;

            ExpressionBase evaluated;

            Assert.That(funcDef.ReplaceVariables(scope, out evaluated), Is.True);
            funcCall = evaluated as FunctionCallExpression;

            var parseError = funcDef.BuildTrigger(context, scope, funcCall);

            Assert.That(parseError, Is.Not.Null);
            Assert.That(parseError.InnermostError.Message, Is.EqualTo("Function used like a variable"));
        }
Beispiel #4
0
        private List <Requirement> Evaluate(string input, string expectedError = null)
        {
            var requirements = new List <Requirement>();
            var funcDef      = new RepeatedFunction();

            var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input)));

            Assert.That(expression, Is.InstanceOf <FunctionCallExpression>());
            var funcCall = (FunctionCallExpression)expression;

            ExpressionBase error;
            var            scope   = funcCall.GetParameters(funcDef, AchievementScriptInterpreter.GetGlobalScope(), out error);
            var            context = new TriggerBuilderContext {
                Trigger = requirements
            };

            scope.Context = context;

            ExpressionBase evaluated;

            Assert.That(funcDef.ReplaceVariables(scope, out evaluated), Is.True);

            if (expectedError == null)
            {
                Assert.That(funcDef.BuildTrigger(context, scope, funcCall), Is.Null);
            }
            else
            {
                var parseError = funcDef.BuildTrigger(context, scope, funcCall);
                Assert.That(parseError, Is.Not.Null);
                Assert.That(parseError.Message, Is.EqualTo(expectedError));
            }

            return(requirements);
        }
Beispiel #5
0
        public void TestSizes()
        {
            var scope = AchievementScriptInterpreter.GetGlobalScope();
            var sizes = new Dictionary <string, FieldSize>
            {
                { "byte(0x1234)", FieldSize.Byte },
                { "bit0(0x1234)", FieldSize.Bit0 },
                { "bit1(0x1234)", FieldSize.Bit1 },
                { "bit2(0x1234)", FieldSize.Bit2 },
                { "bit3(0x1234)", FieldSize.Bit3 },
                { "bit4(0x1234)", FieldSize.Bit4 },
                { "bit5(0x1234)", FieldSize.Bit5 },
                { "bit6(0x1234)", FieldSize.Bit6 },
                { "bit7(0x1234)", FieldSize.Bit7 },
                { "low4(0x1234)", FieldSize.LowNibble },
                { "high4(0x1234)", FieldSize.HighNibble },
                { "word(0x1234)", FieldSize.Word },
                { "dword(0x1234)", FieldSize.DWord },
                { "bit(0,0x1234)", FieldSize.Bit0 },
                { "bit(1,0x1234)", FieldSize.Bit1 },
                { "bit(2,0x1234)", FieldSize.Bit2 },
                { "bit(3,0x1234)", FieldSize.Bit3 },
                { "bit(4,0x1234)", FieldSize.Bit4 },
                { "bit(5,0x1234)", FieldSize.Bit5 },
                { "bit(6,0x1234)", FieldSize.Bit6 },
                { "bit(7,0x1234)", FieldSize.Bit7 },
            };

            foreach (var kvp in sizes)
            {
                var requirements = Evaluate(kvp.Key);
                Assert.That(requirements.Count, Is.EqualTo(1), kvp.Key);
                Assert.That(requirements[0].Left.Size, Is.EqualTo(kvp.Value), kvp.Key);
            }
        }
Beispiel #6
0
        public void TestTriggerWhenDefinition()
        {
            var funcDef = AchievementScriptInterpreter.GetGlobalScope().GetFunction("trigger_when");

            Assert.That(funcDef, Is.Not.Null);
            Assert.That(funcDef.Name.Name, Is.EqualTo("trigger_when"));
            Assert.That(funcDef.Parameters.Count, Is.EqualTo(1));
            Assert.That(funcDef.Parameters.ElementAt(0).Name, Is.EqualTo("comparison"));
        }
        public void TestDefinition()
        {
            var def = AchievementScriptInterpreter.GetGlobalScope().GetFunction("disable_when");

            Assert.That(def, Is.Not.Null);
            Assert.That(def.Name.Name, Is.EqualTo("disable_when"));
            Assert.That(def.Parameters.Count, Is.EqualTo(2));
            Assert.That(def.Parameters.ElementAt(0).Name, Is.EqualTo("comparison"));
            Assert.That(def.Parameters.ElementAt(1).Name, Is.EqualTo("until"));
        }
        public void TestIsTrueMemoryAccessorFunction()
        {
            var expr  = new FunctionCallExpression("byte", new ExpressionBase[] { new IntegerConstantExpression(0x1234) });
            var scope = AchievementScriptInterpreter.GetGlobalScope();

            ParseErrorExpression error;

            Assert.That(expr.IsTrue(scope, out error), Is.Null);
            Assert.That(error, Is.Null);
        }
        public void TestIsTrueAlwaysFalseFunction()
        {
            var expr  = AlwaysFalseFunction.CreateAlwaysFalseFunctionCall();
            var scope = AchievementScriptInterpreter.GetGlobalScope();

            ParseErrorExpression error;

            Assert.That(expr.IsTrue(scope, out error), Is.False);
            Assert.That(error, Is.Null);
        }
        public void TestIsTrue(string input, bool?expected)
        {
            var tokenizer = Tokenizer.CreateTokenizer(input);
            var expr      = ExpressionBase.Parse(new PositionalTokenizer(tokenizer));

            var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            scope.Context = new RATools.Parser.TriggerBuilderContext();
            ParseErrorExpression error;

            Assert.That(expr.IsTrue(scope, out error), Is.EqualTo(expected));
            Assert.That(error, Is.Null);
        }
        public void TestIsTrueUserFunctionReturningBoolean()
        {
            var userFunc = Parse("function u() => always_true()");
            var expr     = new FunctionCallExpression("u", new ExpressionBase[0]);
            var scope    = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            scope.AddFunction(userFunc);

            ParseErrorExpression error;

            Assert.That(expr.IsTrue(scope, out error), Is.True);
            Assert.That(error, Is.Null);
        }
        public void TestGetValueString(string input, string expected)
        {
            ExpressionBase   error;
            InterpreterScope scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            scope.Context = new TriggerBuilderContext();

            var expression = Parse(input);
            var result     = TriggerBuilderContext.GetValueString(expression, scope, out error);

            Assert.That(error, Is.Null);
            Assert.That(result, Is.EqualTo(expected));
        }
        public void TestIsTrue(string input, bool expected)
        {
            var tokenizer  = new PositionalTokenizer(Tokenizer.CreateTokenizer(input));
            var expression = ExpressionBase.Parse(tokenizer);

            Assert.That(expression, Is.InstanceOf <ConditionalExpression>());

            ParseErrorExpression error;
            var scope  = AchievementScriptInterpreter.GetGlobalScope();
            var result = expression.IsTrue(scope, out error);

            Assert.That(error, Is.Null);
            Assert.That(result, Is.EqualTo(expected));
        }
Beispiel #14
0
                  "trigger_when(byte(1) == 56) && trigger_when(byte(2) == 3) && trigger_when(byte(1) == 55 || byte(2) == 4)")]                             // and can be separated, but not nested ors
        public void TestReplaceVariables(string input, string expected)
        {
            var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            scope.Context = new TriggerBuilderContext();

            var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input)));

            ExpressionBase evaluated;

            Assert.That(expression.ReplaceVariables(scope, out evaluated), Is.True);

            var builder = new StringBuilder();

            evaluated.AppendString(builder);
            Assert.That(builder.ToString(), Is.EqualTo(expected));
        }
        public void TestPushMemoryComparison()
        {
            var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());
            var array = new ArrayExpression();

            scope.DefineVariable(new VariableDefinitionExpression("arr"), array);
            AddHappyFunction(scope);

            Evaluate("array_push(arr, byte(1) == 2)", scope);

            var comparison = (ComparisonExpression)array.Entries[0];

            Assert.That(comparison.Left, Is.InstanceOf <FunctionCallExpression>());
            Assert.That(((FunctionCallExpression)comparison.Left).FunctionName.Name, Is.EqualTo("byte"));
            Assert.That(comparison.Right, Is.InstanceOf <IntegerConstantExpression>());
            Assert.That(((IntegerConstantExpression)comparison.Right).Value, Is.EqualTo(2));
        }
        private RichPresenceBuilder Evaluate(string input, string expectedError = null)
        {
            var funcDef = new RichPresenceValueFunction();

            var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input)));

            Assert.That(expression, Is.InstanceOf <FunctionCallExpression>());
            var funcCall = (FunctionCallExpression)expression;

            ExpressionBase error;
            var            scope   = funcCall.GetParameters(funcDef, AchievementScriptInterpreter.GetGlobalScope(), out error);
            var            context = new RichPresenceDisplayFunction.RichPresenceDisplayContext {
                RichPresence = new RichPresenceBuilder()
            };

            scope.Context = context;

            ExpressionBase evaluated;

            if (expectedError != null && expectedError.EndsWith(" format"))
            {
                Assert.That(funcDef.ReplaceVariables(scope, out evaluated), Is.False);
                var parseError = evaluated as ParseErrorExpression;
                Assert.That(parseError, Is.Not.Null);
                Assert.That(parseError.Message, Is.EqualTo(expectedError));
                return(context.RichPresence);
            }

            ExpressionBase result;

            Assert.That(funcDef.ReplaceVariables(scope, out evaluated), Is.True);
            if (expectedError == null)
            {
                Assert.That(funcDef.BuildMacro(context, scope, out result), Is.True);
                context.RichPresence.DisplayString = ((StringConstantExpression)result).Value;
            }
            else
            {
                Assert.That(funcDef.BuildMacro(context, scope, out result), Is.False);
                Assert.That(result, Is.InstanceOf <ParseErrorExpression>());
                Assert.That(((ParseErrorExpression)result).Message, Is.EqualTo(expectedError));
            }

            return(context.RichPresence);
        }
Beispiel #17
0
        public void TestExplicitCall()
        {
            // not providing a TriggerBuilderContext simulates calling the function at a global scope
            var funcDef = new MemoryAccessorFunction("byte", FieldSize.Byte);

            var input      = "byte(0x1234)";
            var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input)));

            Assert.That(expression, Is.InstanceOf <FunctionCallExpression>());
            var funcCall = (FunctionCallExpression)expression;

            ExpressionBase error;
            var            scope = funcCall.GetParameters(funcDef, AchievementScriptInterpreter.GetGlobalScope(), out error);

            Assert.That(funcDef.Evaluate(scope, out error), Is.False);
            Assert.That(error, Is.InstanceOf <ParseErrorExpression>());
            Assert.That(((ParseErrorExpression)error).Message, Is.EqualTo("byte has no meaning outside of a trigger clause"));
        }
Beispiel #18
0
        public void TestExplicitCall()
        {
            // not providing a RichPresenceDisplayContext simulates calling the function at a global scope
            var funcDef = new RichPresenceValueFunction();

            var input      = "rich_presence_value(\"Name\", byte(0x1234))";
            var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input)));

            Assert.That(expression, Is.InstanceOf <FunctionCallExpression>());
            var funcCall = (FunctionCallExpression)expression;

            ExpressionBase error;
            var            scope = funcCall.GetParameters(funcDef, AchievementScriptInterpreter.GetGlobalScope(), out error);

            Assert.That(funcDef.Evaluate(scope, out error), Is.False);
            Assert.That(error, Is.InstanceOf <ParseErrorExpression>());
            Assert.That(((ParseErrorExpression)error).Message, Is.EqualTo("rich_presence_value has no meaning outside of a rich_presence_display call"));
        }
Beispiel #19
0
        public void TestReplaceVariablesMemoryAccessor()
        {
            var value = new FunctionCallExpression("byte", new[] { new IntegerConstantExpression(1) });
            var expr  = new ArrayExpression();

            expr.Entries.Add(value);

            var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            ExpressionBase result;

            Assert.That(expr.ReplaceVariables(scope, out result), Is.True);

            Assert.That(result, Is.InstanceOf <ArrayExpression>());
            var arrayResult = (ArrayExpression)result;

            Assert.That(arrayResult.Entries.Count, Is.EqualTo(1));
            Assert.That(arrayResult.Entries[0].ToString(), Is.EqualTo(value.ToString()));
        }
        public void TestReplaceVariablesLogicalFunctionCall()
        {
            var functionDefinition = UserFunctionDefinitionExpression.ParseForTest("function func(i) => byte(i) == 1");

            var functionCall = new FunctionCallExpression("func", new ExpressionBase[] { new IntegerConstantExpression(2) });
            var value1       = new IntegerConstantExpression(98);
            var expr         = new DictionaryExpression();

            expr.Add(functionCall, value1);

            var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            scope.AddFunction(functionDefinition);

            ExpressionBase result;

            Assert.That(expr.ReplaceVariables(scope, out result), Is.False);
            Assert.That(result, Is.InstanceOf <ParseErrorExpression>());
            Assert.That(((ParseErrorExpression)result).Message, Is.EqualTo("Dictionary key must evaluate to a constant"));
        }
Beispiel #21
0
        protected override void OnUpdateSyntax(ContentChangedEventArgs e)
        {
            bool needsUpdate = false;

            // parse immediately so we can update the syntax highlighting
            var tokenizer = Tokenizer.CreateTokenizer(e.Content);

            if (_parsedContent == null || e.Type == ContentChangeType.Refresh)
            {
                _parsedContent               = new ExpressionGroupCollection();
                _parsedContent.Scope         = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());
                _parsedContent.Scope.Context = new AchievementScriptContext();

                lock (_parsedContent)
                {
                    _parsedContent.Parse(tokenizer);
                    needsUpdate = true;
                }
            }
            else if (e.Type == ContentChangeType.Update)
            {
                lock (_parsedContent)
                {
                    needsUpdate = _parsedContent.Update(tokenizer, e.AffectedLines);
                }

                if (!needsUpdate && !e.IsAborted)
                {
                    UpdateErrorList();
                }
            }

            if (needsUpdate && !e.IsAborted)
            {
                // running the script can take a lot of time, push that work onto a background thread and show progress bar
                UpdateProgress(1, 0);

                // make sure to at least show the script file in the editor list
                if (!_owner.Editors.Any())
                {
                    _owner.PopulateEditorList(null);
                }

                ServiceRepository.Instance.FindService <IBackgroundWorkerService>().RunAsync(() =>
                {
                    if (!e.IsAborted)
                    {
                        // run the script
                        var callback    = new ScriptInterpreterCallback(this, e);
                        var interpreter = new AchievementScriptInterpreter();

                        bool hadErrors, hasErrors;
                        lock (_parsedContent)
                        {
                            hadErrors = _parsedContent.HasEvaluationErrors;
                            hasErrors = !interpreter.Run(_parsedContent, callback);
                        }

                        if (!e.IsAborted)
                        {
                            UpdateProgress(100, 0);

                            // if any errors were added or removed, update the highlighting
                            if (hasErrors != hadErrors)
                            {
                                UpdateSyntaxHighlighting(e);
                            }

                            // report any errors
                            UpdateErrorList();

                            if (!e.IsAborted)
                            {
                                // update the editor list
                                _owner.PopulateEditorList(interpreter);
                            }
                        }
                    }

                    // make sure the progress bar is hidden
                    UpdateProgress(0, 0);
                });
            }

            base.OnUpdateSyntax(e);
        }
Beispiel #22
0
        protected new ExpressionBase Parse(PositionalTokenizer tokenizer)
        {
            ExpressionBase.SkipWhitespace(tokenizer);
            if (tokenizer.NextChar != '(')
            {
                return(ExpressionBase.ParseError(tokenizer, "Expected '(' after function name", Name));
            }
            tokenizer.Advance();

            ExpressionBase.SkipWhitespace(tokenizer);
            if (tokenizer.NextChar != ')')
            {
                do
                {
                    var line   = tokenizer.Line;
                    var column = tokenizer.Column;

                    var parameter = tokenizer.ReadIdentifier();
                    if (parameter.IsEmpty)
                    {
                        return(ExpressionBase.ParseError(tokenizer, "Invalid parameter name", line, column));
                    }

                    var variableDefinition = new VariableDefinitionExpression(parameter.ToString(), line, column);
                    Parameters.Add(variableDefinition);

                    ExpressionBase.SkipWhitespace(tokenizer);

                    if (tokenizer.NextChar == '=')
                    {
                        tokenizer.Advance();
                        ExpressionBase.SkipWhitespace(tokenizer);

                        var value = ExpressionBase.Parse(tokenizer);
                        if (value.Type == ExpressionType.ParseError)
                        {
                            return(ExpressionBase.ParseError(tokenizer, "Invalid default value for " + parameter.ToString(), value));
                        }

                        var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());
                        scope.Context = new TriggerBuilderContext(); // prevent errors passing memory references as default parameters

                        ExpressionBase evaluated;
                        if (!value.ReplaceVariables(scope, out evaluated))
                        {
                            return(ExpressionBase.ParseError(tokenizer, "Default value for " + parameter.ToString() + " is not constant", evaluated));
                        }

                        DefaultParameters[parameter.ToString()] = evaluated;
                    }
                    else if (DefaultParameters.Count > 0)
                    {
                        return(ExpressionBase.ParseError(tokenizer,
                                                         string.Format("Non-default parameter {0} appears after default parameters", parameter.ToString()), variableDefinition));
                    }

                    if (tokenizer.NextChar == ')')
                    {
                        break;
                    }

                    if (tokenizer.NextChar != ',')
                    {
                        return(ExpressionBase.ParseError(tokenizer, "Expected ',' or ')' after parameter name, found: " + tokenizer.NextChar));
                    }

                    tokenizer.Advance();
                    ExpressionBase.SkipWhitespace(tokenizer);
                } while (true);
            }

            tokenizer.Advance(); // closing parenthesis
            ExpressionBase.SkipWhitespace(tokenizer);

            ExpressionBase expression;

            if (tokenizer.Match("=>"))
            {
                return(ParseShorthandBody(tokenizer));
            }

            if (tokenizer.NextChar != '{')
            {
                return(ExpressionBase.ParseError(tokenizer, "Expected '{' after function declaration", Name));
            }

            tokenizer.Advance();
            ExpressionBase.SkipWhitespace(tokenizer);

            bool seenReturn = false;

            while (tokenizer.NextChar != '}')
            {
                expression = ExpressionBase.Parse(tokenizer);
                if (expression.Type == ExpressionType.ParseError)
                {
                    // the ExpressionTokenizer will capture the error, we should still return the incomplete FunctionDefinition
                    if (tokenizer is ExpressionTokenizer)
                    {
                        break;
                    }

                    // not an ExpressionTokenizer, just return the error
                    return(expression);
                }

                if (expression.Type == ExpressionType.Return)
                {
                    seenReturn = true;
                }
                else if (seenReturn)
                {
                    ExpressionBase.ParseError(tokenizer, "Expression after return statement", expression);
                }

                Expressions.Add(expression);

                ExpressionBase.SkipWhitespace(tokenizer);
            }

            Location = new TextRange(Location.Start, tokenizer.Location);
            tokenizer.Advance();
            return(MakeReadOnly(this));
        }
Beispiel #23
0
        public void TestComparison()
        {
            var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            Evaluate("length(byte(0x1234) != 12)", scope, "Cannot calculate length of Comparison");
        }