Esempio n. 1
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);
        }
Esempio n. 2
0
        /// <summary>
        /// Gets the string parameter from the <paramref name="scope"/> or <see cref="DefaultParameters"/> collections.
        /// </summary>
        /// <param name="scope">The scope.</param>
        /// <param name="name">The name of the parameter.</param>
        /// <param name="parseError">[out] The error that occurred.</param>
        /// <returns>The parameter value, or <c>null</c> if an error occurred.</b></returns>
        protected StringConstantExpression GetStringParameter(InterpreterScope scope, string name, out ExpressionBase parseError)
        {
            var parameter = GetParameter(scope, name, out parseError);

            if (parameter == null)
            {
                return(null);
            }

            var typedParameter = parameter as StringConstantExpression;

            if (typedParameter == null)
            {
                parseError = new ParseErrorExpression(name + " is not a string", parameter);
                return(null);
            }

            parseError = null;
            return(typedParameter);
        }
Esempio n. 3
0
        /// <summary>
        /// Determines whether the specified <see cref="FunctionDefinitionExpression" /> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="FunctionDefinitionExpression" /> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="FunctionDefinitionExpression" /> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        protected override bool Equals(ExpressionBase obj)
        {
            var that = (FunctionDefinitionExpression)obj;

            return(Name == that.Name && Parameters == that.Parameters && Expressions == that.Expressions);
        }
Esempio n. 4
0
 /// <summary>
 /// Replaces the variables in the expression with values from <paramref name="scope"/>.
 /// </summary>
 /// <param name="scope">The scope object containing variable values.</param>
 /// <param name="result">[out] The new expression containing the replaced variables.</param>
 /// <returns><c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result"/> will likely be a <see cref="ParseErrorExpression"/>.</returns>
 public virtual bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result)
 {
     result = this;
     return(true);
 }
        /// <summary>
        /// Determines whether the specified <see cref="IntegerConstantExpression" /> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="IntegerConstantExpression" /> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="IntegerConstantExpression" /> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        protected override bool Equals(ExpressionBase obj)
        {
            var that = obj as IntegerConstantExpression;

            return(that != null && Value == that.Value);
        }
Esempio n. 6
0
 /// <summary>
 /// Determines whether the specified <see cref="ExpressionBase" /> is equal to this instance.
 /// </summary>
 /// <param name="obj">The <see cref="ExpressionBase" /> to compare with this instance.</param>
 /// <returns>
 ///   <c>true</c> if the specified <see cref="ExpressionBase" /> is equal to this instance; otherwise, <c>false</c>.
 /// </returns>
 protected abstract bool Equals(ExpressionBase obj);
Esempio n. 7
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));
        }
Esempio n. 8
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));
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Gets the next expression from the input.
        /// </summary>
        /// <returns>The next expression, <c>null</c> if at end of file.</returns>
        public static ExpressionBase Parse(PositionalTokenizer tokenizer)
        {
            SkipWhitespace(tokenizer);

            if (tokenizer.NextChar == '\0')
            {
                return(new ParseErrorExpression("Unexpected end of script", tokenizer.Line, tokenizer.Column, tokenizer.Line, tokenizer.Column));
            }

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

            var clause = ExpressionBase.ParseClause(tokenizer);

            if (clause.Type == ExpressionType.ParseError || clause.Type == ExpressionType.Comment)
            {
                return(clause);
            }

            var clauseEndLine   = tokenizer.Line;
            var clauseEndColumn = tokenizer.Column;

            SkipWhitespace(tokenizer);

            var joinerLine   = tokenizer.Line;
            var joinerColumn = tokenizer.Column;

            switch (tokenizer.NextChar)
            {
            case '+':
                tokenizer.Advance();
                clause = ParseMathematic(tokenizer, clause, MathematicOperation.Add, joinerLine, joinerColumn);
                break;

            case '-':
                tokenizer.Advance();
                clause = ParseMathematic(tokenizer, clause, MathematicOperation.Subtract, joinerLine, joinerColumn);
                break;

            case '*':
                tokenizer.Advance();
                clause = ParseMathematic(tokenizer, clause, MathematicOperation.Multiply, joinerLine, joinerColumn);
                break;

            case '/':
                tokenizer.Advance();
                clause = ParseMathematic(tokenizer, clause, MathematicOperation.Divide, joinerLine, joinerColumn);
                break;

            case '%':
                tokenizer.Advance();
                clause = ParseMathematic(tokenizer, clause, MathematicOperation.Modulus, joinerLine, joinerColumn);
                break;

            case '=':
                tokenizer.Advance();
                if (tokenizer.NextChar == '=')
                {
                    tokenizer.Advance();
                    clause = ParseComparison(tokenizer, clause, ComparisonOperation.Equal, joinerLine, joinerColumn);
                }
                else
                {
                    clause = ParseAssignment(tokenizer, clause, joinerLine, joinerColumn);
                }
                break;

            case '!':
                tokenizer.Advance();
                if (tokenizer.NextChar != '=')
                {
                    clause = ParseError(tokenizer, "= expected following !", joinerLine, joinerColumn);
                }
                else
                {
                    tokenizer.Advance();
                    clause = ParseComparison(tokenizer, clause, ComparisonOperation.NotEqual, joinerLine, joinerColumn);
                }
                break;

            case '<':
                tokenizer.Advance();
                if (tokenizer.NextChar == '=')
                {
                    tokenizer.Advance();
                    clause = ParseComparison(tokenizer, clause, ComparisonOperation.LessThanOrEqual, joinerLine, joinerColumn);
                }
                else
                {
                    clause = ParseComparison(tokenizer, clause, ComparisonOperation.LessThan, joinerLine, joinerColumn);
                }
                break;

            case '>':
                tokenizer.Advance();
                if (tokenizer.NextChar == '=')
                {
                    tokenizer.Advance();
                    clause = ParseComparison(tokenizer, clause, ComparisonOperation.GreaterThanOrEqual, joinerLine, joinerColumn);
                }
                else
                {
                    clause = ParseComparison(tokenizer, clause, ComparisonOperation.GreaterThan, joinerLine, joinerColumn);
                }
                break;

            case '&':
                tokenizer.Advance();
                if (tokenizer.NextChar != '&')
                {
                    clause = ParseError(tokenizer, "& expected following &", joinerLine, joinerColumn);
                }
                else
                {
                    tokenizer.Advance();
                    clause = ParseConditional(tokenizer, clause, ConditionalOperation.And, joinerLine, joinerColumn);
                    if (clause.Type == ExpressionType.ParseError)
                    {
                        return(clause);
                    }
                }
                break;

            case '|':
                tokenizer.Advance();
                if (tokenizer.NextChar != '|')
                {
                    clause = ParseError(tokenizer, "| expected following |", joinerLine, joinerColumn);
                }
                else
                {
                    tokenizer.Advance();
                    clause = ParseConditional(tokenizer, clause, ConditionalOperation.Or, joinerLine, joinerColumn);
                    if (clause.Type == ExpressionType.ParseError)
                    {
                        return(clause);
                    }
                }
                break;

            default:
                if (clause.EndColumn == 0)
                {
                    clause.EndLine   = clauseEndLine;
                    clause.EndColumn = clauseEndColumn;
                }
                return(clause);
            }

            clause = clause.Rebalance();

            Debug.Assert(clause.Line != 0);
            Debug.Assert(clause.Column != 0);
            Debug.Assert(clause.EndLine != 0);
            Debug.Assert(clause.EndColumn != 0);

            return(clause);
        }
Esempio n. 10
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);
        }