Example #1
0
        private static ExpressionBase ParseAssignment(PositionalTokenizer tokenizer, ExpressionBase variable, int joinerLine, int joinerColumn)
        {
            if (variable.Type != ExpressionType.Variable)
            {
                return(ParseError(tokenizer, "Cannot assign value to non-variable", variable));
            }

            var value = ExpressionBase.Parse(tokenizer);

            switch (value.Type)
            {
            case ExpressionType.ParseError:
                return(value);

            case ExpressionType.Array:
            case ExpressionType.Comparison:
            case ExpressionType.Conditional:
            case ExpressionType.Dictionary:
            case ExpressionType.FunctionCall:
            case ExpressionType.IntegerConstant:
            case ExpressionType.Mathematic:
            case ExpressionType.StringConstant:
            case ExpressionType.Variable:
                break;

            default:
                ParseError(tokenizer, "incompatible assignment", new KeywordExpression("=", joinerLine, joinerColumn));
                break;
            }

            return(new AssignmentExpression((VariableExpression)variable, value));
        }
Example #2
0
        public void TestParseExpressionGroupingLogical(string input, bool leftPrioritized)
        {
            var tokenizer  = new PositionalTokenizer(Tokenizer.CreateTokenizer(input));
            var expression = ExpressionBase.Parse(tokenizer) as ConditionalExpression;

            Assert.That(expression, Is.Not.Null);
            if (leftPrioritized)
            {
                var builder = new StringBuilder();
                expression.Conditions.ElementAt(0).AppendString(builder);
                Assert.That(builder.ToString(), Is.EqualTo(input.Substring(0, 5)));

                builder.Clear();
                expression.Conditions.ElementAt(1).AppendString(builder);
                Assert.That(builder.ToString(), Is.EqualTo(input.Substring(8, 1)));
            }
            else
            {
                var builder = new StringBuilder();
                expression.Conditions.ElementAt(0).AppendString(builder);
                Assert.That(builder.ToString(), Is.EqualTo(input.Substring(0, 1)));

                builder.Clear();
                expression.Conditions.ElementAt(1).AppendString(builder);
                Assert.That(builder.ToString(), Is.EqualTo(input.Substring(4, 5)));
            }
        }
Example #3
0
        protected static ExpressionBase ParseClause(PositionalTokenizer tokenizer)
        {
            var start = tokenizer.Location;

            var clause = ParseClauseCore(tokenizer);

            var end = clause.Location.End;

            if (end.Column == 0 || clause.Location.Start.Column == 0)
            {
                if (clause.Location.Start.Column != 0)
                {
                    start = clause.Location.Start;
                }

                if (end.Line == 0)
                {
                    end = new TextLocation(tokenizer.Line, (tokenizer.Column > 1) ? tokenizer.Column - 1 : 1);
                }

                clause.Location = new TextRange(start, end);
            }

            return(clause);
        }
Example #4
0
        private static ExpressionBase ParseArray(PositionalTokenizer tokenizer)
        {
            SkipWhitespace(tokenizer);

            var array = new ArrayExpression();

            while (tokenizer.NextChar != ']')
            {
                var value = Parse(tokenizer);
                if (value.Type == ExpressionType.ParseError)
                {
                    return(value);
                }

                array.Entries.Add(value);

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

                if (tokenizer.NextChar != ',')
                {
                    return(ParseError(tokenizer, "Expecting comma between entries"));
                }
                tokenizer.Advance();
                SkipWhitespace(tokenizer);
            }

            tokenizer.Advance();
            return(array);
        }
Example #5
0
        public void TestSkipWhitespaceMultiComment()
        {
            var tokenizer = new PositionalTokenizer(Tokenizer.CreateTokenizer("  // comment\r\n// comment2\r\nhi"));

            ExpressionBase.SkipWhitespace(tokenizer);
            Assert.That(tokenizer.NextChar, Is.EqualTo('h'));
        }
        public void TestReplaceVariables(string input, string expected)
        {
            input = input.Replace("A", "byte(10)");
            input = input.Replace("B", "byte(11)");
            input = input.Replace("C", "byte(12)");

            expected = expected.Replace("A", "byte(10)");
            expected = expected.Replace("B", "byte(11)");
            expected = expected.Replace("C", "byte(12)");

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

            var scope = new InterpreterScope();

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

            ExpressionBase result;

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

            var builder = new StringBuilder();

            result.AppendString(builder);
            Assert.That(builder.ToString(), Is.EqualTo(expected));
        }
Example #7
0
        public void TestReplaceVariablesMethodCall()
        {
            var input     = "function func(i) { j = i }";
            var tokenizer = new PositionalTokenizer(Tokenizer.CreateTokenizer(input));

            tokenizer.Match("function");
            var functionDefinition = (FunctionDefinitionExpression)FunctionDefinitionExpression.Parse(tokenizer);

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

            expr.Entries.Add(new DictionaryExpression.DictionaryEntry {
                Key = functionCall, Value = value1
            });

            var scope = new InterpreterScope();

            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("func did not return a value"));
        }
Example #8
0
        public void TestParseExpressionGroupingMathematic(string input, bool leftPrioritized)
        {
            var tokenizer  = new PositionalTokenizer(Tokenizer.CreateTokenizer(input));
            var expression = ExpressionBase.Parse(tokenizer) as MathematicExpression;

            Assert.That(expression, Is.Not.Null);

            var    parts = input.Split(' ');
            string expectedLeft, expectedRight;

            if (leftPrioritized)
            {
                expectedLeft  = parts[0] + ' ' + parts[1] + ' ' + parts[2];
                expectedRight = parts[4];
            }
            else
            {
                expectedLeft  = parts[0];
                expectedRight = parts[2] + ' ' + parts[3] + ' ' + parts[4];
            }

            var builder = new StringBuilder();

            expression.Left.AppendString(builder);
            Assert.That(builder.ToString(), Is.EqualTo(expectedLeft));

            builder.Clear();
            expression.Right.AppendString(builder);
            Assert.That(builder.ToString(), Is.EqualTo(expectedRight));
        }
Example #9
0
        public void TestParseExpressionGroupingStringBuildingWithSubtraction()
        {
            var input      = "\"A\" + B + \"C\" + D - E + \"F\"";
            var tokenizer  = new PositionalTokenizer(Tokenizer.CreateTokenizer(input));
            var expression = ExpressionBase.Parse(tokenizer) as MathematicExpression;

            Assert.That(expression, Is.Not.Null);
            Assert.That(expression.Left.ToString(), Is.EqualTo("StringConstant: \"A\""));

            expression = expression.Right as MathematicExpression;
            Assert.That(expression, Is.Not.Null);
            Assert.That(expression.Left.ToString(), Is.EqualTo("Variable: B"));

            expression = expression.Right as MathematicExpression;
            Assert.That(expression, Is.Not.Null);
            Assert.That(expression.Left.ToString(), Is.EqualTo("StringConstant: \"C\""));

            expression = expression.Right as MathematicExpression;
            Assert.That(expression, Is.Not.Null);
            Assert.That(expression.Right.ToString(), Is.EqualTo("StringConstant: \"F\""));

            expression = expression.Left as MathematicExpression;
            Assert.That(expression, Is.Not.Null);
            Assert.That(expression.ToString(), Is.EqualTo("Mathematic: D - E"));
        }
Example #10
0
        /// <summary>
        /// Determines if the tokenizer is pointing at a parameter list for an anonymous function.
        /// </summary>
        internal static bool IsAnonymousParameterList(PositionalTokenizer tokenizer)
        {
            var result = false;

            tokenizer.PushState();

            if (tokenizer.Match("("))
            {
                tokenizer.SkipWhitespace();

                do
                {
                    tokenizer.ReadIdentifier();
                    tokenizer.SkipWhitespace();

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

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

                if (tokenizer.Match(")"))
                {
                    tokenizer.SkipWhitespace();
                    result = (tokenizer.NextChar == '{' || tokenizer.Match("=>"));
                }
            }

            tokenizer.PopState();

            return(result);
        }
Example #11
0
        private static ExpressionBase ParseComparison(PositionalTokenizer tokenizer, ExpressionBase left, ComparisonOperation operation, int joinerLine, int joinerColumn)
        {
            var right = ParseExpression(tokenizer, OperationPriority.Compare);

            switch (right.Type)
            {
            case ExpressionType.ParseError:
                return(right);

            case ExpressionType.BooleanConstant:
            case ExpressionType.Conditional:     // will be rebalanced
            case ExpressionType.FloatConstant:
            case ExpressionType.FunctionCall:
            case ExpressionType.IntegerConstant:
            case ExpressionType.Mathematic:
            case ExpressionType.StringConstant:
            case ExpressionType.Variable:
                break;

            default:
                var expressionTokenizer = tokenizer as ExpressionTokenizer;
                if (expressionTokenizer != null)
                {
                    expressionTokenizer.QueueExpression(right);
                }

                right = new KeywordExpression(ComparisonExpression.GetOperatorString(operation), joinerLine, joinerColumn);
                return(ParseError(tokenizer, "Incompatible comparison", right));
            }

            return(new ComparisonExpression(left, operation, right));
        }
Example #12
0
        internal static void SkipWhitespace(PositionalTokenizer tokenizer)
        {
            tokenizer.SkipWhitespace();
            while (tokenizer.Match("//"))
            {
                var expressionTokenizer = tokenizer as ExpressionTokenizer;
                if (expressionTokenizer != null)
                {
                    int line   = tokenizer.Line;
                    int column = tokenizer.Column - 2;

                    var comment = tokenizer.ReadTo('\n');
                    if (comment.Length > 0 && comment[comment.Length - 1] == '\r')
                    {
                        comment = comment.SubToken(0, comment.Length - 1);
                    }

                    expressionTokenizer.AddComment(new CommentExpression("//" + comment.ToString())
                    {
                        Location = new TextRange(line, column, line, column + comment.Length + 1)
                    });
                }
                else
                {
                    tokenizer.ReadTo('\n');
                }

                tokenizer.SkipWhitespace();
            }
        }
Example #13
0
        private static ExpressionBase ParseMathematic(PositionalTokenizer tokenizer, ExpressionBase left, MathematicOperation operation, int joinerLine, int joinerColumn)
        {
            var right = ExpressionBase.Parse(tokenizer);

            switch (right.Type)
            {
            case ExpressionType.ParseError:
                return(right);

            case ExpressionType.Comparison:
            case ExpressionType.Conditional:
            case ExpressionType.Dictionary:
            case ExpressionType.FunctionCall:
            case ExpressionType.IntegerConstant:
            case ExpressionType.Mathematic:
            case ExpressionType.StringConstant:
            case ExpressionType.Variable:
                break;

            default:
                ParseError(tokenizer, "incompatible mathematical operation", new KeywordExpression(MathematicExpression.GetOperatorCharacter(operation).ToString(), joinerLine, joinerColumn));
                break;
            }

            return(new MathematicExpression(left, operation, right));
        }
Example #14
0
        protected ExpressionBase ParseShorthandBody(PositionalTokenizer tokenizer)
        {
            ExpressionBase.SkipWhitespace(tokenizer);

            var expression = ExpressionBase.Parse(tokenizer);

            if (expression.Type == ExpressionType.ParseError)
            {
                return(expression);
            }

            switch (expression.Type)
            {
            case ExpressionType.Return:
                return(ParseError(tokenizer, "Return statement is implied by =>", ((ReturnExpression)expression).Keyword));

            case ExpressionType.For:
                return(ParseError(tokenizer, "Shorthand function definition does not support loops.", expression));

            case ExpressionType.If:
                return(ParseError(tokenizer, "Shorthand function definition does not support branches.", expression));
            }

            var returnExpression = new ReturnExpression(expression);

            Expressions.Add(returnExpression);
            Location = new TextRange(Location.Start, expression.Location.End);
            return(MakeReadOnly(this));
        }
Example #15
0
        internal static UserFunctionDefinitionExpression ParseForTest(string definition)
        {
            var tokenizer = new PositionalTokenizer(Tokenizer.CreateTokenizer(definition));

            tokenizer.Match("function");
            return(Parse(tokenizer, 0, 0) as UserFunctionDefinitionExpression);
        }
Example #16
0
        public void TestReplaceVariablesIndexFunctionCall()
        {
            var input     = "function func(i) => 6";
            var tokenizer = new PositionalTokenizer(Tokenizer.CreateTokenizer(input));

            tokenizer.Match("function");
            var functionDefinition = (FunctionDefinitionExpression)FunctionDefinitionExpression.Parse(tokenizer);

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

            var variable = new VariableExpression("variable");
            var dict     = new DictionaryExpression();

            dict.Entries.Add(new DictionaryExpression.DictionaryEntry {
                Key = new IntegerConstantExpression(6), Value = value
            });

            var scope = new InterpreterScope();

            scope.AssignVariable(variable, dict);
            scope.AddFunction(functionDefinition);

            var expr = new IndexedVariableExpression(variable, functionCall);

            ExpressionBase result;

            Assert.That(expr.ReplaceVariables(scope, out result), Is.True);
            Assert.That(result, Is.InstanceOf <IntegerConstantExpression>());
            Assert.That(((IntegerConstantExpression)result).Value, Is.EqualTo(98));
        }
Example #17
0
        public void TestReplaceVariablesFunctionCall()
        {
            var input     = "function func(i) => 6";
            var tokenizer = new PositionalTokenizer(Tokenizer.CreateTokenizer(input));

            tokenizer.Match("function");
            var functionDefinition = (FunctionDefinitionExpression)FunctionDefinitionExpression.Parse(tokenizer);

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

            expr.Entries.Add(new DictionaryExpression.DictionaryEntry {
                Key = functionCall, Value = value1
            });

            var scope = new InterpreterScope();

            scope.AddFunction(functionDefinition);

            ExpressionBase result;

            Assert.That(expr.ReplaceVariables(scope, out result), Is.True);
            Assert.That(result, Is.InstanceOf <DictionaryExpression>());
            var dictResult = (DictionaryExpression)result;

            Assert.That(dictResult.Entries.Count, Is.EqualTo(1));
            Assert.That(dictResult.Entries[0].Key, Is.EqualTo(new IntegerConstantExpression(6)));
            Assert.That(dictResult.Entries[0].Value, Is.EqualTo(value1));
        }
Example #18
0
        /// <summary>
        /// Parses an anonymous function definition in the format "(a) => body" or "(a) { body }"
        /// </summary>
        public static ExpressionBase ParseAnonymous(PositionalTokenizer tokenizer)
        {
            var name     = CreateAnonymousFunctionName(tokenizer.Line, tokenizer.Column);
            var function = new AnonymousUserFunctionDefinitionExpression(name);

            function.Location = new TextRange(tokenizer.Line, tokenizer.Column, 0, 0);
            return(function.Parse(tokenizer));
        }
Example #19
0
        internal static ParseErrorExpression ParseError(PositionalTokenizer tokenizer, string message, ExpressionBase expression)
        {
            var error = ParseError(tokenizer, message);

            error.InnerError = expression as ParseErrorExpression;
            expression.CopyLocation(error);
            return(error);
        }
Example #20
0
        public void TestParseErrorInsideDefinition()
        {
            var tokenizer = new PositionalTokenizer(Tokenizer.CreateTokenizer("function func() { if (j) { j = i } }"));

            tokenizer.Match("function");
            var expr = FunctionDefinitionExpression.Parse(tokenizer);

            Assert.That(expr, Is.InstanceOf <ParseErrorExpression>());
            Assert.That(((ParseErrorExpression)expr).Message, Is.EqualTo("Expected conditional statement following if"));
        }
        public void TestParseErrorInsideDefinition()
        {
            var tokenizer = new PositionalTokenizer(Tokenizer.CreateTokenizer("function func() { j = }"));

            tokenizer.Match("function");
            var expr = UserFunctionDefinitionExpression.Parse(tokenizer);

            Assert.That(expr, Is.InstanceOf <ParseErrorExpression>());
            Assert.That(((ParseErrorExpression)expr).Message, Is.EqualTo("Unexpected end of script"));
        }
Example #22
0
        private IfExpression Parse(string input)
        {
            var tokenizer = new PositionalTokenizer(Tokenizer.CreateTokenizer(input));

            tokenizer.Match("if");
            var expr = IfExpression.Parse(tokenizer);

            Assert.That(expr, Is.InstanceOf <IfExpression>());
            return((IfExpression)expr);
        }
Example #23
0
        internal static ParseErrorExpression ParseError(PositionalTokenizer tokenizer, string message, ExpressionBase expression)
        {
            var error = ParseError(tokenizer, message);

            error.Line      = expression.Line;
            error.Column    = expression.Column;
            error.EndLine   = expression.EndLine;
            error.EndColumn = expression.EndColumn;
            return(error);
        }
Example #24
0
        private FunctionDefinitionExpression Parse(string input)
        {
            var tokenizer = new PositionalTokenizer(Tokenizer.CreateTokenizer(input));

            tokenizer.Match("function");
            var expr = FunctionDefinitionExpression.Parse(tokenizer);

            Assert.That(expr, Is.InstanceOf <FunctionDefinitionExpression>());
            return((FunctionDefinitionExpression)expr);
        }
Example #25
0
        [TestCase("(A && B || C) && (D || E && F)", "((A && B) || C) && (D || (E && F))")] // AND has higher priority than OR
        public void TestParseExpressionGrouping(string input, string expected)
        {
            var tokenizer  = new PositionalTokenizer(Tokenizer.CreateTokenizer(input));
            var expression = ExpressionBase.Parse(tokenizer);

            SetLogicalUnit(expression);

            var builder = new StringBuilder();

            expression.AppendString(builder);
            Assert.That(builder.ToString(), Is.EqualTo(expected));
        }
Example #26
0
        internal static ExpressionBase ParseStatementBlock(PositionalTokenizer tokenizer, ICollection <ExpressionBase> expressions)
        {
            ExpressionBase.SkipWhitespace(tokenizer);

            if (tokenizer.NextChar != '{')
            {
                var statement = ExpressionBase.Parse(tokenizer);
                if (statement.Type == ExpressionType.ParseError)
                {
                    return(statement);
                }

                expressions.Add(statement);
            }
            else
            {
                var line   = tokenizer.Line;
                var column = tokenizer.Column;

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

                    if (tokenizer.NextChar == '\0')
                    {
                        return(ParseError(tokenizer, "No matching closing brace found", line, column));
                    }

                    var statement = ExpressionBase.Parse(tokenizer);
                    if (statement.Type == ExpressionType.ParseError)
                    {
                        return(statement);
                    }

                    if (statement.Type == ExpressionType.Variable)
                    {
                        return(new ParseErrorExpression("standalone variable has no meaning", statement));
                    }

                    expressions.Add(statement);
                } while (true);

                tokenizer.Advance();
            }

            return(null);
        }
Example #27
0
        internal static ParseErrorExpression ParseError(PositionalTokenizer tokenizer, string message, int line, int column)
        {
            var error = new ParseErrorExpression(message, line, column, tokenizer.Line, tokenizer.Column);

            var expressionTokenizer = tokenizer as ExpressionTokenizer;

            if (expressionTokenizer != null)
            {
                expressionTokenizer.AddError(error);
            }

            return(error);
        }
Example #28
0
        internal static ExpressionBase Parse(PositionalTokenizer tokenizer, int line = 0, int column = 0)
        {
            SkipWhitespace(tokenizer);

            var dict = new DictionaryExpression();

            while (tokenizer.NextChar != '}')
            {
                var key = ExpressionBase.ParseClause(tokenizer);
                if (key.Type == ExpressionType.ParseError)
                {
                    return(key);
                }

                SkipWhitespace(tokenizer);
                if (tokenizer.NextChar != ':')
                {
                    ParseError(tokenizer, "Expecting colon following key expression");
                    break;
                }
                tokenizer.Advance();
                SkipWhitespace(tokenizer);

                var value = ExpressionBase.ParseClause(tokenizer);
                if (value.Type == ExpressionType.ParseError)
                {
                    break;
                }

                dict.Entries.Add(new DictionaryExpression.DictionaryEntry {
                    Key = key, Value = value
                });

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

                if (tokenizer.NextChar != ',')
                {
                    ParseError(tokenizer, "Expecting comma between entries");
                    break;
                }
                tokenizer.Advance();
                SkipWhitespace(tokenizer);
            }

            tokenizer.Advance();
            return(dict);
        }
Example #29
0
        /// <summary>
        /// Parses a for loop.
        /// </summary>
        /// <remarks>
        /// Assumes the 'for' keyword has already been consumed.
        /// </remarks>
        internal static ExpressionBase Parse(PositionalTokenizer tokenizer, int line = 0, int column = 0)
        {
            ExpressionBase.SkipWhitespace(tokenizer);
            var keywordFor = new KeywordExpression("for", line, column);

            line   = tokenizer.Line;
            column = tokenizer.Column;
            var iteratorName = tokenizer.ReadIdentifier();

            if (iteratorName.IsEmpty)
            {
                return(ParseError(tokenizer, "Invalid function name", line, column));
            }
            var iterator = new VariableDefinitionExpression(iteratorName.ToString(), line, column);

            ExpressionBase.SkipWhitespace(tokenizer);

            line   = tokenizer.Line;
            column = tokenizer.Column;
            if (!tokenizer.Match("in"))
            {
                return(ParseError(tokenizer, "Expected 'in' after loop variable"));
            }
            var keywordIn = new KeywordExpression("in", line, column);

            var range = ExpressionBase.Parse(tokenizer);

            if (range.Type == ExpressionType.ParseError)
            {
                return(range);
            }

            var loop = new ForExpression(iterator, range);

            var error = ExpressionBase.ParseStatementBlock(tokenizer, loop.Expressions);

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

            loop._keywordFor = keywordFor;
            loop._keywordIn  = keywordIn;
            loop.Line        = keywordFor.Line;
            loop.Column      = keywordFor.Column;
            loop.EndLine     = tokenizer.Line;
            loop.EndColumn   = tokenizer.Column;

            return(loop);
        }
        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));
        }