diff --git a/sample/switch.c b/sample/switch.c new file mode 100644 index 00000000..ebbe8ec5 --- /dev/null +++ b/sample/switch.c @@ -0,0 +1,27 @@ +int small_switch(int x) { + switch (x) { + case 0: + return 2; + case 1: + return 6; + default: + return 0; + } +} + +int large_switch(int x) { + switch (x) { + case 0: + return 2; + case 2: + return 6; + case 4: + return 10; + case 6: + return 14; + case -10: + return 17; + default: + return 0; + } +} diff --git a/src/ast/ast.h b/src/ast/ast.h index aa12fed8..909e53be 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -54,12 +54,15 @@ typedef enum AstType { // statement AST_CMPD_STMT, + AST_CASE_STMT, + AST_DEFAULT_STMT, AST_CONTINUE_STMT, AST_BREAK_STMT, AST_RET_STMT, AST_EXPR_STMT, AST_NULL_STMT, AST_IF_STMT, + AST_SWITCH_STMT, AST_WHILE_STMT, AST_FOR_STMT, diff --git a/src/ctoken/ctoken.c b/src/ctoken/ctoken.c index 1f4e7303..9255bb4b 100644 --- a/src/ctoken/ctoken.c +++ b/src/ctoken/ctoken.c @@ -9,8 +9,9 @@ BaseType t_ctoken = { char* ctoken_types[] = { // non-punctuators - "break", "char", "continue", "else", "enum", "for", "if", "int", "long", "return", "sizeof", "struct", "typedef", - "unsigned", "void", "while", "identifier", "integer-constant", "character-constant", "string-literal", + "break", "case", "char", "continue", "default", "else", "enum", "for", "if", "int", "long", "return", "sizeof", + "struct", "switch", "typedef", "unsigned", "void", "while", "identifier", "integer-constant", "character-constant", + "string-literal", // punctuators "[", "]", "(", ")", "{", "}", ".", "->", "++", "--", "&", "*", "+", "-", "~", "!", "/", "%", "<<", ">>", "<", ">", "<=", ">=", "==", "!=", "^", "|", "&&", "||", "?", ":", ";", "=", diff --git a/src/ctoken/ctoken.h b/src/ctoken/ctoken.h index c60912c8..9468dc08 100644 --- a/src/ctoken/ctoken.h +++ b/src/ctoken/ctoken.h @@ -8,8 +8,10 @@ typedef enum CTokenType { // keyword CTOKEN_KEYWORD_BREAK, + CTOKEN_KEYWORD_CASE, CTOKEN_KEYWORD_CHAR, CTOKEN_KEYWORD_CONTINUE, + CTOKEN_KEYWORD_DEFAULT, CTOKEN_KEYWORD_ELSE, CTOKEN_KEYWORD_ENUM, CTOKEN_KEYWORD_FOR, @@ -19,6 +21,7 @@ typedef enum CTokenType { CTOKEN_KEYWORD_RETURN, CTOKEN_KEYWORD_SIZEOF, CTOKEN_KEYWORD_STRUCT, + CTOKEN_KEYWORD_SWITCH, CTOKEN_KEYWORD_TYPEDEF, CTOKEN_KEYWORD_UNSIGNED, CTOKEN_KEYWORD_VOID, diff --git a/src/immcgen/immcgen.c b/src/immcgen/immcgen.c index 8a8dc043..42c1bdf4 100644 --- a/src/immcgen/immcgen.c +++ b/src/immcgen/immcgen.c @@ -20,6 +20,7 @@ Immcgen* new_immcgen(Srt* srt) { immcgen->continue_label_id = -1; immcgen->break_label_id = -1; immcgen->return_label_id = -1; + immcgen->case_label_values = NULL; immcgen->label_id = -1; return immcgen; } @@ -53,6 +54,12 @@ Vector* immcgen_generate_immcode(Immcgen* immcgen) { case SRT_INIT: codes = gen_initializer_immcode(immcgen); break; + case SRT_CASE_STMT: + codes = gen_case_stmt_immcode(immcgen); + break; + case SRT_DEFAULT_STMT: + codes = gen_default_stmt_immcode(immcgen); + break; case SRT_CMPD_STMT: immcgen->symbol_table = symboltable_enter_scope(immcgen->symbol_table); immcgen->tag_table = tagtable_enter_scope(immcgen->tag_table); @@ -78,6 +85,9 @@ Vector* immcgen_generate_immcode(Immcgen* immcgen) { case SRT_IF_STMT: codes = gen_if_else_stmt_immcode(immcgen); break; + case SRT_SWITCH_STMT: + codes = gen_switch_stmt_immcode(immcgen); + break; case SRT_WHILE_STMT: codes = gen_while_stmt_immcode(immcgen); break; @@ -175,5 +185,8 @@ void delete_immcgen(Immcgen* immcgen) { if (immcgen->initialized_dtype != NULL) { delete_dtype(immcgen->initialized_dtype); } + if (immcgen->case_label_values != NULL) { + delete_vector(immcgen->case_label_values); + } free(immcgen); } diff --git a/src/immcgen/immcgen.h b/src/immcgen/immcgen.h index 19db642f..935f91b2 100644 --- a/src/immcgen/immcgen.h +++ b/src/immcgen/immcgen.h @@ -19,6 +19,8 @@ typedef struct Immcgen { int continue_label_id; int break_label_id; int return_label_id; + Vector* case_label_values; + int default_label_id; int label_id; } Immcgen; diff --git a/src/immcgen/statement.c b/src/immcgen/statement.c index 796f3ea8..08918078 100644 --- a/src/immcgen/statement.c +++ b/src/immcgen/statement.c @@ -1,6 +1,7 @@ #include "./statement.h" #include "../common/type.h" #include "../immc/immc.h" +#include "../pair/pair.h" #include "./util.h" #include @@ -11,6 +12,39 @@ Vector* gen_compound_stmt_immcode(Immcgen* immcgen) { return codes; } +Vector* gen_case_stmt_immcode(Immcgen* immcgen) { + Vector* codes = new_vector(&t_immc); + + Srt* case_value_srt = vector_at(immcgen->srt->children, 0); + + immcgen->label_id++; + int case_label_id = immcgen->label_id; + + Pair* label_value_pair = new_pair(&t_integer, &t_iliteral); + pair_set(label_value_pair, new_integer(case_label_id), iliteral_copy(case_value_srt->iliteral)); + vector_push(immcgen->case_label_values, label_value_pair); + + vector_push(codes, new_label_immc_from_id(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, case_label_id)); + + append_child_immcode(immcgen, codes, 1); + return codes; +} + +Vector* gen_default_stmt_immcode(Immcgen* immcgen) { + Vector* codes = new_vector(&t_immc); + + immcgen->label_id++; + int default_label_id = immcgen->label_id; + + immcgen->default_label_id = default_label_id; + + vector_push(codes, new_label_immc_from_id(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, default_label_id)); + + append_child_immcode(immcgen, codes, 0); + + return codes; +} + Vector* gen_continue_stmt_immcode(Immcgen* immcgen) { Vector* codes = new_vector(&t_immc); ImmcOpe* continue_label = new_label_immcope_from_id(immcgen->continue_label_id); @@ -126,6 +160,63 @@ Vector* gen_if_with_else_stmt_immcode(Immcgen* immcgen) { return codes; } +Vector* gen_switch_stmt_immcode(Immcgen* immcgen) { + Vector* codes = new_vector(&t_immc); + + Vector* cases_codes = new_vector(&t_immc); + ImmcOpe* reg = gen_child_reg_immcope(immcgen, cases_codes, 0); + + Vector* body_codes = new_vector(&t_immc); + immcgen->label_id++; + int break_label_id = immcgen->label_id; + + Vector* original_case_label_values = immcgen->case_label_values; + int original_default_label_id = immcgen->default_label_id; + int original_break_label_id = immcgen->break_label_id; + + immcgen->case_label_values = new_vector(&t_pair); + immcgen->default_label_id = -1; + + immcgen->break_label_id = break_label_id; + append_child_immcode(immcgen, body_codes, 1); + immcgen->break_label_id = original_break_label_id; + + int num_labels = vector_size(immcgen->case_label_values); + for (int i = 0; i < num_labels; i++) { + Pair* label_value_pair = vector_at(immcgen->case_label_values, i); + int* case_label_id_ref = pair_first(label_value_pair); + ImmcOpe* case_label = new_label_immcope_from_id(*case_label_id_ref); + + IntegerLiteral* case_value_iliteral = pair_second(label_value_pair); + ImmcSuffix suffix = immcsuffix_get(iliteral_nbytes(case_value_iliteral)); + ImmcOpe* case_value = new_int_immcope(suffix, iliteral_copy(case_value_iliteral)); + + vector_push(cases_codes, new_inst_immc(IMMC_INST_JEQ, case_label, immcope_copy(reg), case_value)); + } + delete_immcope(reg); + + if (immcgen->default_label_id > 0) { + ImmcOpe* default_label = new_label_immcope_from_id(immcgen->default_label_id); + vector_push(cases_codes, new_inst_immc(IMMC_INST_JMP, default_label, NULL, NULL)); + } else { + ImmcOpe* break_label = new_label_immcope_from_id(break_label_id); + vector_push(cases_codes, new_inst_immc(IMMC_INST_JMP, break_label, NULL, NULL)); + } + + delete_vector(immcgen->case_label_values); + immcgen->case_label_values = original_case_label_values; + immcgen->default_label_id = original_default_label_id; + + vector_push(body_codes, new_label_immc_from_id(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, break_label_id)); + + vector_extend(codes, cases_codes); + delete_vector(cases_codes); + vector_extend(codes, body_codes); + delete_vector(body_codes); + + return codes; +} + Vector* gen_while_stmt_immcode(Immcgen* immcgen) { Vector* codes = new_vector(&t_immc); diff --git a/src/immcgen/statement.h b/src/immcgen/statement.h index 87ae17ce..32597b8a 100644 --- a/src/immcgen/statement.h +++ b/src/immcgen/statement.h @@ -3,6 +3,8 @@ #include "./immcgen.h" +Vector* gen_case_stmt_immcode(Immcgen* immcgen); +Vector* gen_default_stmt_immcode(Immcgen* immcgen); Vector* gen_compound_stmt_immcode(Immcgen* immcgen); Vector* gen_continue_stmt_immcode(Immcgen* immcgen); Vector* gen_break_stmt_immcode(Immcgen* immcgen); @@ -10,6 +12,7 @@ Vector* gen_return_stmt_immcode(Immcgen* immcgen); Vector* gen_expression_stmt_immcode(Immcgen* immcgen); Vector* gen_null_stmt_immcode(void); Vector* gen_if_else_stmt_immcode(Immcgen* immcgen); +Vector* gen_switch_stmt_immcode(Immcgen* immcgen); Vector* gen_while_stmt_immcode(Immcgen* immcgen); Vector* gen_for_stmt_immcode(Immcgen* immcgen); diff --git a/src/lexer/util.c b/src/lexer/util.c index 9c3e295e..bd34ac57 100644 --- a/src/lexer/util.c +++ b/src/lexer/util.c @@ -10,8 +10,10 @@ Map* new_keyword_map(void) { Map* keyword_map = new_map(&t_hashable_string, &t_integer); ctoken_map_add(keyword_map, "break", CTOKEN_KEYWORD_BREAK); + ctoken_map_add(keyword_map, "case", CTOKEN_KEYWORD_CASE); ctoken_map_add(keyword_map, "char", CTOKEN_KEYWORD_CHAR); ctoken_map_add(keyword_map, "continue", CTOKEN_KEYWORD_CONTINUE); + ctoken_map_add(keyword_map, "default", CTOKEN_KEYWORD_DEFAULT); ctoken_map_add(keyword_map, "else", CTOKEN_KEYWORD_ELSE); ctoken_map_add(keyword_map, "enum", CTOKEN_KEYWORD_ENUM); ctoken_map_add(keyword_map, "for", CTOKEN_KEYWORD_FOR); @@ -21,6 +23,7 @@ Map* new_keyword_map(void) { ctoken_map_add(keyword_map, "return", CTOKEN_KEYWORD_RETURN); ctoken_map_add(keyword_map, "sizeof", CTOKEN_KEYWORD_SIZEOF); ctoken_map_add(keyword_map, "struct", CTOKEN_KEYWORD_STRUCT); + ctoken_map_add(keyword_map, "switch", CTOKEN_KEYWORD_SWITCH); ctoken_map_add(keyword_map, "typedef", CTOKEN_KEYWORD_TYPEDEF); ctoken_map_add(keyword_map, "unsigned", CTOKEN_KEYWORD_UNSIGNED); ctoken_map_add(keyword_map, "void", CTOKEN_KEYWORD_VOID); diff --git a/src/literal/iliteral.c b/src/literal/iliteral.c index 1b3fa265..89015ec5 100644 --- a/src/literal/iliteral.c +++ b/src/literal/iliteral.c @@ -43,6 +43,11 @@ int iliteral_isunsigned(IntegerLiteral* iliteral) { return iliteral_type_isunsigned(iliteral->type); } +int iliteral_nbytes(IntegerLiteral* iliteral) { + // TODO: consider range of integer literal value + return iliteral_type_nbytes(iliteral->type); +} + char* iliteral_display_string(IntegerLiteral* iliteral) { char* display_string = malloc(50 * sizeof(char)); if (iliteral_isunsigned(iliteral)) { @@ -63,6 +68,22 @@ int iliteral_type_isunsigned(IntegerLiteralType type) { return type == INTEGER_UNSIGNED_INT || type == INTEGER_UNSIGNED_LONG || type == INTEGER_UNSIGNED_LONGLONG; } +int iliteral_type_nbytes(IntegerLiteralType type) { + switch (type) { + case INTEGER_INT: + case INTEGER_UNSIGNED_INT: + return 4; + case INTEGER_LONG: + case INTEGER_UNSIGNED_LONG: + return 8; + case INTEGER_LONGLONG: + case INTEGER_UNSIGNED_LONGLONG: + return 8; + default: + return 0; + } +} + IntegerLiteralType iliteral_type_get(int scalar_rank, int is_unsigned) { if (scalar_rank < 3) { return is_unsigned ? INTEGER_UNSIGNED_INT : INTEGER_INT; diff --git a/src/literal/iliteral.h b/src/literal/iliteral.h index ca87f2ce..8503aaaa 100644 --- a/src/literal/iliteral.h +++ b/src/literal/iliteral.h @@ -24,10 +24,12 @@ IntegerLiteral* new_signed_iliteral(IntegerLiteralType type, long long value); IntegerLiteral* new_unsigned_iliteral(IntegerLiteralType type, unsigned long long value); IntegerLiteral* iliteral_copy(IntegerLiteral* iliteral); int iliteral_isunsigned(IntegerLiteral* iliteral); +int iliteral_nbytes(IntegerLiteral* iliteral); char* iliteral_display_string(IntegerLiteral* iliteral); void delete_iliteral(IntegerLiteral* iliteral); int iliteral_type_isunsigned(IntegerLiteralType type); +int iliteral_type_nbytes(IntegerLiteralType type); IntegerLiteralType iliteral_type_get(int rank, int is_unsigned); #endif diff --git a/src/pair/pair.c b/src/pair/pair.c index 0a49f3fc..1fe7f45e 100644 --- a/src/pair/pair.c +++ b/src/pair/pair.c @@ -9,6 +9,11 @@ struct Pair { void* second; }; +BaseType t_pair = { + .copy_object = (void* (*)(void*))pair_copy, + .delete_object = (void (*)(void*))delete_pair, +}; + Pair* new_pair(BaseType* t_first, BaseType* t_second) { Pair* pair = malloc(sizeof(Pair)); pair->t_first = t_first; diff --git a/src/pair/pair.h b/src/pair/pair.h index 41d40558..6eb4b169 100644 --- a/src/pair/pair.h +++ b/src/pair/pair.h @@ -5,6 +5,8 @@ typedef struct Pair Pair; +extern BaseType t_pair; + Pair* new_pair(BaseType* t_first, BaseType* t_second); Pair* pair_copy(Pair* pair); void* pair_first(Pair* pair); diff --git a/src/parser/statement.c b/src/parser/statement.c index f9f0f55d..facd004d 100644 --- a/src/parser/statement.c +++ b/src/parser/statement.c @@ -8,6 +8,10 @@ ParserReturn* parse_stmt(Parser* parser) { CToken* ctoken = vector_at(parser->ctokens, parser->index); switch (ctoken->type) { + case CTOKEN_KEYWORD_CASE: + return parse_case_stmt(parser); + case CTOKEN_KEYWORD_DEFAULT: + return parse_default_stmt(parser); case CTOKEN_LBRACE: return parse_compound_stmt(parser); case CTOKEN_KEYWORD_CONTINUE: @@ -18,6 +22,8 @@ ParserReturn* parse_stmt(Parser* parser) { return parse_return_stmt(parser); case CTOKEN_KEYWORD_IF: return parse_if_else_stmt(parser); + case CTOKEN_KEYWORD_SWITCH: + return parse_switch_stmt(parser); case CTOKEN_KEYWORD_WHILE: return parse_while_stmt(parser); case CTOKEN_KEYWORD_FOR: @@ -27,6 +33,67 @@ ParserReturn* parse_stmt(Parser* parser) { } } +ParserReturn* parse_case_stmt(Parser* parser) { + Ast* ast = new_ast(AST_CASE_STMT, 0); + Ast* child_ast = NULL; + Error* err = NULL; + + err = consume_ctoken(parser, CTOKEN_KEYWORD_CASE); + if (err != NULL) { + delete_ast(ast); + return new_parserret_error(err); + } + + parserret_assign(&child_ast, &err, parse_expr(parser)); + if (err != NULL) { + delete_ast(ast); + return new_parserret_error(err); + } + vector_push(ast->children, child_ast); + + err = consume_ctoken(parser, CTOKEN_COLON); + 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); +} + +ParserReturn* parse_default_stmt(Parser* parser) { + Ast* ast = new_ast(AST_DEFAULT_STMT, 0); + Ast* child_ast = NULL; + Error* err = NULL; + + err = consume_ctoken(parser, CTOKEN_KEYWORD_DEFAULT); + if (err != NULL) { + delete_ast(ast); + return new_parserret_error(err); + } + + err = consume_ctoken(parser, CTOKEN_COLON); + 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); +} + ParserReturn* parse_compound_stmt(Parser* parser) { Ast* ast = new_ast(AST_CMPD_STMT, 0); Ast* child_ast = NULL; @@ -213,6 +280,46 @@ ParserReturn* parse_if_else_stmt(Parser* parser) { return new_parserret(ast); } +ParserReturn* parse_switch_stmt(Parser* parser) { + Ast* ast = new_ast(AST_SWITCH_STMT, 0); + Ast* child_ast = NULL; + Error* err = NULL; + + err = consume_ctoken(parser, CTOKEN_KEYWORD_SWITCH); + 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); + } + + parserret_assign(&child_ast, &err, parse_expr(parser)); + if (err != NULL) { + delete_ast(ast); + return new_parserret_error(err); + } + vector_push(ast->children, 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); +} + ParserReturn* parse_while_stmt(Parser* parser) { Ast* ast = new_ast(AST_WHILE_STMT, 0); Ast* child_ast = NULL; diff --git a/src/parser/statement.h b/src/parser/statement.h index d027b47f..abaa02e2 100644 --- a/src/parser/statement.h +++ b/src/parser/statement.h @@ -4,12 +4,15 @@ #include "./parser.h" ParserReturn* parse_stmt(Parser* parser); +ParserReturn* parse_case_stmt(Parser* parser); +ParserReturn* parse_default_stmt(Parser* parser); ParserReturn* parse_compound_stmt(Parser* parser); ParserReturn* parse_continue_stmt(Parser* parser); ParserReturn* parse_break_stmt(Parser* parser); ParserReturn* parse_return_stmt(Parser* parser); ParserReturn* parse_expression_stmt(Parser* parser); ParserReturn* parse_if_else_stmt(Parser* parser); +ParserReturn* parse_switch_stmt(Parser* parser); ParserReturn* parse_while_stmt(Parser* parser); ParserReturn* parse_for_stmt(Parser* parser); diff --git a/src/resolver/declaration.c b/src/resolver/declaration.c index c621c93e..c2b52192 100644 --- a/src/resolver/declaration.c +++ b/src/resolver/declaration.c @@ -752,7 +752,7 @@ ResolverReturn* resolve_declarator(Resolver* resolver) { if (array_size_srt->type != SRT_ILITERAL_EXPR || iliteral_isunsigned(array_size_srt->iliteral)) { errs = new_vector(&t_error); - err = new_error("only integer constant is supported as array size"); + err = new_error("only signed integer constant is supported as array size"); vector_push(errs, err); delete_srt(array_size_srt); break; diff --git a/src/resolver/expression.c b/src/resolver/expression.c index af009527..c54ba79c 100644 --- a/src/resolver/expression.c +++ b/src/resolver/expression.c @@ -1624,6 +1624,7 @@ ResolverReturn* resolve_integer_expr(Resolver* resolver) { DType* dtype = NULL; switch (ast->iliteral->type) { + // TODO: consider range of integer literal value case INTEGER_INT: dtype = new_integer_dtype(DTYPE_INT); break; diff --git a/src/resolver/resolver.c b/src/resolver/resolver.c index 15f99ee0..3a8d2f60 100644 --- a/src/resolver/resolver.c +++ b/src/resolver/resolver.c @@ -11,6 +11,8 @@ Resolver* new_resolver(Ast* ast) { resolver->symbol_table = new_symboltable(); resolver->tag_table = new_tagtable(); resolver->inside_loop = 0; + resolver->switch_cases = NULL; + resolver->switch_default_exists = 0; resolver->return_dtype = NULL; resolver->specifier_dtype = NULL; resolver->default_enum_value = 0; @@ -36,6 +38,9 @@ void delete_resolver(Resolver* resolver) { } delete_symboltable(resolver->symbol_table); delete_tagtable(resolver->tag_table); + if (resolver->switch_cases != NULL) { + delete_vector(resolver->switch_cases); + } if (resolver->return_dtype != NULL) { delete_dtype(resolver->return_dtype); } diff --git a/src/resolver/resolver.h b/src/resolver/resolver.h index df5415da..7d6867d7 100644 --- a/src/resolver/resolver.h +++ b/src/resolver/resolver.h @@ -2,6 +2,7 @@ #define UMLCC_RESOLVER_H #include "../ast/ast.h" +#include "../set/set.h" #include "../symtab/symtab.h" #include "../tagtab/tagtab.h" #include "./resolverret.h" @@ -13,6 +14,8 @@ typedef struct Resolver { SymbolTable* symbol_table; TagTable* tag_table; int inside_loop; + Vector* switch_cases; + int switch_default_exists; DType* return_dtype; DType* specifier_dtype; int default_enum_value; diff --git a/src/resolver/statement.c b/src/resolver/statement.c index 3a1e1232..f8ddaa9f 100644 --- a/src/resolver/statement.c +++ b/src/resolver/statement.c @@ -19,6 +19,12 @@ ResolverReturn* resolve_stmt(Resolver* resolver) { resolver->tag_table = tagtable_exit_scope(resolver->tag_table); resolver->symbol_table = symboltable_exit_scope(resolver->symbol_table); break; + case AST_CASE_STMT: + resolverret_assign(&srt, &errs, resolve_case_stmt(resolver)); + break; + case AST_DEFAULT_STMT: + resolverret_assign(&srt, &errs, resolve_default_stmt(resolver)); + break; case AST_CONTINUE_STMT: resolverret_assign(&srt, &errs, resolve_continue_stmt(resolver)); break; @@ -37,6 +43,9 @@ ResolverReturn* resolve_stmt(Resolver* resolver) { case AST_IF_STMT: resolverret_assign(&srt, &errs, resolve_if_else_stmt(resolver)); break; + case AST_SWITCH_STMT: + resolverret_assign(&srt, &errs, resolve_switch_stmt(resolver)); + break; case AST_WHILE_STMT: resolverret_assign(&srt, &errs, resolve_while_stmt(resolver)); break; @@ -59,6 +68,110 @@ ResolverReturn* resolve_stmt(Resolver* resolver) { return new_resolverret(srt); } +ResolverReturn* resolve_case_stmt(Resolver* resolver) { + Srt* srt = new_srt(SRT_CASE_STMT, 0); + Srt* child_srt = NULL; + Vector* errs = NULL; + Error* err = NULL; + Ast* ast = resolver->ast; + + if (resolver->switch_cases == NULL) { + errs = new_vector(&t_error); + err = new_error("case statement is not allowed outside of switch"); + vector_push(errs, err); + delete_srt(srt); + return new_resolverret_errors(errs); + } + + resolver->ast = vector_at(ast->children, 0); + resolverret_assign(&child_srt, &errs, resolve_expr(resolver)); + resolver->ast = ast; + if (errs != NULL) { + delete_srt(srt); + return new_resolverret_errors(errs); + } + + if (child_srt->type != SRT_ILITERAL_EXPR || iliteral_isunsigned(child_srt->iliteral)) { + errs = new_vector(&t_error); + err = new_error("only signed integer constant is supported as case label"); + vector_push(errs, err); + delete_srt(child_srt); + delete_srt(srt); + return new_resolverret_errors(errs); + } + + child_srt = perform_integer_promotion(child_srt); + vector_push(srt->children, child_srt); + + IntegerLiteral* case_value_iliteral = child_srt->iliteral; + int num_cases = vector_size(resolver->switch_cases); + for (int i = 0; i < num_cases; i++) { + IntegerLiteral* iliteral = vector_at(resolver->switch_cases, i); + if (iliteral->signed_value != case_value_iliteral->signed_value) { + continue; + } + errs = new_vector(&t_error); + err = new_error("value of case label is already used in switch"); + vector_push(errs, err); + delete_srt(srt); + return new_resolverret_errors(errs); + } + + vector_push(resolver->switch_cases, iliteral_copy(case_value_iliteral)); + + resolver->ast = vector_at(ast->children, 1); + resolverret_assign(&child_srt, &errs, resolve_stmt(resolver)); + resolver->ast = ast; + + if (errs != NULL) { + delete_srt(srt); + return new_resolverret_errors(errs); + } + + vector_push(srt->children, child_srt); + + return new_resolverret(srt); +} + +ResolverReturn* resolve_default_stmt(Resolver* resolver) { + Srt* srt = new_srt(SRT_DEFAULT_STMT, 0); + Srt* child_srt = NULL; + Vector* errs = NULL; + Error* err = NULL; + Ast* ast = resolver->ast; + + if (resolver->switch_cases == NULL) { + errs = new_vector(&t_error); + err = new_error("default statement is not allowed outside of switch"); + vector_push(errs, err); + delete_srt(srt); + return new_resolverret_errors(errs); + } + + if (resolver->switch_default_exists) { + errs = new_vector(&t_error); + err = new_error("default statement is already used in switch"); + vector_push(errs, err); + delete_srt(srt); + return new_resolverret_errors(errs); + } + + resolver->switch_default_exists = 1; + + resolver->ast = vector_at(ast->children, 0); + resolverret_assign(&child_srt, &errs, resolve_stmt(resolver)); + resolver->ast = ast; + + if (errs != NULL) { + delete_srt(srt); + return new_resolverret_errors(errs); + } + + vector_push(srt->children, child_srt); + + return new_resolverret(srt); +} + ResolverReturn* resolve_compound_stmt(Resolver* resolver) { Srt* srt = new_srt(SRT_CMPD_STMT, 0); Vector* errs = NULL; @@ -166,7 +279,7 @@ ResolverReturn* resolve_continue_stmt(Resolver* resolver) { } ResolverReturn* resolve_break_stmt(Resolver* resolver) { - if (!resolver->inside_loop) { + if (!resolver->inside_loop && resolver->switch_cases == NULL) { Vector* errs = new_vector(&t_error); Error* err = new_error("break statement is not allowed outside of loop or switch"); vector_push(errs, err); @@ -253,6 +366,57 @@ ResolverReturn* resolve_if_else_stmt(Resolver* resolver) { return new_resolverret(srt); } +ResolverReturn* resolve_switch_stmt(Resolver* resolver) { + Srt* srt = new_srt(SRT_SWITCH_STMT, 0); + Srt* child_srt = NULL; + Vector* errs = NULL; + Error* err = NULL; + Ast* ast = resolver->ast; + + resolver->ast = vector_at(ast->children, 0); + resolverret_assign(&child_srt, &errs, resolve_expr(resolver)); + resolver->ast = ast; + if (errs != NULL) { + delete_srt(srt); + return new_resolverret_errors(errs); + } + + child_srt = convert_to_ptr_if_array(child_srt); + child_srt = convert_to_ptr_if_function(child_srt); + child_srt = perform_integer_promotion(child_srt); + vector_push(srt->children, child_srt); + + if (!dtype_isinteger(child_srt->dtype)) { + errs = new_vector(&t_error); + err = new_error("condition of switch statement should have integer type"); + vector_push(errs, err); + delete_srt(srt); + return new_resolverret_errors(errs); + } + + Vector* original_switch_cases = resolver->switch_cases; + int original_switch_default_exists = resolver->switch_default_exists; + + resolver->switch_cases = new_vector(&t_iliteral); + resolver->switch_default_exists = 0; + + resolver->ast = vector_at(ast->children, 1); + resolverret_assign(&child_srt, &errs, resolve_stmt(resolver)); + resolver->ast = ast; + + delete_vector(resolver->switch_cases); + resolver->switch_cases = original_switch_cases; + resolver->switch_default_exists = original_switch_default_exists; + + if (errs != NULL) { + delete_srt(srt); + return new_resolverret_errors(errs); + } + vector_push(srt->children, child_srt); + + return new_resolverret(srt); +} + ResolverReturn* resolve_while_stmt(Resolver* resolver) { Srt* srt = new_srt(SRT_WHILE_STMT, 0); Srt* child_srt = NULL; diff --git a/src/resolver/statement.h b/src/resolver/statement.h index ae5d4f46..6334d5b2 100644 --- a/src/resolver/statement.h +++ b/src/resolver/statement.h @@ -4,6 +4,8 @@ #include "./resolver.h" ResolverReturn* resolve_stmt(Resolver* resolver); +ResolverReturn* resolve_case_stmt(Resolver* resolver); +ResolverReturn* resolve_default_stmt(Resolver* resolver); ResolverReturn* resolve_compound_stmt(Resolver* resolver); ResolverReturn* resolve_continue_stmt(Resolver* resolver); ResolverReturn* resolve_break_stmt(Resolver* resolver); @@ -11,6 +13,7 @@ ResolverReturn* resolve_return_stmt(Resolver* resolver); ResolverReturn* resolve_expression_stmt(Resolver* resolver); ResolverReturn* resolve_null_stmt(void); ResolverReturn* resolve_if_else_stmt(Resolver* resolver); +ResolverReturn* resolve_switch_stmt(Resolver* resolver); ResolverReturn* resolve_while_stmt(Resolver* resolver); ResolverReturn* resolve_for_stmt(Resolver* resolver); diff --git a/src/srt/srt.h b/src/srt/srt.h index a2b969fe..b9825019 100644 --- a/src/srt/srt.h +++ b/src/srt/srt.h @@ -24,12 +24,15 @@ typedef enum SrtType { // statement SRT_CMPD_STMT, + SRT_CASE_STMT, + SRT_DEFAULT_STMT, SRT_CONTINUE_STMT, SRT_BREAK_STMT, SRT_RET_STMT, SRT_EXPR_STMT, SRT_NULL_STMT, SRT_IF_STMT, + SRT_SWITCH_STMT, SRT_WHILE_STMT, SRT_FOR_STMT, diff --git a/test-fixtures/switch/expected.txt b/test-fixtures/switch/expected.txt new file mode 100644 index 00000000..5a3bd36c --- /dev/null +++ b/test-fixtures/switch/expected.txt @@ -0,0 +1,26 @@ +0 +1 +0 +1 +0 +1 + +4 +4 +8 +8 +8 +8 + +int +unsigned int +long +unsigned long +long long +unsigned long long + +-1 +10 +200 +3 + diff --git a/test-fixtures/switch/main.c b/test-fixtures/switch/main.c new file mode 100644 index 00000000..e8185888 --- /dev/null +++ b/test-fixtures/switch/main.c @@ -0,0 +1,110 @@ +void put_int(int x); +void put_str(char* s); +void put_blank_line(void); + +typedef enum IntegerType { + INT, + UNSIGNED_INT, + LONG, + UNSIGNED_LONG, + LONG_LONG, + UNSIGNED_LONG_LONG, +} IntegerType; + +int get_integer_unsigned(IntegerType type) { + switch (type) { + case UNSIGNED_INT: + case UNSIGNED_LONG: + case UNSIGNED_LONG_LONG: + return 1; + default: + return 0; + } +} + +void put_integer_size(IntegerType type) { + switch (type) { + case INT: + case UNSIGNED_INT: + put_int(4); + break; + case LONG: + case UNSIGNED_LONG: + put_int(8); + break; + case LONG_LONG: + case UNSIGNED_LONG_LONG: + put_int(8); + break; + } +} + +void put_integer_type_name(IntegerType type) { + switch (type) { + case INT: + put_str("int"); + break; + case UNSIGNED_INT: + put_str("unsigned int"); + break; + case LONG: + put_str("long"); + break; + case UNSIGNED_LONG: + put_str("unsigned long"); + break; + case LONG_LONG: + put_str("long long"); + break; + case UNSIGNED_LONG_LONG: + put_str("unsigned long long"); + break; + } +} + +int various_integer_literal(int x) { + switch (x) { + case 3: + return 3; + default: + return -1; + case 1L: + return 10; + case 2LL: + return 200; + } +} + +int main(void) { + put_int(get_integer_unsigned(INT)); + put_int(get_integer_unsigned(UNSIGNED_INT)); + put_int(get_integer_unsigned(LONG)); + put_int(get_integer_unsigned(UNSIGNED_LONG)); + put_int(get_integer_unsigned(LONG_LONG)); + put_int(get_integer_unsigned(UNSIGNED_LONG_LONG)); + put_blank_line(); + + put_integer_size(INT); + put_integer_size(UNSIGNED_INT); + put_integer_size(LONG); + put_integer_size(UNSIGNED_LONG); + put_integer_size(LONG_LONG); + put_integer_size(UNSIGNED_LONG_LONG); + put_blank_line(); + + put_integer_type_name(INT); + put_integer_type_name(UNSIGNED_INT); + put_integer_type_name(LONG); + put_integer_type_name(UNSIGNED_LONG); + put_integer_type_name(LONG_LONG); + put_integer_type_name(UNSIGNED_LONG_LONG); + put_blank_line(); + + put_int(various_integer_literal(0)); + put_int(various_integer_literal(1)); + put_int(various_integer_literal(2)); + put_int(various_integer_literal(3)); + put_blank_line(); + + return 0; +} diff --git a/tests/immcgen/test_statement.c b/tests/immcgen/test_statement.c index cc98abf9..67c9ac3e 100644 --- a/tests/immcgen/test_statement.c +++ b/tests/immcgen/test_statement.c @@ -2,6 +2,8 @@ #include "../../src/immcgen/statement.h" #include "../testlib/testlib.h" +void test_immcgen_case_stmt(void); +void test_immcgen_default_stmt(void); void test_immcgen_compound_stmt_completed_typedef(void); void test_immcgen_compound_stmt_int(void); void test_immcgen_compound_stmt_unsigned_int(void); @@ -20,8 +22,11 @@ void test_immcgen_return_stmt_void(void); void test_immcgen_expression_stmt(void); void test_immcgen_null_stmt(void); void test_immcgen_if_stmt(void); +void test_immcgen_if_stmt_nested(void); void test_immcgen_if_else_stmt(void); void test_immcgen_if_else_stmt_chain(void); +void test_immcgen_switch_stmt_int(void); +void test_immcgen_switch_stmt_various_integer(void); void test_immcgen_while_stmt(void); void test_immcgen_for_stmt_init_declaration(void); void test_immcgen_for_stmt_init_expression(void); @@ -31,6 +36,8 @@ void run_stmt_immcgen_test(Srt* input, SymbolTable* local_table, int return_labe CU_Suite* add_test_suite_stmt_immcgen(void) { CU_Suite* suite = CU_add_suite("test_suite_stmt_immcgen", NULL, NULL); + CU_ADD_TEST(suite, test_immcgen_case_stmt); + CU_ADD_TEST(suite, test_immcgen_default_stmt); CU_ADD_TEST(suite, test_immcgen_compound_stmt_completed_typedef); CU_ADD_TEST(suite, test_immcgen_compound_stmt_int); CU_ADD_TEST(suite, test_immcgen_compound_stmt_unsigned_int); @@ -49,8 +56,11 @@ CU_Suite* add_test_suite_stmt_immcgen(void) { CU_ADD_TEST(suite, test_immcgen_expression_stmt); CU_ADD_TEST(suite, test_immcgen_null_stmt); CU_ADD_TEST(suite, test_immcgen_if_stmt); + CU_ADD_TEST(suite, test_immcgen_if_stmt_nested); CU_ADD_TEST(suite, test_immcgen_if_else_stmt); CU_ADD_TEST(suite, test_immcgen_if_else_stmt_chain); + CU_ADD_TEST(suite, test_immcgen_switch_stmt_int); + CU_ADD_TEST(suite, test_immcgen_switch_stmt_various_integer); CU_ADD_TEST(suite, test_immcgen_while_stmt); CU_ADD_TEST(suite, test_immcgen_for_stmt_init_declaration); CU_ADD_TEST(suite, test_immcgen_for_stmt_init_expression); @@ -58,6 +68,104 @@ CU_Suite* add_test_suite_stmt_immcgen(void) { return suite; } +void test_immcgen_case_stmt(void) { + Srt* input = new_srt( + SRT_SWITCH_STMT, 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 0)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 1)))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_immc); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // dst + new_mem_immcope(4), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JEQ, // inst + new_label_immcope(new_string(".L1")), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 0))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L0")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L1"))); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // dst + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 1), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(8), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L0"))); + + run_stmt_immcgen_test(input, local_table, -1, expected); + + delete_vector(expected); +} + +void test_immcgen_default_stmt(void) { + Srt* input = new_srt( + SRT_SWITCH_STMT, 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_srt(SRT_DEFAULT_STMT, 1, // non-terminal + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 9)))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_immc); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // dst + new_mem_immcope(4), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L1")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L1"))); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // dst + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 9), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(8), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L0"))); + + run_stmt_immcgen_test(input, local_table, -1, expected); + + delete_vector(expected); +} + void test_immcgen_compound_stmt_completed_typedef(void) { Srt* input = new_srt( SRT_CMPD_STMT, 3, // non-terminal @@ -1021,6 +1129,68 @@ void test_immcgen_if_stmt(void) { delete_vector(expected); } +void test_immcgen_if_stmt_nested(void) { + Srt* input = new_srt( + SRT_IF_STMT, 2, // non-terminal + new_dtyped_srt(SRT_EQUAL_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 0))), + new_srt(SRT_IF_STMT, 2, // non-terminal + new_dtyped_srt(SRT_EQUAL_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y")), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 0))), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("z"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 1)))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("z"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_immc); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // dst + new_mem_immcope(4), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JNEQ, // inst + new_label_immcope(new_string(".L1")), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 0))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // dst + new_mem_immcope(8), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JNEQ, // inst + new_label_immcope(new_string(".L1")), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 0))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 2), // dst + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 1), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(12), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 2), // fst_src + NULL)); // snd_src + // .L0 is replaced by .L1 (end of if chain) + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L1"))); + + run_stmt_immcgen_test(input, local_table, -1, expected); + + delete_vector(expected); +} + void test_immcgen_if_else_stmt(void) { Srt* input = new_srt( SRT_CMPD_STMT, 1, // non-terminal @@ -1218,6 +1388,275 @@ void test_immcgen_if_else_stmt_chain(void) { delete_vector(expected); } +void test_immcgen_switch_stmt_int(void) { + Srt* input = new_srt( + SRT_SWITCH_STMT, 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_srt( + SRT_CMPD_STMT, 6, // non-terminal + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 0)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 1))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 1)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 2))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_DEFAULT_STMT, 1, // non-terminal + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 9))))), + new_srt(SRT_BREAK_STMT, 0))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_immc); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // dst + new_mem_immcope(4), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JEQ, // inst + new_label_immcope(new_string(".L1")), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 0))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JEQ, // inst + new_label_immcope(new_string(".L2")), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 1))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L3")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L1"))); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // dst + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 1), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(8), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L0")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L2"))); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 2), // dst + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 2), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(8), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 2), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L0")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L3"))); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 3), // dst + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 9), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(8), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 3), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L0")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L0"))); + + run_stmt_immcgen_test(input, local_table, -1, expected); + + delete_vector(expected); +} + +void test_immcgen_switch_stmt_various_integer(void) { + Srt* input = new_srt( + SRT_SWITCH_STMT, 2, // non-terminal + new_dtyped_srt(SRT_CAST_EXPR, new_integer_dtype(DTYPE_INT), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_CHAR), new_string("x"))), + new_srt( + SRT_CMPD_STMT, 8, // non-terminal + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_LONG), new_signed_iliteral(INTEGER_LONG, 0L)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 1))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_DEFAULT_STMT, 1, // non-terminal + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 9))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_LONGLONG), new_signed_iliteral(INTEGER_LONGLONG, 1LL)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 2))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 2)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 3))))), + new_srt(SRT_BREAK_STMT, 0))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_CHAR)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_immc); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_BYTE, 0), // dst + new_mem_immcope(4), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // dst + new_signed_reg_immcope(IMMC_SUFFIX_BYTE, 0), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JEQ, // inst + new_label_immcope(new_string(".L1")), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_QUAD, INTEGER_LONG, 0L))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JEQ, // inst + new_label_immcope(new_string(".L3")), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_QUAD, INTEGER_LONGLONG, 1LL))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JEQ, // inst + new_label_immcope(new_string(".L4")), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 2))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L2")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L1"))); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 2), // dst + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 1), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(8), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 2), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L0")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L2"))); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 3), // dst + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 9), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(8), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 3), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L0")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L3"))); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 4), // dst + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 2), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(8), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 4), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L0")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L4"))); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 5), // dst + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 3), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(8), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 5), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L0")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L0"))); + + run_stmt_immcgen_test(input, local_table, -1, expected); + + delete_vector(expected); +} + void test_immcgen_while_stmt(void) { Srt* input = new_srt( SRT_WHILE_STMT, 2, // non-terminal diff --git a/tests/lexer/test_lexer.c b/tests/lexer/test_lexer.c index fab7d4c8..cf5be3ea 100644 --- a/tests/lexer/test_lexer.c +++ b/tests/lexer/test_lexer.c @@ -13,6 +13,7 @@ void test_read_declaration_long_long_with_init(void); void test_read_declaration_pointer_with_init(void); void test_read_declaration_aggregate_with_init(void); void test_read_if_else_statement(void); +void test_read_switch_case_statement(void); void test_read_while_statement(void); void test_read_for_statement(void); void test_read_continue_stmt(void); @@ -52,6 +53,7 @@ CU_Suite* add_test_suite_lexer(void) { CU_ADD_TEST(suite, test_read_declaration_pointer_with_init); CU_ADD_TEST(suite, test_read_declaration_aggregate_with_init); CU_ADD_TEST(suite, test_read_if_else_statement); + CU_ADD_TEST(suite, test_read_switch_case_statement); CU_ADD_TEST(suite, test_read_while_statement); CU_ADD_TEST(suite, test_read_for_statement); CU_ADD_TEST(suite, test_read_continue_stmt); @@ -395,6 +397,49 @@ void test_read_if_else_statement(void) { delete_vector(expected); } +void test_read_switch_case_statement(void) { + char* input = "switch (x) { case 0: y = 1; break; case 1: y = 2; break; default: y = 3; break; }"; + + Vector* expected = new_vector(&t_ctoken); + vector_push(expected, new_ctoken(CTOKEN_KEYWORD_SWITCH)); + vector_push(expected, new_ctoken(CTOKEN_LPAREN)); + vector_push(expected, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(expected, new_ctoken(CTOKEN_RPAREN)); + vector_push(expected, new_ctoken(CTOKEN_LBRACE)); + vector_push(expected, new_ctoken(CTOKEN_KEYWORD_CASE)); + vector_push(expected, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0))); + vector_push(expected, new_ctoken(CTOKEN_COLON)); + vector_push(expected, new_identifier_ctoken(CTOKEN_IDENT, new_string("y"))); + vector_push(expected, new_ctoken(CTOKEN_EQUAL)); + vector_push(expected, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 1))); + vector_push(expected, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(expected, new_ctoken(CTOKEN_KEYWORD_BREAK)); + vector_push(expected, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(expected, new_ctoken(CTOKEN_KEYWORD_CASE)); + vector_push(expected, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 1))); + vector_push(expected, new_ctoken(CTOKEN_COLON)); + vector_push(expected, new_identifier_ctoken(CTOKEN_IDENT, new_string("y"))); + vector_push(expected, new_ctoken(CTOKEN_EQUAL)); + vector_push(expected, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 2))); + vector_push(expected, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(expected, new_ctoken(CTOKEN_KEYWORD_BREAK)); + vector_push(expected, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(expected, new_ctoken(CTOKEN_KEYWORD_DEFAULT)); + vector_push(expected, new_ctoken(CTOKEN_COLON)); + vector_push(expected, new_identifier_ctoken(CTOKEN_IDENT, new_string("y"))); + vector_push(expected, new_ctoken(CTOKEN_EQUAL)); + vector_push(expected, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 3))); + vector_push(expected, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(expected, new_ctoken(CTOKEN_KEYWORD_BREAK)); + vector_push(expected, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(expected, new_ctoken(CTOKEN_RBRACE)); + vector_push(expected, new_ctoken(CTOKEN_EOF)); + + run_lexer_test(input, expected); + + delete_vector(expected); +} + void test_read_while_statement(void) { char* input = "while (x < 10) { x = x + 1; y = 2 * y; }"; diff --git a/tests/parser/test_statement.c b/tests/parser/test_statement.c index c249de8a..9d939a83 100644 --- a/tests/parser/test_statement.c +++ b/tests/parser/test_statement.c @@ -3,6 +3,8 @@ #include "../../src/parser/statement.h" #include "../testlib/testlib.h" +void test_parse_case_stmt(void); +void test_parse_default_stmt(void); void test_parse_compound_stmt_complete_typedef(void); void test_parse_compound_stmt_incomplete_typedef(void); void test_parse_compound_stmt_int(void); @@ -22,6 +24,7 @@ void test_parse_null_stmt(void); void test_parse_if_stmt(void); void test_parse_if_else_stmt(void); void test_parse_if_else_stmt_chain(void); +void test_parse_switch_stmt(void); void test_parse_while_stmt(void); void test_parse_for_stmt_init_declaration(void); void test_parse_for_stmt_init_expression(void); @@ -34,6 +37,8 @@ void run_stmt_parser_test(Vector* input, Ast* expected); CU_Suite* add_test_suite_stmt_parser(void) { CU_Suite* suite = CU_add_suite("test_suite_stmt_parser", NULL, NULL); + CU_ADD_TEST(suite, test_parse_case_stmt); + CU_ADD_TEST(suite, test_parse_default_stmt); CU_ADD_TEST(suite, test_parse_compound_stmt_complete_typedef); CU_ADD_TEST(suite, test_parse_compound_stmt_incomplete_typedef); CU_ADD_TEST(suite, test_parse_compound_stmt_int); @@ -53,6 +58,7 @@ CU_Suite* add_test_suite_stmt_parser(void) { CU_ADD_TEST(suite, test_parse_if_stmt); 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_switch_stmt); 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); @@ -63,6 +69,38 @@ CU_Suite* add_test_suite_stmt_parser(void) { return suite; } +void test_parse_case_stmt(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_CASE)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 1))); + vector_push(input, new_ctoken(CTOKEN_COLON)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Ast* expected = + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)), new_ast(AST_NULL_STMT, 0)); + + run_stmt_parser_test(input, expected); + + delete_ast(expected); +} + +void test_parse_default_stmt(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_DEFAULT)); + vector_push(input, new_ctoken(CTOKEN_COLON)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Ast* expected = new_ast(AST_DEFAULT_STMT, 1, // non-terminal + new_ast(AST_NULL_STMT, 0)); + + run_stmt_parser_test(input, expected); + + delete_ast(expected); +} + void test_parse_compound_stmt_complete_typedef(void) { Vector* input = new_vector(&t_ctoken); vector_push(input, new_ctoken(CTOKEN_LBRACE)); @@ -1031,6 +1069,72 @@ void test_parse_if_else_stmt_chain(void) { delete_ast(expected); } +void test_parse_switch_stmt(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_SWITCH)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_CASE)); + 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_identifier_ctoken(CTOKEN_IDENT, new_string("y"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_CHAR, new_signed_iliteral(INTEGER_INT, '+'))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_BREAK)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_CASE)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 1))); + vector_push(input, new_ctoken(CTOKEN_COLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("y"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_CHAR, new_signed_iliteral(INTEGER_INT, '-'))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_BREAK)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_DEFAULT)); + vector_push(input, new_ctoken(CTOKEN_COLON)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("y"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_CHAR, new_signed_iliteral(INTEGER_INT, '*'))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_BREAK)); + 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_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CMPD_STMT, 6, // non-terminal + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 0)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_CHAR_EXPR, new_signed_iliteral(INTEGER_INT, '+'))))), + new_ast(AST_BREAK_STMT, 0), + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_CHAR_EXPR, new_signed_iliteral(INTEGER_INT, '-'))))), + new_ast(AST_BREAK_STMT, 0), + new_ast(AST_DEFAULT_STMT, 1, // 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("y")), + new_iliteral_ast(AST_CHAR_EXPR, new_signed_iliteral(INTEGER_INT, '*'))))), + new_ast(AST_BREAK_STMT, 0))); + + run_stmt_parser_test(input, expected); + + delete_ast(expected); +} + void test_parse_while_stmt(void) { Vector* input = new_vector(&t_ctoken); vector_push(input, new_ctoken(CTOKEN_KEYWORD_WHILE)); diff --git a/tests/parser/test_statement_error.c b/tests/parser/test_statement_error.c index 41274c4c..a8ad5a06 100644 --- a/tests/parser/test_statement_error.c +++ b/tests/parser/test_statement_error.c @@ -3,17 +3,27 @@ #include "../../src/parser/statement.h" #include "../testlib/testlib.h" +void test_parse_case_stmt_error_expr(void); +void test_parse_case_stmt_error_colon(void); +void test_parse_case_stmt_error_statement(void); +void test_parse_default_stmt_error_colon(void); +void test_parse_default_stmt_error_statement(void); void test_parse_compound_stmt_error_child(void); void test_parse_compound_stmt_error_braces(void); void test_parse_continue_stmt_error(void); void test_parse_break_stmt_error(void); -void test_parse_return_stmt_error(void); +void test_parse_return_stmt_error_semicolon(void); +void test_parse_return_stmt_error_expr(void); void test_parse_expression_stmt_error(void); void test_parse_if_else_stmt_error_controlling_lparen(void); void test_parse_if_else_stmt_error_controlling_expr(void); void test_parse_if_else_stmt_error_controlling_rparen(void); void test_parse_if_else_stmt_error_then_stmt(void); void test_parse_if_else_stmt_error_else_stmt(void); +void test_parse_switch_stmt_error_controlling_lparen(void); +void test_parse_switch_stmt_error_controlling_expr(void); +void test_parse_switch_stmt_error_controlling_rparen(void); +void test_parse_switch_stmt_error_body(void); 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); @@ -32,17 +42,27 @@ void run_stmt_parser_error_test(Vector* input, Error* expected); CU_Suite* add_test_suite_stmt_parser_error(void) { CU_Suite* suite = CU_add_suite("test_suite_stmt_parser_error", NULL, NULL); + CU_ADD_TEST(suite, test_parse_case_stmt_error_expr); + CU_ADD_TEST(suite, test_parse_case_stmt_error_colon); + CU_ADD_TEST(suite, test_parse_case_stmt_error_statement); + CU_ADD_TEST(suite, test_parse_default_stmt_error_colon); + CU_ADD_TEST(suite, test_parse_default_stmt_error_statement); CU_ADD_TEST(suite, test_parse_compound_stmt_error_child); CU_ADD_TEST(suite, test_parse_compound_stmt_error_braces); CU_ADD_TEST(suite, test_parse_continue_stmt_error); CU_ADD_TEST(suite, test_parse_break_stmt_error); - CU_ADD_TEST(suite, test_parse_return_stmt_error); + CU_ADD_TEST(suite, test_parse_return_stmt_error_expr); + CU_ADD_TEST(suite, test_parse_return_stmt_error_semicolon); CU_ADD_TEST(suite, test_parse_expression_stmt_error); CU_ADD_TEST(suite, test_parse_if_else_stmt_error_controlling_lparen); CU_ADD_TEST(suite, test_parse_if_else_stmt_error_controlling_expr); CU_ADD_TEST(suite, test_parse_if_else_stmt_error_controlling_rparen); CU_ADD_TEST(suite, test_parse_if_else_stmt_error_then_stmt); CU_ADD_TEST(suite, test_parse_if_else_stmt_error_else_stmt); + CU_ADD_TEST(suite, test_parse_switch_stmt_error_controlling_lparen); + CU_ADD_TEST(suite, test_parse_switch_stmt_error_controlling_expr); + CU_ADD_TEST(suite, test_parse_switch_stmt_error_controlling_rparen); + CU_ADD_TEST(suite, test_parse_switch_stmt_error_body); CU_ADD_TEST(suite, test_parse_while_stmt_error_controlling_lparen); CU_ADD_TEST(suite, test_parse_while_stmt_error_controlling_expr); CU_ADD_TEST(suite, test_parse_while_stmt_error_controlling_rparen); @@ -59,6 +79,75 @@ CU_Suite* add_test_suite_stmt_parser_error(void) { return suite; } +void test_parse_case_stmt_error_expr(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_CASE)); + vector_push(input, new_ctoken(CTOKEN_COLON)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_BREAK)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + 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_case_stmt_error_colon(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_CASE)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 1))); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + 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_case_stmt_error_statement(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_CASE)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 1))); + vector_push(input, new_ctoken(CTOKEN_COLON)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("unexpected token EOF"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_default_stmt_error_colon(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_DEFAULT)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + 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_default_stmt_error_statement(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_DEFAULT)); + vector_push(input, new_ctoken(CTOKEN_COLON)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("unexpected token EOF"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + void test_parse_compound_stmt_error_child(void) { Vector* input = new_vector(&t_ctoken); vector_push(input, new_ctoken(CTOKEN_LBRACE)); @@ -98,7 +187,22 @@ void test_parse_compound_stmt_error_braces(void) { delete_error(expected); } -void test_parse_return_stmt_error(void) { +void test_parse_return_stmt_error_expr(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_RETURN)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_SEMICOLON)); + 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_return_stmt_error_semicolon(void) { Vector* input = new_vector(&t_ctoken); vector_push(input, new_ctoken(CTOKEN_KEYWORD_RETURN)); vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("ret"))); @@ -247,6 +351,80 @@ void test_parse_if_else_stmt_error_else_stmt(void) { delete_error(expected); } +void test_parse_switch_stmt_error_controlling_lparen(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_SWITCH)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_CASE)); + 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_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_switch_stmt_error_controlling_expr(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_SWITCH)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_CASE)); + 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_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_switch_stmt_error_controlling_rparen(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_SWITCH)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_CASE)); + 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_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_switch_stmt_error_body(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_SWITCH)); + vector_push(input, new_ctoken(CTOKEN_LPAREN)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("unexpected token EOF"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + void test_parse_while_stmt_error_controlling_lparen(void) { Vector* input = new_vector(&t_ctoken); vector_push(input, new_ctoken(CTOKEN_KEYWORD_WHILE)); diff --git a/tests/resolver/test_declaration_error.c b/tests/resolver/test_declaration_error.c index 8745648d..99cbbba1 100644 --- a/tests/resolver/test_declaration_error.c +++ b/tests/resolver/test_declaration_error.c @@ -11,7 +11,7 @@ void test_resolve_declarator_error_incomplete(void); void test_resolve_array_error_functions(void); void test_resolve_array_error_incomplete(void); void test_resolve_array_error_size_non_positive(void); -void test_resolve_array_error_size_limit(void); +void test_resolve_array_error_size_limitation(void); void test_resolve_struct_error_duplicated(void); void test_resolve_struct_member_error_duplicated(void); void test_resolve_struct_member_error_invalid(void); @@ -55,7 +55,7 @@ CU_Suite* add_test_suite_decl_resolver_error(void) { CU_ADD_TEST(suite, test_resolve_array_error_functions); CU_ADD_TEST(suite, test_resolve_array_error_incomplete); CU_ADD_TEST(suite, test_resolve_array_error_size_non_positive); - CU_ADD_TEST(suite, test_resolve_array_error_size_limit); + CU_ADD_TEST(suite, test_resolve_array_error_size_limitation); CU_ADD_TEST(suite, test_resolve_struct_error_duplicated); CU_ADD_TEST(suite, test_resolve_struct_member_error_duplicated); CU_ADD_TEST(suite, test_resolve_struct_member_error_invalid); @@ -235,7 +235,7 @@ void test_resolve_array_error_size_non_positive(void) { delete_vector(expected); } -void test_resolve_array_error_size_limit(void) { +void test_resolve_array_error_size_limitation(void) { Ast* local_input = new_ast( AST_DECL, 2, // non-terminal new_ast(AST_DECL_SPECS, 1, // non-terminal @@ -250,7 +250,7 @@ void test_resolve_array_error_size_limit(void) { Ast* global_input = ast_copy(local_input); Vector* expected = new_vector(&t_error); - vector_push(expected, new_error("only integer constant is supported as array size")); + vector_push(expected, new_error("only signed integer constant is supported as array size")); run_local_decl_resolver_error_test(local_input, NULL, NULL, expected); run_global_decl_resolver_error_test(global_input, NULL, NULL, expected); diff --git a/tests/resolver/test_statement.c b/tests/resolver/test_statement.c index 00328d35..c38ff97f 100644 --- a/tests/resolver/test_statement.c +++ b/tests/resolver/test_statement.c @@ -2,6 +2,8 @@ #include "../../src/resolver/statement.h" #include "../testlib/testlib.h" +void test_resolve_case_stmt(void); +void test_resolve_default_stmt(void); void test_resolve_compound_stmt_completed_typedef(void); void test_resolve_compound_stmt_incompleted_typedef(void); void test_resolve_compound_stmt_int(void); @@ -28,6 +30,9 @@ void test_resolve_null_stmt(void); void test_resolve_if_stmt(void); void test_resolve_if_else_stmt(void); void test_resolve_if_else_stmt_chain(void); +void test_resolve_switch_stmt_int_iliteral(void); +void test_resolve_switch_stmt_various_iliteral(void); +void test_resolve_switch_stmt_enum(void); void test_resolve_while_stmt(void); void test_resolve_for_stmt_init_declaration(void); void test_resolve_for_stmt_init_expression(void); @@ -40,6 +45,8 @@ void run_stmt_resolver_test(Ast* input, SymbolTable* local_table, DType* return_ CU_Suite* add_test_suite_stmt_resolver(void) { CU_Suite* suite = CU_add_suite("test_suite_stmt_resolver", NULL, NULL); + CU_ADD_TEST(suite, test_resolve_case_stmt); + CU_ADD_TEST(suite, test_resolve_default_stmt); CU_ADD_TEST(suite, test_resolve_compound_stmt_completed_typedef); CU_ADD_TEST(suite, test_resolve_compound_stmt_incompleted_typedef); CU_ADD_TEST(suite, test_resolve_compound_stmt_int); @@ -66,6 +73,9 @@ CU_Suite* add_test_suite_stmt_resolver(void) { CU_ADD_TEST(suite, test_resolve_if_stmt); CU_ADD_TEST(suite, test_resolve_if_else_stmt); CU_ADD_TEST(suite, test_resolve_if_else_stmt_chain); + CU_ADD_TEST(suite, test_resolve_switch_stmt_int_iliteral); + CU_ADD_TEST(suite, test_resolve_switch_stmt_various_iliteral); + CU_ADD_TEST(suite, test_resolve_switch_stmt_enum); CU_ADD_TEST(suite, test_resolve_while_stmt); CU_ADD_TEST(suite, test_resolve_for_stmt_init_declaration); CU_ADD_TEST(suite, test_resolve_for_stmt_init_expression); @@ -76,6 +86,70 @@ CU_Suite* add_test_suite_stmt_resolver(void) { return suite; } +void test_resolve_case_stmt(void) { + Ast* input = + new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 0)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Srt* expected = new_srt( + SRT_SWITCH_STMT, 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 0)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 1)))))); + + run_stmt_resolver_test(input, local_table, NULL, expected); + + delete_srt(expected); +} + +void test_resolve_default_stmt(void) { + Ast* input = + new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_DEFAULT_STMT, 1, // 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("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 9)))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Srt* expected = new_srt( + SRT_SWITCH_STMT, 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_srt(SRT_DEFAULT_STMT, 1, // non-terminal + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 9)))))); + + run_stmt_resolver_test(input, local_table, NULL, expected); + + delete_srt(expected); +} + void test_resolve_compound_stmt_completed_typedef(void) { Ast* input = new_ast(AST_CMPD_STMT, 3, // non-terminal @@ -1189,6 +1263,244 @@ void test_resolve_if_else_stmt_chain(void) { delete_srt(expected); } +void test_resolve_switch_stmt_int_iliteral(void) { + Ast* input = + new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CMPD_STMT, 6, + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 0)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1))))), + new_ast(AST_BREAK_STMT, 0), + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 2))))), + new_ast(AST_BREAK_STMT, 0), + new_ast(AST_DEFAULT_STMT, 1, // 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("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 9))))), + new_ast(AST_BREAK_STMT, 0))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Srt* expected = new_srt( + SRT_SWITCH_STMT, 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_srt( + SRT_CMPD_STMT, 6, // non-terminal + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 0)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 1))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 1)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 2))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_DEFAULT_STMT, 1, // non-terminal + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 9))))), + new_srt(SRT_BREAK_STMT, 0))); + + run_stmt_resolver_test(input, local_table, NULL, expected); + + delete_srt(expected); +} + +void test_resolve_switch_stmt_various_iliteral(void) { + Ast* input = + new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CMPD_STMT, 8, + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_LONG, 0L)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1))))), + new_ast(AST_BREAK_STMT, 0), + new_ast(AST_DEFAULT_STMT, 1, // 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("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 9))))), + new_ast(AST_BREAK_STMT, 0), + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_LONGLONG, 1LL)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 2))))), + new_ast(AST_BREAK_STMT, 0), + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 2)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 3))))), + new_ast(AST_BREAK_STMT, 0))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_CHAR)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Srt* expected = new_srt( + SRT_SWITCH_STMT, 2, // non-terminal + new_dtyped_srt(SRT_CAST_EXPR, new_integer_dtype(DTYPE_INT), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_CHAR), new_string("x"))), + new_srt( + SRT_CMPD_STMT, 8, // non-terminal + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_LONG), new_signed_iliteral(INTEGER_LONG, 0L)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 1))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_DEFAULT_STMT, 1, // non-terminal + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 9))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_LONGLONG), new_signed_iliteral(INTEGER_LONGLONG, 1LL)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 2))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 2)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 3))))), + new_srt(SRT_BREAK_STMT, 0))); + + run_stmt_resolver_test(input, local_table, NULL, expected); + + delete_srt(expected); +} + +void test_resolve_switch_stmt_enum(void) { + Ast* input = + new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CMPD_STMT, 6, + new_ast(AST_CASE_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("A")), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1))))), + new_ast(AST_BREAK_STMT, 0), + new_ast(AST_CASE_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("B")), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 2))))), + new_ast(AST_BREAK_STMT, 0), + new_ast(AST_DEFAULT_STMT, 1, // 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("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 9))))), + new_ast(AST_BREAK_STMT, 0))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + IntegerLiteral* iliteral = NULL; + iliteral = new_signed_iliteral(INTEGER_INT, 0); + symboltable_define_integer(local_table, new_string("A"), new_integer_dtype(DTYPE_INT), iliteral); + iliteral = new_signed_iliteral(INTEGER_INT, 1); + symboltable_define_integer(local_table, new_string("B"), new_integer_dtype(DTYPE_INT), iliteral); + iliteral = new_signed_iliteral(INTEGER_INT, 2); + symboltable_define_integer(local_table, new_string("C"), new_integer_dtype(DTYPE_INT), iliteral); + iliteral = new_signed_iliteral(INTEGER_INT, 3); + symboltable_define_integer(local_table, new_string("D"), new_integer_dtype(DTYPE_INT), iliteral); + + Srt* expected = new_srt( + SRT_SWITCH_STMT, 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_srt( + SRT_CMPD_STMT, 6, // non-terminal + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 0)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 1))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_CASE_STMT, 2, // non-terminal + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 1)), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 2))))), + new_srt(SRT_BREAK_STMT, 0), + new_srt(SRT_DEFAULT_STMT, 1, // non-terminal + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt( + SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("y"))), + new_iliteral_srt(new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 9))))), + new_srt(SRT_BREAK_STMT, 0))); + + run_stmt_resolver_test(input, local_table, NULL, expected); + + delete_srt(expected); +} + void test_resolve_while_stmt(void) { Ast* input = new_ast(AST_WHILE_STMT, 2, // non-terminal diff --git a/tests/resolver/test_statement_error.c b/tests/resolver/test_statement_error.c index 78eab8fe..38a48ed0 100644 --- a/tests/resolver/test_statement_error.c +++ b/tests/resolver/test_statement_error.c @@ -2,6 +2,14 @@ #include "../testlib/testlib.h" #include "./test_external_error.h" +void test_resolve_case_stmt_error_outside_switch(void); +void test_resolve_case_stmt_error_label(void); +void test_resolve_case_stmt_error_limitation(void); +void test_resolve_case_stmt_error_duplicated(void); +void test_resolve_case_stmt_error_child(void); +void test_resolve_default_stmt_error_outside_switch(void); +void test_resolve_default_stmt_error_duplicated(void); +void test_resolve_default_stmt_error_child(void); void test_resolve_compound_stmt_error_child(void); void test_resolve_continue_stmt_error(void); void test_resolve_break_stmt_error(void); @@ -14,6 +22,9 @@ void test_resolve_if_else_stmt_error_condition_child(void); void test_resolve_if_else_stmt_error_condition_non_scalar(void); void test_resolve_if_else_stmt_error_then_child(void); void test_resolve_if_else_stmt_error_else_child(void); +void test_resolve_switch_stmt_error_condition_child(void); +void test_resolve_switch_stmt_error_condition_non_integer(void); +void test_resolve_switch_stmt_error_body_child(void); void test_resolve_while_stmt_error_condition_child(void); void test_resolve_while_stmt_error_condition_non_scalar(void); void test_resolve_while_stmt_error_body_child(void); @@ -30,6 +41,14 @@ void run_stmt_resolver_error_test(Ast* input, SymbolTable* local_table, DType* r CU_Suite* add_test_suite_stmt_resolver_error(void) { CU_Suite* suite = CU_add_suite("test_suite_stmt_resolver_error", NULL, NULL); + CU_ADD_TEST(suite, test_resolve_case_stmt_error_outside_switch); + CU_ADD_TEST(suite, test_resolve_case_stmt_error_label); + CU_ADD_TEST(suite, test_resolve_case_stmt_error_limitation); + CU_ADD_TEST(suite, test_resolve_case_stmt_error_duplicated); + CU_ADD_TEST(suite, test_resolve_case_stmt_error_child); + CU_ADD_TEST(suite, test_resolve_default_stmt_error_outside_switch); + CU_ADD_TEST(suite, test_resolve_default_stmt_error_duplicated); + CU_ADD_TEST(suite, test_resolve_default_stmt_error_child); CU_ADD_TEST(suite, test_resolve_compound_stmt_error_child); CU_ADD_TEST(suite, test_resolve_continue_stmt_error); CU_ADD_TEST(suite, test_resolve_break_stmt_error); @@ -42,6 +61,9 @@ CU_Suite* add_test_suite_stmt_resolver_error(void) { CU_ADD_TEST(suite, test_resolve_if_else_stmt_error_condition_non_scalar); CU_ADD_TEST(suite, test_resolve_if_else_stmt_error_then_child); CU_ADD_TEST(suite, test_resolve_if_else_stmt_error_else_child); + CU_ADD_TEST(suite, test_resolve_switch_stmt_error_condition_child); + CU_ADD_TEST(suite, test_resolve_switch_stmt_error_condition_non_integer); + CU_ADD_TEST(suite, test_resolve_switch_stmt_error_body_child); CU_ADD_TEST(suite, test_resolve_while_stmt_error_condition_child); CU_ADD_TEST(suite, test_resolve_while_stmt_error_condition_non_scalar); CU_ADD_TEST(suite, test_resolve_while_stmt_error_body_child); @@ -56,6 +78,206 @@ CU_Suite* add_test_suite_stmt_resolver_error(void) { return suite; } +void test_resolve_case_stmt_error_outside_switch(void) { + Ast* input = new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_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, 1))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("case statement is not allowed outside of switch")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_case_stmt_error_label(void) { + Ast* input = + new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CASE_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("UNKNOWN")), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("identifier 'UNKNOWN' is used before declared")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_case_stmt_error_limitation(void) { + Ast* input = + new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CASE_STMT, 2, // non-terminal + new_ast(AST_ADD_EXPR, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 2))), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("only signed integer constant is supported as case label")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_case_stmt_error_duplicated(void) { + Ast* input = new_ast( + AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CMPD_STMT, 3, // non-terminal + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1))))), + new_ast(AST_DEFAULT_STMT, 1, // 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("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 9))))), + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 2))))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("value of case label is already used in switch")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_case_stmt_error_child(void) { + Ast* input = new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CMPD_STMT, 1, // non-terminal + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_PREINC_EXPR, 1, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y"))))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("identifier 'y' is used before declared")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_default_stmt_error_outside_switch(void) { + Ast* input = + new_ast(AST_CMPD_STMT, 2, + new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_DEFAULT_STMT, 1, // 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("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)))))), + new_ast(AST_DEFAULT_STMT, 1, // 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("z")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 9)))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("z"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("default statement is not allowed outside of switch")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_default_stmt_error_duplicated(void) { + Ast* input = new_ast( + AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CMPD_STMT, 2, // non-terminal + new_ast(AST_DEFAULT_STMT, 1, // 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("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 9))))), + new_ast(AST_DEFAULT_STMT, 1, // 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("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 10))))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("default statement is already used in switch")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_default_stmt_error_child(void) { + Ast* input = new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CMPD_STMT, 1, // non-terminal + new_ast(AST_DEFAULT_STMT, 1, // non-terminal + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_POSTDEC_EXPR, 1, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y"))))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("identifier 'y' is used before declared")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + void test_resolve_compound_stmt_error_child(void) { Ast* input = new_ast(AST_CMPD_STMT, 4, // non-terminal new_ast(AST_DECL, 2, // non-terminal @@ -304,6 +526,79 @@ void test_resolve_if_else_stmt_error_else_child(void) { delete_vector(expected); } +void test_resolve_switch_stmt_error_condition_child(void) { + Ast* input = + new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CMPD_STMT, 2, // non-terminal + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1))))), + new_ast(AST_BREAK_STMT, 0))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("identifier 'x' is used before declared")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_switch_stmt_error_condition_non_integer(void) { + Ast* input = + new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CMPD_STMT, 2, // non-terminal + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1))))), + new_ast(AST_BREAK_STMT, 0))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_pointer_dtype(new_integer_dtype(DTYPE_INT))); + symboltable_define_memory(local_table, new_string("y"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("condition of switch statement should have integer type")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_switch_stmt_error_body_child(void) { + Ast* input = + new_ast(AST_SWITCH_STMT, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x")), + new_ast(AST_CMPD_STMT, 2, // non-terminal + new_ast(AST_CASE_STMT, 2, // non-terminal + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1)), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_ast(AST_ASSIGN_EXPR, 2, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("y")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 1))))), + new_ast(AST_BREAK_STMT, 0))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("identifier 'y' is used before declared")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + void test_resolve_while_stmt_error_condition_child(void) { Ast* input = new_ast(AST_WHILE_STMT, 2, // non-terminal