Esempio n. 1
0
        public void Dispose()
        {
            if (!IsDisposed)
            {
                // Fixup break targets references
                int loopEndIp = Writer.IP;
                foreach (var ip in BreakFixups)
                {
                    Writer.WriteAt(ip, loopEndIp);
                }

                // Fixup continue targets
                foreach (var ip in ContinueFixups)
                {
                    Writer.WriteAt(ip, ContinueIP);
                }

                // Remove this context from loop stack
                Debug.Assert(Function.LoopContexts.Count > 0);
                Debug.Assert(Function.LoopContexts.Peek() == this);
                Function.LoopContexts.Pop();

                IsDisposed = true;
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Parses arguments for a function call. If <paramref name="usingParentheses"/>
        /// is true, assumes opening parenthesis has been read and reads up to and
        /// including the closing parenthesis. Returns false on error.
        /// </summary>
        /// <param name="function">Function being called. May be null for user
        /// functions. Used to verify argument count for intrinsic functions.</param>
        private bool ParseFunctionArguments(Function function, bool usingParentheses)
        {
            Token token;
            int   count = 0;

            // Save position and write placeholder for argument count
            int argumentCountIP = Writer.Write(0);

            if (ParseExpression(false))
            {
                count++;
                token = Lexer.GetNext();
                while (token.Type == TokenType.Comma)
                {
                    if (!ParseExpression())
                    {
                        return(false);
                    }
                    count++;
                    token = Lexer.GetNext();
                }
            }
            else
            {
                token = Lexer.GetNext();
            }

            if (usingParentheses)
            {
                if (token.Type != TokenType.RightParen)
                {
                    Error(ErrorCode.ExpectedRightParen, token);
                    return(false);
                }
            }
            else
            {
                Lexer.UngetToken(token);
            }

            // Enforce argument count for intrinsic functions
            // (May be null for user functions not yet defined)
            if (function is IntrinsicFunction intrinsicFunction)
            {
                if (!intrinsicFunction.IsParameterCountValid(count, out string error))
                {
                    Error(ErrorCode.WrongNumberOfArguments, error);
                    return(false);
                }
            }
            // Fixup argument count
            Writer.WriteAt(argumentCountIP, count);
            return(true);
        }
Esempio n. 3
0
        /// <summary>
        /// Parses a symbol. Expected to be either a label, an assignment, a function
        /// definition, or function call.
        /// </summary>
        private void ParseSymbol(Token token)
        {
            Token nextToken = Lexer.GetNext();

            switch (nextToken.Type)
            {
            case TokenType.Colon:
                // Label definition
                if (!InFunction)
                {
                    Error(ErrorCode.CodeOutsideFunction, token);
                    NextLine();
                    return;
                }
                AddLabel(token.Value, Writer.IP);
                // Allow another statement on same line
                break;

            case TokenType.LeftBracket:
                // Assignment to list item
                if (!InFunction)
                {
                    Error(ErrorCode.CodeOutsideFunction, token);
                    NextLine();
                    return;
                }

                Writer.Write(ByteCode.AssignListVariableMulti, GetVariableId(token.Value));
                int subscriptsIP = Writer.Write(0);        //
                int subscripts   = 0;

                do
                {
                    // Parse list index
                    if (!ParseExpression())
                    {
                        return;
                    }
                    token = Lexer.GetNext();
                    if (token.Type != TokenType.RightBracket)
                    {
                        Error(ErrorCode.ExpectedRightBracket, token);
                        NextLine();
                        return;
                    }
                    subscripts++;

                    // Get next token
                    token = Lexer.GetNext();
                } while (token.Type == TokenType.LeftBracket);

                // Set index count
                Writer.WriteAt(subscriptsIP, subscripts);

                if (token.Type != TokenType.Equal)
                {
                    Error(ErrorCode.ExpectedEquals, token);
                    NextLine();
                    return;
                }

                // Parse expression
                if (!ParseExpression())
                {
                    return;
                }
                VerifyEndOfLine();
                break;

            case TokenType.Equal:
                // Assignment
                if (!InFunction)
                {
                    Error(ErrorCode.CodeOutsideFunction, token);
                    NextLine();
                    return;
                }
                // Test for read-only
                int varId = GetVariableId(token.Value);
                if (IsReadOnly(varId))
                {
                    Error(ErrorCode.AssignToReadOnlyVariable, token);
                    NextLine();
                    return;
                }
                Writer.Write(ByteCode.Assign, varId);
                if (!ParseExpression())
                {
                    return;
                }
                VerifyEndOfLine();
                break;

            default:
                if (InFunction)
                {
                    // Function call
                    int      functionId = GetFunctionId(token.Value);
                    Function?function   = Functions[functionId];
                    Writer.Write(ByteCode.ExecFunction, functionId);
                    // Next token might be part of argument expression
                    Lexer.UngetToken(nextToken);
                    if (!ParseFunctionArguments(function, false))
                    {
                        return;
                    }
                    VerifyEndOfLine();
                }
                else
                {
                    // Function definition requires parentheses
                    if (nextToken.Type != TokenType.LeftParen)
                    {
                        Error(ErrorCode.ExpectedLeftParen, nextToken);
                        break;
                    }
                    // Create function
                    var function = new CompileTimeUserFunction(token.Value, Writer.IP);
                    // Parse and add parameters
                    if (!ParseFunctionParameters(function))
                    {
                        return;
                    }
                    // Add user function
                    AddUserFunction(token.Value, function);

                    InHeader        = false;
                    CurrentFunction = function;

                    token = Lexer.GetNextSkipNewLines();
                    if (token.Type != TokenType.LeftBrace)
                    {
                        Error(ErrorCode.ExpectedLeftBrace, token);
                        return;
                    }

                    // Parse statements in function
                    while (ParseStatement())
                    {
                        ;
                    }

                    token = Lexer.GetNext();
                    if (token.Type != TokenType.RightBrace)
                    {
                        Error(ErrorCode.ExpectedRightBrace);
                        return;
                    }

                    // Write return (no return expression)
                    Writer.Write(ByteCode.Return, 0);

                    // Check for undefined labels
                    foreach (var labelInfo in function.Labels.GetKeyValuePairs())
                    {
                        if (labelInfo.Value.IP == null)
                        {
                            Error(ErrorCode.LabelNotDefined, labelInfo.Key.MakeQuoted());
                            return;
                        }
                    }
                    CurrentFunction = null;
                }
                break;
            }
        }