Exemple #1
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));
        }
Exemple #2
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));
        }
Exemple #3
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));
        }
Exemple #4
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);
        }
Exemple #5
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);
        }
        private static void ParseGroups(ExpressionTokenizer tokenizer, List <ExpressionGroup> groups)
        {
            while (tokenizer.NextChar != '\0')
            {
                // create a separate group for comments
                var newGroup = new ExpressionGroup();
                groups.Add(newGroup);
                tokenizer.ChangeExpressionGroup(newGroup);
                ExpressionBase.SkipWhitespace(tokenizer);

                // if comments were found, start a new group
                if (!newGroup.IsEmpty)
                {
                    newGroup = new ExpressionGroup();
                    groups.Add(newGroup);
                    tokenizer.ChangeExpressionGroup(newGroup);
                }

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

                var expression = ExpressionBase.Parse(tokenizer);

                // sometimes parsing an expression will process trailing whitespace looking for a continuation character.
                // move the trailing comments into a separate group. do not move the internal comments
                var commentGroup = newGroup.ExtractTrailingComments(expression);
                if (commentGroup != null)
                {
                    groups.Add(commentGroup);
                }

                if (expression.Type != ExpressionType.ParseError)
                {
                    newGroup.AddExpression(expression);
                }
            }

            var lastGroup = groups.LastOrDefault();

            if (lastGroup != null && lastGroup.IsEmpty)
            {
                groups.RemoveAt(groups.Count - 1);
            }
        }
Exemple #7
0
        private static ExpressionBase ParseParameters(PositionalTokenizer tokenizer, ICollection <ExpressionBase> parameters)
        {
            int line   = tokenizer.Line;
            int column = tokenizer.Column;

            SkipWhitespace(tokenizer);

            if (tokenizer.NextChar != ')')
            {
                do
                {
                    var parameter = ExpressionBase.Parse(tokenizer);
                    if (parameter.Type == ExpressionType.ParseError)
                    {
                        return(ParseError(tokenizer, "Invalid expression", parameter));
                    }

                    parameters.Add(parameter);

                    SkipWhitespace(tokenizer);

                    var commaLine   = tokenizer.Line;
                    var commaColumn = tokenizer.Column;
                    if (tokenizer.NextChar != ',')
                    {
                        break;
                    }

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

            if (tokenizer.NextChar == ')')
            {
                tokenizer.Advance();
                return(null);
            }

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

            return(ParseError(tokenizer, "Expected closing parenthesis, found: " + tokenizer.NextChar));
        }
Exemple #8
0
        /// <summary>
        /// Parses a if definition.
        /// </summary>
        /// <remarks>
        /// Assumes the 'if' keyword has already been consumed.
        /// </remarks>
        internal static ExpressionBase Parse(PositionalTokenizer tokenizer, int line = 0, int column = 0)
        {
            ExpressionBase.SkipWhitespace(tokenizer);

            var condition = ExpressionBase.Parse(tokenizer);

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

            if (condition.Type != ExpressionType.Conditional && condition.Type != ExpressionType.Comparison)
            {
                return(ParseError(tokenizer, "Expected conditional statement following if", condition));
            }

            var ifExpression = new IfExpression(condition);

            ifExpression._keyword = new KeywordExpression("if", line, column);

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

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

            ExpressionBase.SkipWhitespace(tokenizer);

            if (tokenizer.Match("else"))
            {
                error = ExpressionBase.ParseStatementBlock(tokenizer, ifExpression.ElseExpressions);
                if (error != null)
                {
                    return(error);
                }
            }

            return(ifExpression);
        }
Exemple #9
0
        /// <summary>
        /// Parses a if definition.
        /// </summary>
        /// <remarks>
        /// Assumes the 'if' keyword has already been consumed.
        /// </remarks>
        internal static ExpressionBase Parse(PositionalTokenizer tokenizer, int line = 0, int column = 0)
        {
            ExpressionBase.SkipWhitespace(tokenizer);

            var condition = ExpressionBase.Parse(tokenizer);

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

            var ifExpression = new IfExpression(condition);

            ifExpression._keyword = new KeywordExpression("if", line, column);

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

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

            ExpressionBase.SkipWhitespace(tokenizer);

            line   = tokenizer.Line;
            column = tokenizer.Column;
            if (tokenizer.Match("else"))
            {
                ifExpression._elseKeyword = new KeywordExpression("else", line, column);

                error = ExpressionBase.ParseStatementBlock(tokenizer, ifExpression.ElseExpressions);
                if (error != null)
                {
                    return(error);
                }
            }

            return(ifExpression);
        }
Exemple #10
0
        private static ExpressionBase ParseConditional(PositionalTokenizer tokenizer, ExpressionBase left, ConditionalOperation 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.FunctionCall:
            case ExpressionType.Variable:
                break;

            default:
                ParseError(tokenizer, "incompatible logical condition", new KeywordExpression(ConditionalExpression.GetOperatorString(operation), joinerLine, joinerColumn));
                break;
            }

            return(new ConditionalExpression(left, operation, right));
        }
Exemple #11
0
        public ExpressionGroup Parse(Tokenizer tokenizer)
        {
            var expressionGroup     = new ExpressionGroup();
            var expressionTokenizer = new ExpressionTokenizer(tokenizer, expressionGroup);

            ExpressionBase.SkipWhitespace(expressionTokenizer);

            while (expressionTokenizer.NextChar != '\0')
            {
                var expression = ExpressionBase.Parse(expressionTokenizer);
                if (expression != null)
                {
                    if (expression is VariableExpression)
                    {
                        expressionGroup.Errors.Add(new ParseErrorExpression("standalone variable has no meaning", expression));
                    }

                    expressionGroup.Expressions.Add(expression);
                }
            }

            return(expressionGroup);
        }
Exemple #12
0
        private static ExpressionBase ParseComparison(PositionalTokenizer tokenizer, ExpressionBase left, ComparisonOperation operation, int joinerLine, int joinerColumn)
        {
            var right = ExpressionBase.Parse(tokenizer);

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

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

            default:
                ParseError(tokenizer, "incompatible comparison", new KeywordExpression(ComparisonExpression.GetOperatorString(operation), joinerLine, joinerColumn));
                break;
            }

            return(new ComparisonExpression(left, operation, right));
        }
Exemple #13
0
        private static ExpressionBase ParseClauseCore(PositionalTokenizer tokenizer)
        {
            ExpressionBase clause;

            switch (tokenizer.NextChar)
            {
            case '!':
                tokenizer.Advance();
                clause = ParseClause(tokenizer);
                if (clause.Type == ExpressionType.ParseError)
                {
                    return(clause);
                }

                return(new ConditionalExpression(null, ConditionalOperation.Not, clause));

            case '(':
                if (AnonymousUserFunctionDefinitionExpression.IsAnonymousParameterList(tokenizer))
                {
                    return(AnonymousUserFunctionDefinitionExpression.ParseAnonymous(tokenizer));
                }

                tokenizer.Advance();
                clause = ExpressionBase.Parse(tokenizer);
                if (clause.Type == ExpressionType.ParseError)
                {
                    return(clause);
                }

                if (tokenizer.NextChar != ')')
                {
                    if (tokenizer.NextChar == '\0')
                    {
                        return(ParseError(tokenizer, "No closing parenthesis found"));
                    }

                    return(ParseError(tokenizer, "Expected closing parenthesis, found: " + tokenizer.NextChar));
                }

                clause.IsLogicalUnit = true;
                tokenizer.Advance();

                return(clause);

            case '"':
                try
                {
                    var stringValue = tokenizer.ReadQuotedString().ToString();
                    return(new StringConstantExpression(stringValue));
                }
                catch (InvalidOperationException ex)
                {
                    return(ParseError(tokenizer, ex.Message));
                }

            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                return(ParseNumber(tokenizer, true));

            case '-':
                var tokenStart = tokenizer.Location;
                tokenizer.Advance();
                if (tokenizer.NextChar >= '0' && tokenizer.NextChar <= '9')
                {
                    var result   = ParseNumber(tokenizer, false);
                    var tokenEnd = result.Location.End;
                    switch (result.Type)
                    {
                    case ExpressionType.IntegerConstant:
                        result = new IntegerConstantExpression(-((IntegerConstantExpression)result).Value);
                        break;

                    case ExpressionType.FloatConstant:
                        result = new FloatConstantExpression(-((FloatConstantExpression)result).Value);
                        break;

                    default:
                        return(result);
                    }

                    result.Location = new TextRange(tokenStart, tokenEnd);
                    return(result);
                }
                return(ParseError(tokenizer, "Minus without value", tokenStart.Line, tokenStart.Column));

            case '{':
                tokenizer.Advance();
                return(DictionaryExpression.Parse(tokenizer));

            case '[':
                tokenizer.Advance();
                return(ParseArray(tokenizer));

            default:
                var line       = tokenizer.Line;
                var column     = tokenizer.Column;
                var identifier = tokenizer.ReadIdentifier();
                if (identifier.IsEmpty)
                {
                    var error = ParseError(tokenizer, "Unexpected character: " + tokenizer.NextChar);
                    tokenizer.Advance();
                    return(error);
                }

                SkipWhitespace(tokenizer);

                if (identifier == "return")
                {
                    clause = ExpressionBase.Parse(tokenizer);
                    if (clause.Type == ExpressionType.ParseError)
                    {
                        return(clause);
                    }

                    return(new ReturnExpression(new KeywordExpression(identifier.ToString(), line, column), clause));
                }

                if (identifier == "function")
                {
                    return(UserFunctionDefinitionExpression.Parse(tokenizer, line, column));
                }
                if (identifier == "for")
                {
                    return(ForExpression.Parse(tokenizer, line, column));
                }
                if (identifier == "if")
                {
                    return(IfExpression.Parse(tokenizer, line, column));
                }

                if (identifier == "true")
                {
                    return(new BooleanConstantExpression(true, line, column));
                }
                if (identifier == "false")
                {
                    return(new BooleanConstantExpression(false, line, column));
                }

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

                    var parameters = new List <ExpressionBase>();
                    ParseParameters(tokenizer, parameters);

                    var functionCall = new FunctionCallExpression(new FunctionNameExpression(identifier.ToString(), line, column), parameters);
                    functionCall.Location = new TextRange(line, column, tokenizer.Line, tokenizer.Column - 1);
                    return(functionCall);
                }

                if (tokenizer.NextChar == '[')
                {
                    IndexedVariableExpression parent = null;

                    do
                    {
                        tokenizer.Advance();

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

                        SkipWhitespace(tokenizer);
                        if (tokenizer.NextChar != ']')
                        {
                            return(ParseError(tokenizer, "Expecting closing bracket after index"));
                        }
                        tokenizer.Advance();
                        SkipWhitespace(tokenizer);

                        if (parent != null)
                        {
                            parent = new IndexedVariableExpression(parent, index);
                        }
                        else
                        {
                            parent = new IndexedVariableExpression(new VariableExpression(identifier.ToString(), line, column), index);
                        }
                    } while (tokenizer.NextChar == '[');

                    return(parent);
                }

                return(new VariableExpression(identifier.ToString(), line, column));
            }
        }
Exemple #14
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));
        }
Exemple #15
0
        /// <summary>
        /// Parses a function definition.
        /// </summary>
        /// <remarks>
        /// Assumes the 'function' keyword has already been consumed.
        /// </remarks>
        internal static ExpressionBase Parse(PositionalTokenizer tokenizer, int line = 0, int column = 0)
        {
            var function = new FunctionDefinitionExpression();

            function._keyword = new KeywordExpression("function", line, column);

            ExpressionBase.SkipWhitespace(tokenizer);

            line   = tokenizer.Line;
            column = tokenizer.Column;

            var functionName = tokenizer.ReadIdentifier();

            function.Name = new VariableDefinitionExpression(functionName.ToString(), line, column);
            if (functionName.IsEmpty)
            {
                ExpressionBase.ParseError(tokenizer, "Invalid function name");
                return(function);
            }

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

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

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

                    function.Parameters.Add(new VariableDefinitionExpression(parameter.ToString(), line, column));

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

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

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

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

            ExpressionBase expression;

            if (tokenizer.Match("=>"))
            {
                ExpressionBase.SkipWhitespace(tokenizer);

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

                if (expression.Type == ExpressionType.Return)
                {
                    return(new ParseErrorExpression("Return statement is implied by =>", ((ReturnExpression)expression).Keyword));
                }

                var returnExpression = new ReturnExpression(expression);
                function.Expressions.Add(returnExpression);
                return(function);
            }

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

            line   = tokenizer.Line;
            column = tokenizer.Column;
            tokenizer.Advance();
            ExpressionBase.SkipWhitespace(tokenizer);

            bool seenReturn = false;

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

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

                function.Expressions.Add(expression);

                ExpressionBase.SkipWhitespace(tokenizer);
            }

            tokenizer.Advance();
            return(function);
        }
Exemple #16
0
        private static ExpressionBase ParseClauseCore(PositionalTokenizer tokenizer)
        {
            ExpressionBase clause;

            switch (tokenizer.NextChar)
            {
            case '!':
                tokenizer.Advance();
                clause = ParseClause(tokenizer);
                if (clause.Type == ExpressionType.ParseError)
                {
                    return(clause);
                }

                return(new ConditionalExpression(null, ConditionalOperation.Not, clause));

            case '(':
                tokenizer.Advance();
                clause = ExpressionBase.Parse(tokenizer);
                if (clause.Type == ExpressionType.ParseError)
                {
                    return(clause);
                }

                if (tokenizer.NextChar != ')')
                {
                    if (tokenizer.NextChar == '\0')
                    {
                        return(ParseError(tokenizer, "No closing parenthesis found"));
                    }

                    return(ParseError(tokenizer, "Expected closing parenthesis, found: " + tokenizer.NextChar));
                }

                clause.IsLogicalUnit = true;
                tokenizer.Advance();
                return(clause);

            case '"':
                try
                {
                    var stringValue = tokenizer.ReadQuotedString().ToString();
                    return(new StringConstantExpression(stringValue));
                }
                catch (InvalidOperationException ex)
                {
                    return(ParseError(tokenizer, ex.Message));
                }

            case '0':
                if (tokenizer.Match("0x"))
                {
                    string hexNumber = "";
                    while (Char.IsDigit(tokenizer.NextChar) || (tokenizer.NextChar >= 'A' && tokenizer.NextChar <= 'F') || (tokenizer.NextChar >= 'a' && tokenizer.NextChar <= 'f'))
                    {
                        hexNumber += tokenizer.NextChar;
                        tokenizer.Advance();
                    }

                    int hexValue = 0;
                    Int32.TryParse(hexNumber, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.CurrentCulture, out hexValue);
                    return(new IntegerConstantExpression(hexValue));
                }
                goto case '1';

            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            {
                var  number = tokenizer.ReadNumber();
                uint value;
                UInt32.TryParse(number.ToString(), out value);
                return(new IntegerConstantExpression((int)value));
            }

            case '-':
                tokenizer.Advance();
                if (tokenizer.NextChar >= '0' && tokenizer.NextChar <= '9')
                {
                    if (tokenizer.Match("0x"))
                    {
                        string hexNumber = "";
                        while (Char.IsDigit(tokenizer.NextChar) || (tokenizer.NextChar >= 'A' && tokenizer.NextChar <= 'F') || (tokenizer.NextChar >= 'a' && tokenizer.NextChar <= 'f'))
                        {
                            hexNumber += tokenizer.NextChar;
                            tokenizer.Advance();
                        }

                        int hexValue = 0;
                        Int32.TryParse(hexNumber, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.CurrentCulture, out hexValue);
                        return(new IntegerConstantExpression(-hexValue));
                    }

                    var number = tokenizer.ReadNumber();
                    int value;
                    Int32.TryParse(number.ToString(), out value);
                    return(new IntegerConstantExpression(-value));
                }
                return(ParseError(tokenizer, "Minus without value"));

            case '{':
                tokenizer.Advance();
                return(DictionaryExpression.Parse(tokenizer));

            case '[':
                tokenizer.Advance();
                return(ParseArray(tokenizer));

            default:
                var line       = tokenizer.Line;
                var column     = tokenizer.Column;
                var identifier = tokenizer.ReadIdentifier();
                if (identifier.IsEmpty)
                {
                    var error = ParseError(tokenizer, "Unexpected character: " + tokenizer.NextChar);
                    tokenizer.Advance();
                    return(error);
                }

                SkipWhitespace(tokenizer);

                if (identifier == "return")
                {
                    clause = ExpressionBase.Parse(tokenizer);
                    if (clause.Type == ExpressionType.ParseError)
                    {
                        return(clause);
                    }

                    return(new ReturnExpression(new KeywordExpression(identifier.ToString(), line, column), clause));
                }

                if (identifier == "function")
                {
                    return(FunctionDefinitionExpression.Parse(tokenizer, line, column));
                }
                if (identifier == "for")
                {
                    return(ForExpression.Parse(tokenizer, line, column));
                }
                if (identifier == "if")
                {
                    return(IfExpression.Parse(tokenizer, line, column));
                }

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

                    var parameters = new List <ExpressionBase>();
                    ParseParameters(tokenizer, parameters);

                    var functionCall = new FunctionCallExpression(new VariableExpression(identifier.ToString(), line, column), parameters);
                    functionCall.EndLine   = tokenizer.Line;
                    functionCall.EndColumn = tokenizer.Column - 1;
                    return(functionCall);
                }

                if (tokenizer.NextChar == '[')
                {
                    IndexedVariableExpression parent = null;

                    do
                    {
                        tokenizer.Advance();

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

                        SkipWhitespace(tokenizer);
                        if (tokenizer.NextChar != ']')
                        {
                            return(ParseError(tokenizer, "Expecting closing bracket after index"));
                        }
                        tokenizer.Advance();
                        SkipWhitespace(tokenizer);

                        if (parent != null)
                        {
                            parent = new IndexedVariableExpression(parent, index);
                        }
                        else
                        {
                            parent = new IndexedVariableExpression(new VariableExpression(identifier.ToString(), line, column), index);
                        }
                    } while (tokenizer.NextChar == '[');

                    return(parent);
                }

                return(new VariableExpression(identifier.ToString(), line, column));
            }
        }