Commit 5d1e8f23 authored by Vít Starý Novotný's avatar Vít Starý Novotný
Browse files

Added call coercion and call parameter number checking.

parent ecc64101
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -73,3 +73,17 @@ void Parser::cannot_coerce(const Token& where, std::string from, std::string to)
    ss << "Cannot coerce " << from << " to " << to << "." << std::endl;
    type_error(where, ss.str());
}

void Parser::extra_parameter(const Token& where)
{
    std::ostringstream ss;
    ss << "Unexpected extra function call parameter." << std::endl;
    type_error(where, ss.str());
}

void Parser::missing_parameter(const Token& where)
{
    std::ostringstream ss;
    ss << "Expected extra function call parameter." << std::endl;
    type_error(where, ss.str());
}
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ protected:
    void multiply_defined_function(const Token& name);
    void type_error(const Token& where, std::string msg);
    void cannot_coerce(const Token& where, std::string from, std::string to);
    void extra_parameter(const Token& where);
    void missing_parameter(const Token& where);

public:
    virtual ~Parser() = default;
+23 −11
Original line number Diff line number Diff line
@@ -351,15 +351,20 @@ DataType XMLParser::grammar_arithmetic_expression()
        token = lexer.getNext();
        if (token.term.type != TT_LEFTPAREN)
            expected_tokens(token, { Term::from_character.find('(')->second });
        grammar_arithmetic_expression_list();
        SymbolData& data = symbols.find(name_token.term.payload);
        if (data.symbol_type != ST_FUNCTION)
            undefined_function(name_token);
        assert(data.data_type.size() > 1);
        // Pass a copy of the expected types reversed, so that we can pop_back() on them.
        std::vector<DataType> expected_types;
        expected_types.resize(data.data_type.size() - 1);
        std::reverse_copy(data.data_type.begin(),
            data.data_type.end() - 1, expected_types.begin());
        grammar_arithmetic_expression_list(expected_types);
        token = lexer.getNext();
        if (token.term.type != TT_RIGHTPAREN)
            expected_tokens(token, { Term::from_character.find(')')->second });
        get_current_out() << "</call>" << std::endl;
        SymbolData& data = symbols.find(name_token.term.payload);
        if (data.symbol_type != ST_FUNCTION)
            undefined_function(name_token);
        assert(!data.data_type.empty());
        return data.data_type.back();
    } else {
        start_buffering();
@@ -428,7 +433,7 @@ DataType XMLParser::grammar_arithmetic_expression_tail(DataType left_operand_typ
    }
}

void XMLParser::grammar_arithmetic_expression_list()
void XMLParser::grammar_arithmetic_expression_list(std::vector<DataType>& expected_types)
{
    get_current_out() << "<arithmetic_expressions>" << std::endl;
    auto token = lexer.peekNext();
@@ -441,13 +446,14 @@ void XMLParser::grammar_arithmetic_expression_list()
                                   Term::from_character.find('-')->second,
                                   Term::from_character.find(')')->second });
    if (token.term.type != TT_RIGHTPAREN) {
        grammar_arithmetic_expression();
        grammar_arithmetic_expression_list_tail();
        grammar_coerced_arithmetic_expression(token, expected_types.back());
        expected_types.pop_back();
        grammar_arithmetic_expression_list_tail(expected_types);
    }
    get_current_out() << "</arithmetic_expressions>" << std::endl;
}

void XMLParser::grammar_arithmetic_expression_list_tail()
void XMLParser::grammar_arithmetic_expression_list_tail(std::vector<DataType>& expected_types)
{
    auto token = lexer.peekNext();
    if (token.term.type != TT_COMMA && token.term.type != TT_RIGHTPAREN)
@@ -455,8 +461,14 @@ void XMLParser::grammar_arithmetic_expression_list_tail()
                                   Term::from_character.find(')')->second });
    if (token.term.type == TT_COMMA) {
        lexer.getNext();
        grammar_arithmetic_expression();
        grammar_arithmetic_expression_list_tail();
        if (expected_types.empty())
            extra_parameter(lexer.peekNext());
        grammar_coerced_arithmetic_expression(token, expected_types.back());
        expected_types.pop_back();
        grammar_arithmetic_expression_list_tail(expected_types);
    } else {
        if (!expected_types.empty())
            missing_parameter(token);
    }
}

+2 −2
Original line number Diff line number Diff line
@@ -112,8 +112,8 @@ private:
    void grammar_coerced_arithmetic_expression(const Token& where, DataType expected_type);
    DataType grammar_arithmetic_expression();
    DataType grammar_arithmetic_expression_tail(DataType left_operand_type);
    void grammar_arithmetic_expression_list();
    void grammar_arithmetic_expression_list_tail();
    void grammar_arithmetic_expression_list(std::vector<DataType>& expected_types);
    void grammar_arithmetic_expression_list_tail(std::vector<DataType>& expected_types);
    DataType grammar_arithmetic_factor();
    DataType grammar_arithmetic_factor_tail(DataType left_operand_type);
    DataType grammar_arithmetic_operand();
+48 −0
Original line number Diff line number Diff line
@@ -162,3 +162,51 @@ TEST(XMLParser, cannotCoerceReturn)
    std::getline(error_stream_in, line);
    ASSERT_EQ("Parser error:\tType error from (Identifier, \"return\") at line 2, character number 3: Cannot coerce double to integer.", line);
}

TEST(XMLParser, cannotCoerceCall)
{
    std::ifstream input_stream("tests/XMLParser/cannot_coerce_call.in");
    Lexer lexer(input_stream, std::cout, std::cerr);
    std::ostringstream error_stream_out;
    NullBuffer null_buffer;
    std::ostream null_stream(&null_buffer);
    XMLParser parser(lexer, null_stream, error_stream_out);
    ASSERT_THROW(parser.run(), std::invalid_argument);

    std::istringstream error_stream_in(error_stream_out.str());
    std::string line;
    std::getline(error_stream_in, line);
    ASSERT_EQ("Parser error:\tType error from (Real number, \"1.23456\") at line 7, character number 12: Cannot coerce double to integer.", line);
}

TEST(XMLParser, extraParameter)
{
    std::ifstream input_stream("tests/XMLParser/extra_parameter.in");
    Lexer lexer(input_stream, std::cout, std::cerr);
    std::ostringstream error_stream_out;
    NullBuffer null_buffer;
    std::ostream null_stream(&null_buffer);
    XMLParser parser(lexer, null_stream, error_stream_out);
    ASSERT_THROW(parser.run(), std::invalid_argument);

    std::istringstream error_stream_in(error_stream_out.str());
    std::string line;
    std::getline(error_stream_in, line);
    ASSERT_EQ("Parser error:\tType error from (Integer, \"13\") at line 7, character number 16: Unexpected extra function call parameter.", line);
}

TEST(XMLParser, missingParameter)
{
    std::ifstream input_stream("tests/XMLParser/missing_parameter.in");
    Lexer lexer(input_stream, std::cout, std::cerr);
    std::ostringstream error_stream_out;
    NullBuffer null_buffer;
    std::ostream null_stream(&null_buffer);
    XMLParser parser(lexer, null_stream, error_stream_out);
    ASSERT_THROW(parser.run(), std::invalid_argument);

    std::istringstream error_stream_in(error_stream_out.str());
    std::string line;
    std::getline(error_stream_in, line);
    ASSERT_EQ("Parser error:\tType error from (Right parenthesis, \")\") at line 7, character number 14: Expected extra function call parameter.", line);
}
Loading