diff --git a/src/ast/ast.h b/src/ast/ast.h index 53bb7760..c0118ded 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -59,6 +59,7 @@ typedef enum AstType { AST_NULL_STMT, AST_IF_STMT, AST_WHILE_STMT, + AST_FOR_STMT, // expression // assignment-expression diff --git a/src/parser/statement.c b/src/parser/statement.c index 7943543a..39e14861 100644 --- a/src/parser/statement.c +++ b/src/parser/statement.c @@ -16,6 +16,8 @@ ParserReturn* parse_stmt(Parser* parser) { return parse_if_else_stmt(parser); case CTOKEN_KEYWORD_WHILE: return parse_while_stmt(parser); + case CTOKEN_KEYWORD_FOR: + return parse_for_stmt(parser); default: return parse_expression_stmt(parser); } @@ -41,13 +43,7 @@ ParserReturn* parse_compound_stmt(Parser* parser) { break; } - int may_decl = -1; - errint_assign(&may_decl, &err, blockitem_may_decl(parser)); - if (err != NULL) { - break; - } - - if (may_decl) { + if (item_may_decl(parser)) { parserret_assign(&child_ast, &err, parse_decl(parser)); } else { parserret_assign(&child_ast, &err, parse_stmt(parser)); @@ -216,3 +212,67 @@ ParserReturn* parse_while_stmt(Parser* parser) { return new_parserret(ast); } + +ParserReturn* parse_for_stmt(Parser* parser) { + Ast* ast = new_ast(AST_FOR_STMT, 0); + Ast* child_ast = NULL; + Error* err = NULL; + + err = consume_ctoken(parser, CTOKEN_KEYWORD_FOR); + if (err != NULL) { + delete_ast(ast); + return new_parserret_error(err); + } + + err = consume_ctoken(parser, CTOKEN_LPAREN); + if (err != NULL) { + delete_ast(ast); + return new_parserret_error(err); + } + + if (item_may_decl(parser)) { + parserret_assign(&child_ast, &err, parse_decl(parser)); + } else { + parserret_assign(&child_ast, &err, parse_expression_stmt(parser)); + } + if (err != NULL) { + delete_ast(ast); + return new_parserret_error(err); + } + vector_push(ast->children, child_ast); + + parserret_assign(&child_ast, &err, parse_expression_stmt(parser)); + if (err != NULL) { + delete_ast(ast); + return new_parserret_error(err); + } + vector_push(ast->children, child_ast); + + CToken* ctoken = vector_at(parser->ctokens, parser->index); + if (ctoken->type == CTOKEN_RPAREN) { + parser->index++; + vector_push(ast->children, new_ast(AST_NULL_STMT, 0)); + } else { + parserret_assign(&child_ast, &err, parse_expr(parser)); + if (err != NULL) { + delete_ast(ast); + return new_parserret_error(err); + } + vector_push(ast->children, new_ast(AST_EXPR_STMT, 1, child_ast)); + + err = consume_ctoken(parser, CTOKEN_RPAREN); + if (err != NULL) { + delete_ast(ast); + return new_parserret_error(err); + } + } + + parserret_assign(&child_ast, &err, parse_stmt(parser)); + if (err != NULL) { + delete_ast(ast); + return new_parserret_error(err); + } + vector_push(ast->children, child_ast); + + return new_parserret(ast); +} diff --git a/src/parser/statement.h b/src/parser/statement.h index c5f128d9..b8eb795e 100644 --- a/src/parser/statement.h +++ b/src/parser/statement.h @@ -9,5 +9,6 @@ ParserReturn* parse_return_stmt(Parser* parser); ParserReturn* parse_expression_stmt(Parser* parser); ParserReturn* parse_if_else_stmt(Parser* parser); ParserReturn* parse_while_stmt(Parser* parser); +ParserReturn* parse_for_stmt(Parser* parser); #endif diff --git a/src/parser/util.c b/src/parser/util.c index d45e53c8..d62ed564 100644 --- a/src/parser/util.c +++ b/src/parser/util.c @@ -41,11 +41,9 @@ ErrorableInt* external_may_function_definition(Parser* parser) { return new_errint(ctoken->type == CTOKEN_LBRACE); } -ErrorableInt* blockitem_may_decl(Parser* parser) { +int item_may_decl(Parser* parser) { CToken* ctoken = vector_at(parser->ctokens, parser->index); - int may_decl = - ctoken_is_storage_class_specifier(ctoken) || ctoken_is_type_specifier(ctoken, parser->typedef_names_set); - return new_errint(may_decl); + return ctoken_is_storage_class_specifier(ctoken) || ctoken_is_type_specifier(ctoken, parser->typedef_names_set); } int ctoken_is_storage_class_specifier(CToken* ctoken) { diff --git a/src/parser/util.h b/src/parser/util.h index d1af74eb..2c5184d5 100644 --- a/src/parser/util.h +++ b/src/parser/util.h @@ -6,7 +6,7 @@ #include "./parser.h" ErrorableInt* external_may_function_definition(Parser* parser); -ErrorableInt* blockitem_may_decl(Parser* parser); +int item_may_decl(Parser* parser); int ctoken_is_storage_class_specifier(CToken* ctoken); int ctoken_is_type_specifier(CToken* ctoken, Set* typedef_names_set); Error* consume_ctoken(Parser* parser, CTokenType ctoken_type); diff --git a/tests/parser/test_statement.c b/tests/parser/test_statement.c index 79aead8b..4bb1f180 100644 --- a/tests/parser/test_statement.c +++ b/tests/parser/test_statement.c @@ -21,6 +21,12 @@ void test_parse_if_stmt(void); void test_parse_if_else_stmt(void); void test_parse_if_else_stmt_chain(void); void test_parse_while_stmt(void); +void test_parse_for_stmt_init_declaration(void); +void test_parse_for_stmt_init_expression(void); +void test_parse_for_stmt_init_null(void); +void test_parse_for_stmt_condition_null(void); +void test_parse_for_stmt_expression_null(void); +void test_parse_for_stmt_all_null(void); void run_stmt_parser_test(Vector* input, Ast* expected); @@ -44,6 +50,12 @@ CU_Suite* add_test_suite_stmt_parser(void) { CU_ADD_TEST(suite, test_parse_if_else_stmt); CU_ADD_TEST(suite, test_parse_if_else_stmt_chain); CU_ADD_TEST(suite, test_parse_while_stmt); + CU_ADD_TEST(suite, test_parse_for_stmt_init_declaration); + CU_ADD_TEST(suite, test_parse_for_stmt_init_expression); + CU_ADD_TEST(suite, test_parse_for_stmt_init_null); + CU_ADD_TEST(suite, test_parse_for_stmt_condition_null); + CU_ADD_TEST(suite, test_parse_for_stmt_expression_null); + CU_ADD_TEST(suite, test_parse_for_stmt_all_null); return suite; } @@ -962,6 +974,221 @@ void test_parse_while_stmt(void) { delete_ast(expected); } +void test_parse_for_stmt_init_declaration(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_INT)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_LESS)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 10))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_PLUS_PLUS)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_ASTERISK_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 2))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Ast* expected = + new_ast(AST_FOR_STMT, 4, // non-terminal + new_ast(AST_DECL, 2, // non-terminal + new_ast(AST_DECL_SPECS, 1, // non-terminal + new_ast(AST_TYPE_INT, 0)), + new_ast(AST_INIT_DECLOR_LIST, 1, // non-terminal + new_ast(AST_INIT_DECLOR, 2, // non-terminal + new_identifier_ast(AST_IDENT_DECLOR, new_string("i")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 0))))), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_LESS_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("i")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 10)))), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_POSTINC_EXPR, 1, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("i")))), + new_ast(AST_CMPD_STMT, 1, // non-terminal + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_MUL_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 2)))))); + + run_stmt_parser_test(input, expected); + + delete_ast(expected); +} + +void test_parse_for_stmt_init_expression(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("n"))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_GREATER)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_MINUS_MINUS)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_SLASH_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 2))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Ast* expected = + new_ast(AST_FOR_STMT, 4, // non-terminal + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("i")), + new_identifier_ast(AST_IDENT_EXPR, new_string("n")))), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_GREATER_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("i")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 0)))), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_POSTDEC_EXPR, 1, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("i")))), + new_ast(AST_CMPD_STMT, 1, + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_DIV_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 2)))))); + + run_stmt_parser_test(input, expected); + + delete_ast(expected); +} + +void test_parse_for_stmt_init_null(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_LESS)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 10))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_PLUS_PLUS)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Ast* expected = new_ast(AST_FOR_STMT, 4, // non-terminal + new_ast(AST_NULL_STMT, 0), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_LESS_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("i")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 10)))), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_POSTINC_EXPR, 1, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("i")))), + new_ast(AST_CMPD_STMT, 0)); + + run_stmt_parser_test(input, expected); + + delete_ast(expected); +} + +void test_parse_for_stmt_condition_null(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_PLUS_PLUS)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Ast* expected = new_ast(AST_FOR_STMT, 4, // non-terminal + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("i")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 0)))), + new_ast(AST_NULL_STMT, 0), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_POSTINC_EXPR, 1, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("i")))), + new_ast(AST_CMPD_STMT, 0)); + + run_stmt_parser_test(input, expected); + + delete_ast(expected); +} + +void test_parse_for_stmt_expression_null(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_LESS)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 10))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Ast* expected = new_ast(AST_FOR_STMT, 4, // non-terminal + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("i")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 0)))), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_LESS_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("i")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 10)))), + new_ast(AST_NULL_STMT, 0), new_ast(AST_CMPD_STMT, 0)); + + run_stmt_parser_test(input, expected); + + delete_ast(expected); +} + +void test_parse_for_stmt_all_null(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Ast* expected = new_ast(AST_FOR_STMT, 4, // non-terminal + new_ast(AST_NULL_STMT, 0), new_ast(AST_NULL_STMT, 0), new_ast(AST_NULL_STMT, 0), + new_ast(AST_CMPD_STMT, 0)); + + run_stmt_parser_test(input, expected); + + delete_ast(expected); +} + void run_stmt_parser_test(Vector* input, Ast* expected) { Parser* parser = new_parser(input); Ast* actual = NULL; diff --git a/tests/parser/test_statement_error.c b/tests/parser/test_statement_error.c index fba86bd6..c130ea0f 100644 --- a/tests/parser/test_statement_error.c +++ b/tests/parser/test_statement_error.c @@ -16,6 +16,15 @@ void test_parse_while_stmt_error_controlling_lparen(void); void test_parse_while_stmt_error_controlling_expr(void); void test_parse_while_stmt_error_controlling_rparen(void); void test_parse_while_stmt_error_body(void); +void test_parse_for_stmt_error_lparen(void); +void test_parse_for_stmt_error_init_decl(void); +void test_parse_for_stmt_error_init_expr(void); +void test_parse_for_stmt_error_init_expr_semicolon(void); +void test_parse_for_stmt_error_controlling_expr(void); +void test_parse_for_stmt_error_controlling_expr_semicolon(void); +void test_parse_for_stmt_error_expr(void); +void test_parse_for_stmt_error_expr_rparen(void); +void test_parse_for_stmt_error_body(void); void run_stmt_parser_error_test(Vector* input, Error* expected); @@ -34,6 +43,15 @@ CU_Suite* add_test_suite_stmt_parser_error(void) { CU_ADD_TEST(suite, test_parse_while_stmt_error_controlling_expr); CU_ADD_TEST(suite, test_parse_while_stmt_error_controlling_rparen); CU_ADD_TEST(suite, test_parse_while_stmt_error_body); + CU_ADD_TEST(suite, test_parse_for_stmt_error_lparen); + CU_ADD_TEST(suite, test_parse_for_stmt_error_init_decl); + CU_ADD_TEST(suite, test_parse_for_stmt_error_init_expr); + CU_ADD_TEST(suite, test_parse_for_stmt_error_init_expr_semicolon); + CU_ADD_TEST(suite, test_parse_for_stmt_error_controlling_expr); + CU_ADD_TEST(suite, test_parse_for_stmt_error_controlling_expr_semicolon); + CU_ADD_TEST(suite, test_parse_for_stmt_error_expr); + CU_ADD_TEST(suite, test_parse_for_stmt_error_expr_rparen); + CU_ADD_TEST(suite, test_parse_for_stmt_error_body); return suite; } @@ -266,6 +284,197 @@ void test_parse_while_stmt_error_body(void) { delete_error(expected); } +void test_parse_for_stmt_error_lparen(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_INT)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("token ( expected, but got int"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_init_decl(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_INT)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("unexpected token ;"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_init_expr(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("unexpected token ;"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_init_expr_semicolon(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0))); + vector_push(input, new_ctoken(CTOKEN_COLON)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("token ; expected, but got :"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_controlling_expr(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_EXCLAM_EQUAL)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("unexpected token ;"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_controlling_expr_semicolon(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_EXCLAM_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 10))); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_PLUS_PLUS)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("token ; expected, but got identifier"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_expr(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("unexpected token ;"); + + run_stmt_parser_error_test(input, expected); +} + +void test_parse_for_stmt_error_expr_rparen(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_INT)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_LESS)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 10))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_PLUS_PLUS)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("token ) expected, but got {"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_body(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_INT)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("unexpected token ="); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + void run_stmt_parser_error_test(Vector* input, Error* expected) { Parser* parser = new_parser(input); Ast* ret = NULL;