} END_TEST START_TEST(test_typecheck_valid_custom_sum_type_constructor) { static const struct RFstring s = RF_STRING_STATIC_INIT( "type person { name:string | id:u32 }" "fn do_something()\n" "{\n" "a:person = person(\"Celina\")\n" "b:person = person(13)\n" "}\n" ); front_testdriver_new_ast_main_source(&s); ck_assert_typecheck_ok(); struct ast_node *fn_impl = ast_node_get_child(front_testdriver_root(), 1); ck_assert(fn_impl->type == AST_FUNCTION_IMPLEMENTATION); struct ast_node *block = ast_fnimpl_body_get(fn_impl); struct ast_node *bop1 = ast_node_get_child(block, 0); struct ast_node *bop2 = ast_node_get_child(block, 1); ck_assert(ast_node_is_specific_binaryop(bop1, BINARYOP_ASSIGN)); ck_assert(ast_node_is_specific_binaryop(bop2, BINARYOP_ASSIGN)); struct ast_node *ctor1 = ast_binaryop_right(bop1); struct ast_node *ctor2 = ast_binaryop_right(bop2); ck_assert(ctor1->type = AST_FUNCTION_CALL); ck_assert(ctor2->type = AST_FUNCTION_CALL); struct type *t_string = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_STRING); struct type *t_u32 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_UINT_32); ck_assert(type_compare(ctor1->fncall.params_type, t_string, TYPECMP_IDENTICAL)); ck_assert(type_compare(ctor2->fncall.params_type, t_u32, TYPECMP_IDENTICAL)); } END_TEST
} END_TEST START_TEST(test_array_type4) { static const struct RFstring s = RF_STRING_STATIC_INIT( "{\n" "a:u64[] = [1, 2, 3]\n" "}" ); front_testdriver_new_ast_main_source(&s); ck_assert_typecheck_ok(); int64_t dims[] = {3}; struct type *t_u64 = testsupport_analyzer_type_create_elemarray( ELEMENTARY_TYPE_UINT_64, dims ); struct ast_node *block = ast_node_get_child(front_testdriver_module()->node, 0); struct ast_node *blist = ast_binaryop_right(ast_node_get_child(block, 0)); const struct type *blist_type = ast_node_get_type(blist); ck_assert_msg(blist_type, "bracket type should not be NULL"); ck_assert_msg( type_compare(blist_type, t_u64, TYPECMP_GENERIC), "Bracket type comparison failure" ); struct ast_node *vardecl = ast_binaryop_left(ast_node_get_child(block, 0)); const struct type *vardecl_type = ast_node_get_type(vardecl); ck_assert_msg(vardecl_type, "bracket type should not be NULL"); ck_assert_msg( type_compare(vardecl_type, t_u64, TYPECMP_IDENTICAL), "Bracket type comparison failure" ); } END_TEST
} END_TEST START_TEST (test_type_comparison_for_sum_fncall) { // test for a bug concerning subtypes of sum types // make type a:i64 | b:u64 | c:f64 | d:string // just like the typechecking for function calls // check that comparing a subtype gives the correct matched type struct type *t_i64 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_INT_64); struct type *t_u64 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_UINT_64); struct type *t_f64 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_FLOAT_64); struct type *t_string = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_STRING); struct type *t_sum = testsupport_analyzer_type_create_operator(TYPEOP_SUM, t_i64, t_u64, t_f64, t_string); typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL); ck_assert(type_compare(t_u64, t_sum, TYPECMP_PATTERN_MATCHING)); const struct type *matched_type = typemp_ctx_get_matched_type(); ck_assert_msg( matched_type == t_u64, "Unexpected match type "RFS_PF" found", RFS_PA(type_str_or_die(matched_type, TSTR_DEFAULT)) ); typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL); ck_assert(type_compare(t_i64, t_sum, TYPECMP_PATTERN_MATCHING)); matched_type = typemp_ctx_get_matched_type(); ck_assert_msg( matched_type == t_i64, "Unexpected match type "RFS_PF" found", RFS_PA(type_str_or_die(matched_type, TSTR_DEFAULT)) ); typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL); ck_assert(type_compare(t_f64, t_sum, TYPECMP_PATTERN_MATCHING)); matched_type = typemp_ctx_get_matched_type(); ck_assert_msg( matched_type == t_f64, "Unexpected match type "RFS_PF" found", RFS_PA(type_str_or_die(matched_type, TSTR_DEFAULT)) ); typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL); ck_assert(type_compare(t_string, t_sum, TYPECMP_PATTERN_MATCHING)); matched_type = typemp_ctx_get_matched_type(); ck_assert_msg( matched_type == t_string, "Unexpected match type "RFS_PF" found", RFS_PA(type_str_or_die(matched_type, TSTR_DEFAULT)) ); } END_TEST
//compare the two parameters int param_list_compare(struct param_list *a, struct param_list *b){ if(!a && !b) return 1; if(!a || !b) return 0; if(a->name && b->name) return (strcmp(a->name, b->name) == 0 && type_compare(a->type, b->type) /*&& symbol_compare(a->symbol, b->symbol)*/ && param_list_compare(a->next, b->next)); else if(!a->name && !b->name) return (type_compare(a->type, b->type) /*&& symbol_compare(a->symbol, b->symbol)*/ && param_list_compare(a->next, b->next)); else return 0; }
void expr_typecheck_array(struct type *array_type, struct expr *e_list) { if (!e_list) return; struct type *t; if (e_list->kind == EXPR_LIST) t = expr_typecheck(e_list->left); else if (e_list->kind == EXPR_LIST_OUTER) t = expr_typecheck(e_list->right); if (!type_compare(t, array_type)) { printf("type error: line %d: ", e_list->line); printf("expression type "); type_print(t); printf(" ("); expr_print(e_list->right); printf(")"); printf(" found in assignment to array of type "); type_print(array_type); printf("\n"); error_count++; } expr_typecheck_array(array_type, e_list->right); }
} END_TEST START_TEST(test_determine_block_type2) { struct ast_node *block; static const struct RFstring s = RF_STRING_STATIC_INIT( "type foo {a:i8, b:string}\n" "{\n" "a:foo\n" "}" ); front_testdriver_new_ast_main_source(&s); ck_assert_typecheck_ok(); struct type *t_i8 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_INT_8); struct type *t_string = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_STRING); struct type *t_prod_1 = testsupport_analyzer_type_create_operator(TYPEOP_PRODUCT, t_i8, t_string); static const struct RFstring id_foo = RF_STRING_STATIC_INIT("foo"); struct type *t_foo = testsupport_analyzer_type_create_defined(&id_foo, t_prod_1); block = ast_node_get_child(front_testdriver_module()->node, 1); ck_assert_msg(block, "Block should be the second child of the root"); const struct type *block_type = ast_node_get_type(block); ck_assert_msg(block_type, "Block should have a type"); ck_assert_msg(type_compare(block_type, t_foo, TYPECMP_IDENTICAL), "Expected the block's type to be an f64"); } END_TEST
void decl_typecheck( struct decl *d ) { if (!d) return; if (d->value) { struct type *T = expr_typecheck( d-> value ); if (!type_compare(d->type, T)) { printf("type error: cannot initialize variable (%s) of type ", d->name); type_print(d->type); printf(" and assign it a "); type_print( T ); printf("\n"); } } if (d->type->kind == TYPE_ARRAY) { // for array decl_array_typecheck(d->type, d->name); } else if (d->type->kind == TYPE_FUNCTION) { // for function return decl_array_typecheck(d->type->subtype, d->name); } if (d->code) { decl_func_sym = scope_lookup(d->name); stmt_typecheck(d->code); } if (d->next) decl_typecheck(d->next); }
static bool test_traversal_cb( const struct RFstring *name, const struct ast_node *desc, struct type *t, struct test_traversal_cb_ctx *ctx) { ck_assert_msg( rf_string_equal(&ctx->names[ctx->idx], name), "Ast type traversal index %u expected name "RF_STR_PF_FMT" but got " RF_STR_PF_FMT".", ctx->idx, RF_STR_PF_ARG(&ctx->names[ctx->idx]), RF_STR_PF_ARG(name) ); ck_assert_msg( type_compare(ctx->types[ctx->idx], t, TYPECMP_IDENTICAL), "Ast type traversal index %u expected type "RF_STR_PF_FMT" but got " RF_STR_PF_FMT".", ctx->idx, RF_STR_PF_ARG(type_str(ctx->types[ctx->idx], TSTR_DEFAULT)), RF_STR_PF_ARG(type_str(t, TSTR_DEFAULT)) ); ++ctx->idx; return true; }
int type_compare(const glsl_type *a, const glsl_type *b) { /* If the types are the same, they trivially match. */ if (a == b) return 0; switch (a->base_type) { case GLSL_TYPE_UINT: case GLSL_TYPE_INT: case GLSL_TYPE_BOOL: /* There is no implicit conversion to or from integer types or bool. */ if ((a->is_integer() != b->is_integer()) || (a->is_boolean() != b->is_boolean())) return -1; /* FALLTHROUGH */ case GLSL_TYPE_FLOAT: if ((a->vector_elements != b->vector_elements) || (a->matrix_columns != b->matrix_columns)) return -1; return 1; case GLSL_TYPE_SAMPLER: case GLSL_TYPE_STRUCT: /* Samplers and structures must match exactly. */ return -1; case GLSL_TYPE_ARRAY: if ((b->base_type != GLSL_TYPE_ARRAY) || (a->length != b->length)) return -1; /* From GLSL 1.50 spec, page 27 (page 33 of the PDF): * "There are no implicit array or structure conversions." * * If the comparison of the array element types detects that a conversion * would be required, the array types do not match. */ return (type_compare(a->fields.array, b->fields.array) == 0) ? 0 : -1; case GLSL_TYPE_VOID: case GLSL_TYPE_ERROR: default: /* These are all error conditions. It is invalid for a parameter to * a function to be declared as error, void, or a function. */ return -1; } /* This point should be unreachable. */ assert(0); }
int symbol_compare(struct symbol * a, struct symbol * b) { if (!a && !b) { return 1; } else if ((!a || !b)) { return 0; } else { if (!(a->name) && !(b->name)) { return (a->kind==b->kind) && (a->which==b->which) && type_compare(a->type, b->type) && (a->code==b->code); } else if (!(a->name) || !(b->name)) { return 0; } else { return (a->kind==b->kind) && (a->which==b->which) && type_compare(a->type, b->type) && !strcmp(a->name, b->name) && (a->code==b->code); } } }
int compareWithNoCase2(const char_type* str1, const char_type* str2) { char_type *str1_2 = new char_type[type_length(str1)]; char_type *str2_2 = new char_type[type_length(str2)]; type_copy(str1_2, str1); type_copy(str2_2, str2); toupper(*str1_2); toupper(*str2_2); int result = type_compare(str1_2, str2_2); delete[] str1_2; delete[] str2_2; return result; }
int type_compare(struct type *a, struct type *b) { if(!a && !b) return 1; if(!a || !b) return 0; if(a->kind != b->kind) return 0; if(a->kind == TYPE_FUNCTION) { if(!type_compare(a->subtype,b->subtype)) return 0; } //The following may be necessary but I'm not sure /*if(a->params != b->params) return 0;*/ return 1; }
} END_TEST START_TEST (test_type_comparison_for_sum_fncall_with_conversion) { struct type *t_i8 = testsupport_analyzer_type_create_elementary(ELEMENTARY_TYPE_INT_8, false); struct type *t_i64 = testsupport_analyzer_type_create_elementary(ELEMENTARY_TYPE_INT_64, false); struct type *t_f64 = testsupport_analyzer_type_create_elementary(ELEMENTARY_TYPE_FLOAT_64, false); struct type *t_string = testsupport_analyzer_type_create_elementary(ELEMENTARY_TYPE_STRING, false); struct type *t_sum = testsupport_analyzer_type_create_operator(TYPEOP_SUM, t_i64, t_f64, t_string); typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL); ck_assert(type_compare(t_i8, t_sum, TYPECMP_PATTERN_MATCHING)); const struct type *matched_type = typemp_ctx_get_matched_type(); ck_assert_msg(matched_type == t_i64, "Unexpected match type "RF_STR_PF_FMT" found", RF_STR_PF_ARG(type_str_or_die(matched_type, TSTR_DEFAULT))); } END_TEST
} END_TEST START_TEST(test_determine_block_type1) { struct ast_node *block; static const struct RFstring s = RF_STRING_STATIC_INIT( "{\n" "d:f64 = 3.14 * 0.14\n" "}" ); front_testdriver_new_ast_main_source(&s); ck_assert_typecheck_ok(); struct type *t_f64 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_FLOAT_64); block = ast_node_get_child(front_testdriver_module()->node, 0); ck_assert_msg(block, "Block should be the first child of the root"); const struct type *block_type = ast_node_get_type(block); ck_assert_msg(block_type, "Block should have a type"); ck_assert_msg(type_compare(block_type, t_f64, TYPECMP_IDENTICAL), "Expected the block's type to be an f64"); } END_TEST
void param_list_typecheck( struct expr * e, struct param_list *params, char *func_name) { while (e && params) { struct type *T = expr_typecheck(e); if (!type_compare(T, params->type)) { decl_has_error = 1; printf("type error: cannot pass variable of type "); type_print(T); printf(" to function %s\n", func_name); } e = e->next; params = params->next; } if (e) { decl_has_error = 1; printf("type error: pass more variables to functions call %s than needed\n", func_name); } if (params) { decl_has_error = 1; printf("type error: not enough variables to function call %s\n", func_name); } }
} END_TEST START_TEST(test_array_type3) { static const struct RFstring s = RF_STRING_STATIC_INIT( "a:u64[42][13][24]\n" ); front_testdriver_new_ast_main_source(&s); ck_assert_typecheck_ok(); int64_t dims[] = {42, 13, 24}; struct type *t_u64 = testsupport_analyzer_type_create_elemarray( ELEMENTARY_TYPE_UINT_64, dims ); struct ast_node *typedesc = ast_node_get_child(front_testdriver_module()->node, 0); const struct type *n_type = ast_node_get_type(typedesc); ck_assert_msg(n_type, "Type should not be NULL"); ck_assert_msg( type_compare(n_type, t_u64, TYPECMP_IDENTICAL), "Node type comparison failure" ); } END_TEST
//checks if a function call matches up to the function types void function_typecheck(const char *function_name, struct expr *e, struct param_list *p, int param, int func_params) { if(!e && !p) return; //only for no parameters if(!e) { printf("type error: In call to function %s, expected %d parameters, but received %d\n", function_name, param, func_params); error_count++; return; } if(!p) { struct expr *e1; if(e->kind == EXPR_COMMA) e1 = e->left; else e1 = e; struct type *t = expr_typecheck(e1); printf("type error: In call to function %s, expected %d parameters, but received %d\n", function_name, param, func_params); error_count++; return; } int last_expr = 0, last_param = 0; if(e->kind != EXPR_COMMA) last_expr = 1; if(!p->next) last_param = 1; struct type *t = expr_typecheck(e->left); if(e->kind == EXPR_COMMA){ if(!type_compare(t, p->type)){ printf("type error: In call to function %s, expected parameter %d to be of type ", function_name, param); type_print(p->type); printf(". Instead, expression "); expr_print(e->left); printf(" of type "); type_print(t); printf(" was passed to parameter %d\n", param); error_count++; } } if(last_expr && last_param) return; function_typecheck(function_name, e->right, p->next, ++param, func_params); }
// compare two types int type_compare( struct type *a, struct type *b ){ if(!a && !b) return 1; if(!a || !b) return 0; return (a->kind == b->kind && param_list_compare(a->params, b->params) && type_compare(a->subtype, b->subtype) && expr_compare(a->opt_expr, b->opt_expr)); }
struct type * expr_typecheck( struct expr *e ) { if (!e) return type_create(TYPE_VOID, 0, 0); struct type *L; struct type *R; switch (e->kind) { case EXPR_INT_VAL: return type_create(TYPE_INTEGER, 0, 0); case EXPR_NAME: return type_copy(e->symbol->type); case EXPR_STRING_VAL: return type_create(TYPE_STRING, 0, 0); case EXPR_CHAR_VAL: return type_create(TYPE_CHARACTER, 0, 0); case EXPR_BOOLEAN_VAL: return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_ARRAY_VAL: { struct expr *vals = e->right; struct type *subtype = 0; int num_subtype = 0; while (vals) { struct type *cur_t = expr_typecheck(vals); if (!subtype) { subtype = cur_t; } if (!type_compare(subtype, cur_t)) { decl_has_error = 1; printf("type error: array of element type "); type_print(subtype); printf(" cannot have expression of type "); type_print(cur_t); printf("\n"); } num_subtype++; vals = vals->next; } struct type *t = type_create(TYPE_ARRAY, 0, subtype); t->num_subtype = expr_create_integer_literal(num_subtype); return t; } //return type_copy(e->symbol->type); case EXPR_ARRAY_SUB: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot use "); type_print(R); printf(" as index to an array\n"); } if (L->kind != TYPE_ARRAY) { decl_has_error = 1; printf("type error: access an "); type_print(R); printf(" as an array\n"); } return type_copy(L->subtype); case EXPR_FUNCTION_VAL: // need to check function params!!!!! param_list_typecheck(e->right, e->symbol->params, e->name); return type_copy(e->symbol->type->subtype); case EXPR_ADD: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot add "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_SUB: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if ( !(L->kind == TYPE_INTEGER && L->kind == TYPE_INTEGER) || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot subtract "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_MUL: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot multiply "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_DIV: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot divide "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_MODULO: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot module "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_EXPO: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot expo "); type_print(L); printf(" to a "); type_print(R); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_POST_DECREASE: L = expr_typecheck(e->left); if (L->kind != TYPE_INTEGER ) { decl_has_error = 1; printf("type error: cannot decrease a "); type_print(L); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_POST_INCREASE: L = expr_typecheck(e->left); if (L->kind != TYPE_INTEGER ) { decl_has_error = 1; printf("type error: cannot add a "); type_print(L); printf("\n"); } return type_create(TYPE_INTEGER, 0, 0); case EXPR_GE: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot make greater equal than compare "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_LE: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot make less equal compare "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_GT: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot make greater than compare "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_LT: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) { decl_has_error = 1; printf("type error: cannot make less than compare "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_AND: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN) { decl_has_error = 1; printf("type error: cannot and "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_NOT: R = expr_typecheck(e->right); if (R->kind != TYPE_BOOLEAN) { decl_has_error = 1; printf("type error: cannot not a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_OR: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN) { decl_has_error = 1; printf("type error: cannot or "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_EQ: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind == TYPE_FUNCTION || R->kind == TYPE_FUNCTION || L->kind == TYPE_ARRAY || R->kind == TYPE_ARRAY) { decl_has_error = 1; printf("type error: cannot compare equality "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_NEQ: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind == TYPE_FUNCTION || R->kind == TYPE_FUNCTION || L->kind == TYPE_ARRAY || R->kind == TYPE_ARRAY) { decl_has_error = 1; printf("type error: cannot compare non equality "); type_print(L); printf(" with a "); type_print(R); printf("\n"); } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_ASSIGN: L = expr_typecheck(e->left); R = expr_typecheck(e->right); if (L->kind == TYPE_FUNCTION || R->kind == TYPE_FUNCTION) { decl_has_error = 1; printf("type error: cannot assign "); type_print(R); printf(" to a "); type_print(L); printf("\n"); } if (!type_compare(L, R)) { decl_has_error = 1; printf("type error: cannot assign "); type_print(R); printf(" to a "); type_print(L); printf("\n"); } return type_copy(R); } }
static int F() { // function declaration Tdata_type ftype; switch (token.type) { case TT_INT: case TT_DOUBLE: case TT_STRING: // rule: type idf ( AL ) FD ftype = get_type(); tmp_ftype = ftype; next(); check(TT_ID); try(add_func(ftype, token.p_string)); next(); term(TT_L_BRACKET); call(AL); term(TT_R_BRACKET); return(FD); default: return ERR_PARSER; } } static int AL() { // first function argument switch (token.type) { case TT_INT: case TT_DOUBLE: case TT_STRING: // rule: AL -> AD AL2 call(AD); return(AL2); default: // rule: AL -> eps return OK; } } static int AL2() { // remaining function arguments switch (token.type) { case TT_COMMA: // rule: AL2 -> , AD AL2 next(); call(AD); return(AL2); default: // rule: AL2 -> eps return OK; } } static int AD() { // argument Tdata_type atype; switch (token.type) { case TT_INT: case TT_DOUBLE: case TT_STRING: // rule: AD -> type id atype = get_type(); next(); check(TT_ID); try(add_param(atype, token.p_string)); next(); return OK; default: return ERR_PARSER; } } static int FD() { // function definition unsigned i; switch (token.type) { case TT_SEMICOLON: // rule: FD -> ; try(func_declaration()); next(); return OK; case TT_OPEN_BRACKET: // rule: FD -> { STL } i = get_line(); try(func_definition(i)); // instruction pointer next(); call(STL); term(TT_CLOSE_BRACKET); remove_block(); generate(I_ERR, NULL, NULL, NULL); // no return => runtime error return OK; default: return ERR_PARSER; } } static int STL() { // stat list switch (token.type) { case TT_CLOSE_BRACKET: // rule: STL -> eps return OK; default: // rule: STL -> S STL call(S); return(STL); } } static int S() { // stat unsigned i; Tlocal_sym_tab_node *conv; switch (token.type) { case TT_AUTO: case TT_INT: case TT_DOUBLE: case TT_STRING: // rule: S -> D ; call(D); term(TT_SEMICOLON); return OK; case TT_OPEN_BRACKET: // rule: S -> { STL } next(); try(add_block()); call(STL); term(TT_CLOSE_BRACKET); remove_block(); return OK; case TT_IF: // rule: S -> if ( E ) S else S next(); term(TT_L_BRACKET); call(E); try(type_compare(tmp_psitem.type, TYPE_INT)); if (tmp_psitem.type != TYPE_INT) { try(tmp_var(TYPE_INT, &conv)); generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv); } else { conv = tmp_psitem.value.ptr; } Tlocal_sym_tab_node *label; try(tmp_var(TYPE_INT, &label)); generate(I_JUMPIFN, conv, label, NULL); term(TT_R_BRACKET); call(S); Tlocal_sym_tab_node *endif; try(tmp_var(TYPE_INT, &endif)); generate(I_JUMP, NULL, endif, NULL); i = get_line(); set_var_value_int(label->name, i); call(ELSE); i = get_line(); set_var_value_int(endif->name, i); return OK; case TT_FOR: // rule: S -> for ( D ; E ; E ) S try(add_block()); next(); term(TT_L_BRACKET); call(D); term(TT_SEMICOLON); Tlocal_sym_tab_node *cond; try(tmp_var(TYPE_INT, &cond)); i = get_line(); set_var_value_int(cond->name, i); call(E); try(type_compare(tmp_psitem.type, TYPE_INT)); if (tmp_psitem.type != TYPE_INT) { try(tmp_var(TYPE_INT, &conv)); generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv); } else { conv = tmp_psitem.value.ptr; } Tlocal_sym_tab_node *endfor; try(tmp_var(TYPE_INT, &endfor)); generate(I_JUMPIFN, conv, endfor, NULL); Tlocal_sym_tab_node *statlist; try(tmp_var(TYPE_INT, &statlist)); generate(I_JUMP, NULL, statlist, NULL); Tlocal_sym_tab_node *assign; try(tmp_var(TYPE_INT, &assign)); i = get_line(); set_var_value_int(assign->name, i); term(TT_SEMICOLON); call(E); generate(I_JUMP, NULL, cond, NULL); i = get_line(); set_var_value_int(statlist->name, i); term(TT_R_BRACKET); call(S); generate(I_JUMP, NULL, assign, NULL); i = get_line(); set_var_value_int(endfor->name, i); remove_block(); return OK; case TT_WHILE: // rule: S -> while ( E ) S next(); term(TT_L_BRACKET); Tlocal_sym_tab_node *wcond; try(tmp_var(TYPE_INT, &wcond)); i = get_line(); set_var_value_int(wcond->name, i); call(E); try(type_compare(tmp_psitem.type, TYPE_INT)); if (tmp_psitem.type != TYPE_INT) { try(tmp_var(TYPE_INT, &conv)); generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv); } else { conv = tmp_psitem.value.ptr; } Tlocal_sym_tab_node *endwhile; try(tmp_var(TYPE_INT, &endwhile)); generate(I_JUMPIFN, conv, endwhile, NULL); term (TT_R_BRACKET); call(S); generate(I_JUMP, NULL, wcond, NULL); i = get_line(); set_var_value_int(endwhile->name, i); return OK; case TT_DO: // rule: S -> do S while ( E ) ; next(); Tlocal_sym_tab_node *dwbody; try(tmp_var(TYPE_INT, &dwbody)); i = get_line(); set_var_value_int(dwbody->name, i); call(S); term(TT_WHILE); term(TT_L_BRACKET); call(E); try(type_compare(tmp_psitem.type, TYPE_INT)); if (tmp_psitem.type != TYPE_INT) { try(tmp_var(TYPE_INT, &conv)); generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv); } else { conv = tmp_psitem.value.ptr; } generate(I_JUMPIF, conv, dwbody, NULL); term(TT_R_BRACKET); term(TT_SEMICOLON); return OK; case TT_RETURN: // rule: S -> return E ; next(); call(E); try(type_compare(tmp_ftype, tmp_psitem.type)); if (tmp_psitem.type != tmp_ftype) { try(tmp_var(tmp_ftype, &conv)); generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv); } else { conv = tmp_psitem.value.ptr; } generate(I_RETURN, conv, NULL, NULL); term(TT_SEMICOLON); return OK; case TT_CIN: // rule: S -> cin >> id IN ; next(); term(TT_IN); check(TT_ID); if (!var_exists(token.p_string)) return ERR_UNDEF; Tlocal_sym_tab_node *var = get_var(token.p_string); generate(I_CIN, NULL, NULL, var); next(); call(IN); term(TT_SEMICOLON); return OK; case TT_COUT: // rule: S -> cout << E OUT ; next(); term(TT_OUT); call(E); generate(I_COUT, tmp_psitem.value.ptr, NULL, NULL); call(OUT); term(TT_SEMICOLON); return OK; default: // rule: S -> E ; call(E); term(TT_SEMICOLON); return OK; } } static int D() { // variable declaration Tdata_type vtype; switch (token.type) { case TT_AUTO: case TT_INT: case TT_DOUBLE: case TT_STRING: // rule: D -> type id I vtype = get_type(); tmp_type = vtype; next(); check(TT_ID); try(add_var(vtype, token.p_string)); try(tmpstr(token.p_string)); next(); return(I); default: return ERR_PARSER; } } static int I() { // variable definition switch (token.type) { case TT_ASSIGN: // rule: I -> = E next(); call(E); try(assign_type_compare(tmp_buffer.str, tmp_psitem.type)); Tlocal_sym_tab_node *var = get_var(tmp_buffer.str); Tlocal_sym_tab_node *conv; if (tmp_psitem.type != var->data_type) { try(tmp_var(var->data_type, &conv)); generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv); } else { conv = tmp_psitem.value.ptr; } generate(I_ASSIGN, conv, NULL, var); return OK; default: // rule: I -> eps if (tmp_type == TYPE_AUTO) return ERR_AUTO; return OK; } } static int ELSE() { // else switch (token.type) { case TT_ELSE: // rule: ELSE -> else S next(); return(S); default: // rule: ELSE -> eps return OK; } } static int IN() { // input variables switch (token.type) { case TT_IN: // rule: IN -> >> id IN next(); check(TT_ID); if (!var_exists(token.p_string)) return ERR_UNDEF; Tlocal_sym_tab_node *var = get_var(token.p_string); generate(I_CIN, NULL, NULL, var); next(); return(IN); default: // rule: IN -> eps return OK; } } static int OUT() { // output expressions switch (token.type) { case TT_OUT: // rule: OUT -> << E OUT next(); call(E); generate(I_COUT, tmp_psitem.value.ptr, NULL, NULL); return(OUT); default: // rule: OUT -> eps return OK; } } static int E() { // expression Tpsa_stack *psa_stack = ps_init(); ps_push(psa_stack, OP_END); if (get_prec(OP_END) == ' ') { fprintf(stderr, "Syntax error: 'expression' expected, but '%s' given.\n", token_[token.type]); return ERR_PARSER; } int err; do { Tps_item *ps_item = ps_first_term(psa_stack); switch (get_prec(ps_item->op)) { case '=': err = ps_push_token(psa_stack); if (err != OK) { ps_destroy(psa_stack); return err; } next(); break; case '<': err = ps_ins_after(psa_stack, ps_item, OP_EXPR); if (err != OK) { ps_destroy(psa_stack); return err; } err = ps_push_token(psa_stack); if (err != OK) { ps_destroy(psa_stack); return err; } next(); break; case '>': err = psa(psa_stack); if (err != OK) { ps_destroy(psa_stack); return err; } break; } } while (get_prec(ps_first_term(psa_stack)->op) != ' '); Tps_item *top = ps_top(psa_stack); if (top->op != OP_NTERM || ps_prev(psa_stack)->op != OP_END) { fprintf(stderr, "Syntax error: unexpected '%s'\n", token_[token.type]); return ERR_PARSER; } tmp_psitem.type = top->type; tmp_psitem.value = top->value; ps_destroy(psa_stack); return OK; } int parse() { next(); strInit(&tmp_buffer); int err = P(); strFree(&tmp_buffer); return err; }
enum traversal_cb_res typecheck_function_call( struct ast_node *n, struct analyzer_traversal_ctx *ctx) { const struct RFstring *fn_name; const struct type *fn_type; const struct type *fn_declared_args_type; const struct type *fn_found_args_type; struct ast_node *fn_call_args = ast_fncall_args(n); // check for existence of function fn_name = ast_fncall_name(n); fn_type = type_lookup_identifier_string(fn_name, ctx->current_st); if (!fn_type || !type_is_callable(fn_type)) { analyzer_err(ctx->m, ast_node_startmark(n), ast_node_endmark(n), "Undefined function call \""RFS_PF"\" detected", RFS_PA(fn_name)); goto fail; } // create the arguments ast node array ast_fncall_arguments(n); // also check the ast node of the function declaration to get more // information if it's not a conversion if (!type_is_explicitly_convertable_elementary(fn_type)) { const struct ast_node *fndecl = symbol_table_lookup_node( ctx->current_st, fn_name, NULL ); RF_ASSERT(fndecl, "Since fn_type was found so should fndecl be found here"); if (fndecl->fndecl.position == FNDECL_PARTOF_FOREIGN_IMPORT) { n->fncall.type = AST_FNCALL_FOREIGN; } } fn_found_args_type = (fn_call_args) ? ast_node_get_type(fn_call_args) : type_elementary_get_type(ELEMENTARY_TYPE_NIL); if (!fn_found_args_type) { // argument typechecking failed goto fail; } if (type_is_explicitly_convertable_elementary(fn_type)) { // silly way to check if it's only 1 argument. Maybe figure out safer way? if (!fn_call_args || fn_found_args_type->category == TYPE_CATEGORY_OPERATOR) { analyzer_err( ctx->m, ast_node_startmark(n), ast_node_endmark(n), "Invalid arguments for explicit conversion to \"" RFS_PF"\".", RFS_PA(fn_name) ); goto fail; } // check if the explicit conversion is valid if (!type_compare(fn_found_args_type, fn_type, TYPECMP_EXPLICIT_CONVERSION)) { analyzer_err(ctx->m, ast_node_startmark(n), ast_node_endmark(n), "Invalid explicit conversion. "RFS_PF".", RFS_PA(typecmp_ctx_get_error())); goto fail; } n->fncall.type = AST_FNCALL_EXPLICIT_CONVERSION; } else { //check that the types of its arguments do indeed match fn_declared_args_type = type_callable_get_argtype(fn_type); n->fncall.declared_type = fn_declared_args_type; if (type_is_sumop(fn_declared_args_type)) { n->fncall.type = AST_FNCALL_SUM; } typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL); if (!type_compare( fn_found_args_type, fn_declared_args_type, n->fncall.type == AST_FNCALL_SUM ? TYPECMP_PATTERN_MATCHING : TYPECMP_IMPLICIT_CONVERSION)) { RFS_PUSH(); analyzer_err( ctx->m, ast_node_startmark(n), ast_node_endmark(n), RFS_PF" "RFS_PF"() is called with argument type of \""RFS_PF "\" which does not match the expected " "type of \""RFS_PF"\"%s"RFS_PF".", RFS_PA(type_callable_category_str(fn_type)), RFS_PA(fn_name), RFS_PA(type_str_or_die(fn_found_args_type, TSTR_DEFAULT)), RFS_PA(type_str_or_die(fn_declared_args_type, TSTR_DEFINED_ONLY_CONTENTS)), typecmp_ctx_have_error() ? ". " : "", RFS_PA(typecmp_ctx_get_error()) ); RFS_POP(); goto fail; } // the function call's matched type should be either a specific sum type // that may have matched or the entirety of the called arguments if (!(n->fncall.params_type = typemp_ctx_get_matched_type())) { n->fncall.params_type = fn_found_args_type; } } traversal_node_set_type(n, type_callable_get_rettype(fn_type), ctx); return TRAVERSAL_CB_OK; fail: traversal_node_set_type(n, NULL, ctx); return TRAVERSAL_CB_ERROR; }
struct type * expr_typecheck(struct expr *e) { if (!e) return type_create(TYPE_VOID, 0, 0); struct type *l, *r; switch(e->kind) { case EXPR_INTEGER_LITERAL: return type_create(TYPE_INTEGER, 0, 0); case EXPR_BOOLEAN_LITERAL: return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_CHAR_LITERAL: return type_create(TYPE_CHARACTER, 0, 0); case EXPR_STRING_LITERAL: return type_create(TYPE_STRING, 0, 0); case EXPR_VARIABLE: return type_create(e->symbol->type->kind, 0, 0); case EXPR_FUNCTION_CALL: param_list_typecheck(e->symbol->type->params, e->right, 0); return type_create(e->symbol->type->subtype->kind, 0, 0); case EXPR_ADD: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot add type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" to type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_UNARY: r = expr_typecheck(e->right); if (r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("unary operator (-) cannot be applied to type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_ASSIGN: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind == TYPE_FUNCTION || r->kind == TYPE_FUNCTION) { printf("type error: line %d: ", e->line); printf("= operator not compatible with functions\n"); error_count++; } else if (!(type_compare(l, r))) { printf("type error: line %d: cannot assign type ", e->line); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf(" to type "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf("\n"); error_count++; } return type_create(l->kind, 0, 0); case EXPR_LIST: l = expr_typecheck(e->left); expr_typecheck(e->right); return l; case EXPR_LIST_OUTER: r = expr_typecheck(e->right); return r;; case EXPR_SUB: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot subtract type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" from type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_MUL: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot multiply type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_DIV: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot divide type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" by type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_MOD: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot modulus type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" with type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_POW: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: cannot exponentiate type ", e->line); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" by type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_INCR: r = expr_typecheck(e->right); if (r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("++ operator not compatible with type "); type_print(e->symbol->type); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_DECR: r = expr_typecheck(e->right); if (r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("-- operator not compatible with type "); type_print(e->symbol->type); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0); case EXPR_NOT: r = expr_typecheck(e->right); if (r->kind != TYPE_BOOLEAN) { printf("type error: line %d: ", e->line); printf("! operator requires boolean type boolean type operand (found "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf(" )\n" ); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_LT: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("< operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_LE: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("<= operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_GT: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("> operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_GE: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf(">= operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_EQ: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind == TYPE_ARRAY || l->kind == TYPE_FUNCTION || r->kind == TYPE_ARRAY || r->kind == TYPE_FUNCTION) { printf("type error: line %d: ", e->line); printf("== operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } else if (!type_compare(l, r)) { printf("type error: line %d: ", e->line); printf("cannot use == operator on non-matching types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_NE: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind == TYPE_ARRAY || l->kind == TYPE_FUNCTION || r->kind == TYPE_ARRAY || r->kind == TYPE_FUNCTION) { printf("type error: line %d:", e->line); printf("!= operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } else if (!type_compare(l, r)) { printf("type error: line %d:", e->line); printf("cannot use != operator on non-matching types "); printf(" ("); expr_print(e->left); printf(")"); type_print(l); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_AND: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_BOOLEAN || r->kind != TYPE_BOOLEAN) { printf("type error: line %d: ", e->line); printf("&& operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->right); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_OR: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_BOOLEAN || r->kind != TYPE_BOOLEAN) { printf("type error: line %d: ", e->line); printf("|| operator not compatible with types "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf(" and "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0); case EXPR_ARRAY_MEMBER: l = expr_typecheck(e->left); r = expr_typecheck(e->right); if (l->kind != TYPE_ARRAY && l->kind != TYPE_STRING) { printf("type error: line %d: ", e->line); printf("[] operator cannot follow a variable of type "); type_print(l); printf(" ("); expr_print(e->left); printf(")"); printf("\n"); error_count++; } return type_create(type_array_type(e), 0, 0); case EXPR_INDEX: if (e->left) { l = expr_typecheck(e->left->right); if (l->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("an array index cannot be type "); type_print(l); printf(" ("); expr_print(e->left->right); printf(")"); printf("\n"); error_count++; } expr_typecheck(e->right); } else { r = expr_typecheck(e->right); if (r->kind != TYPE_INTEGER) { printf("type error: line %d: ", e->line); printf("an array index cannot be type "); type_print(r); printf(" ("); expr_print(e->right); printf(")"); printf("\n"); error_count++; } } return type_create(TYPE_INTEGER, 0, 0); default: fprintf(stderr, "cminor: ERROR! Illegal expr type found!\n"); exit(1); } }
void stmt_typecheck(struct stmt *s, struct type *ret, int *returned) { if(!s) return; switch(s -> kind) { struct type *expr; struct expr *curr; case STMT_DECL: decl_typecheck(s -> decl); break; case STMT_EXPR: // need to typecheck, but don't need type type_delete(expr_typecheck(s -> expr)); break; case STMT_IF_ELSE: expr = expr_typecheck(s -> expr); if(expr -> kind != TYPE_BOOLEAN) { fprintf(stderr, "TYPE_ERROR: cannot use a(n) "); type_fprint(stderr, expr); fprintf(stderr, " as the if statement expression (currently "); expr_fprint(stderr, s -> expr); fprintf(stderr, ") requires a boolean\n"); type_error_count++; } stmt_typecheck(s -> body, ret, returned); stmt_typecheck(s -> else_body, ret, returned); type_delete(expr); break; case STMT_FOR: type_delete(expr_typecheck(s -> init_expr)); expr = expr_typecheck(s -> expr); // need to check that the middle // expression is actually there if(expr && expr -> kind != TYPE_BOOLEAN) { fprintf(stderr, "TYPE_ERROR: cannot use a "); type_fprint(stderr, expr); fprintf(stderr, " as the middle expression requires a boolean (or an empty expression)\n"); type_error_count++; } type_delete(expr); type_delete(expr_typecheck(s -> next_expr)); stmt_typecheck(s -> body, ret, returned); break; case STMT_WHILE: break; case STMT_PRINT: curr = s -> expr; while(curr) { expr = expr_typecheck(curr); // pass type through new symbol if(!type_is_atomic(expr)) { fprintf(stderr, "TYPE_ERROR: cannot print (print "); expr_fprint(stderr, s -> expr); fprintf(stderr, ") a non-atomic value ("); type_fprint(stderr, expr); fprintf(stderr, ")\n"); type_error_count++; } switch(expr -> kind) { case TYPE_BOOLEAN: curr -> print_type = 1; break; case TYPE_CHARACTER: curr -> print_type = 2; break; case TYPE_INTEGER: curr -> print_type = 3; break; case TYPE_STRING: curr -> print_type = 4; break; case TYPE_ARRAY: curr -> print_type = 0; fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n"); exit(1); break; case TYPE_ARRAY_DECL: curr -> print_type = 0; fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n"); exit(1); break; case TYPE_FUNCTION: curr -> print_type = 0; fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n"); exit(1); break; case TYPE_VOID: curr -> print_type = 0; fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n"); exit(1); break; } type_delete(expr); curr = curr -> next; } break; case STMT_RET: // always set to 1 *returned = 1; expr = expr_typecheck(s -> expr); if(!s -> expr) { type_delete(expr); expr = type_create(TYPE_VOID, 0, 0, 0); } if(!type_compare(expr, ret)) { fprintf(stderr, "TYPE_ERROR: the return statement (return "); expr_fprint(stderr, s -> expr); fprintf(stderr, ") does not match the function return type ("); type_fprint(stderr, ret); fprintf(stderr, ")\n"); type_error_count++; } type_delete(expr); break; case STMT_BLOCK: stmt_typecheck(s -> body, ret, returned); break; } stmt_typecheck(s -> next, ret, returned); }
static int parameter_lists_match(const exec_list *list_a, const exec_list *list_b) { const exec_node *node_a = list_a->head; const exec_node *node_b = list_b->head; int total_score = 0; for (/* empty */ ; !node_a->is_tail_sentinel() ; node_a = node_a->next, node_b = node_b->next) { /* If all of the parameters from the other parameter list have been * exhausted, the lists have different length and, by definition, * do not match. */ if (node_b->is_tail_sentinel()) return -1; const ir_variable *const param = (ir_variable *) node_a; const ir_instruction *const actual = (ir_instruction *) node_b; /* Determine whether or not the types match. If the types are an * exact match, the match score is zero. If the types don't match * but the actual parameter can be coerced to the type of the declared * parameter, the match score is one. */ int score; switch ((enum ir_variable_mode)(param->mode)) { case ir_var_auto: case ir_var_uniform: case ir_var_temporary: /* These are all error conditions. It is invalid for a parameter to * a function to be declared as auto (not in, out, or inout) or * as uniform. */ assert(0); return -1; case ir_var_in: score = type_compare(param->type, actual->type); break; case ir_var_out: score = type_compare(actual->type, param->type); break; case ir_var_inout: /* Since there are no bi-directional automatic conversions (e.g., * there is int -> float but no float -> int), inout parameters must * be exact matches. */ score = (type_compare(actual->type, param->type) == 0) ? 0 : -1; break; default: assert(false); } if (score < 0) return -1; total_score += score; } /* If all of the parameters from the other parameter list have been * exhausted, the lists have different length and, by definition, do not * match. */ if (!node_b->is_tail_sentinel()) return -1; return total_score; }
struct type * expr_typecheck(struct expr *e) { if(!e) return type_create(TYPE_VOID, 0, 0, 0); struct type *L = expr_typecheck(e->left); struct type *R = expr_typecheck(e->right); switch(e->kind) { case EXPR_ASSIGNMENT: if(L->kind == TYPE_FUNCTION){ printf("type error: cannot use assignment operator on function "); expr_print(e->left); error_count++; } if(R->kind == TYPE_FUNCTION){ printf("type error: cannot use assignment operator on function "); expr_print(e->right); error_count++; } if(!type_compare(L, R)){ printf("type error: cannot assign "); type_print(R); printf(" "); expr_print(e->right); printf(" to "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } return L; break; case EXPR_GE: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot use operator >= to compare "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf(". This operator can only be used on two integers.\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_LE: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot use operator <= to compare "); type_print(L); expr_print(e->left); printf(" and "); type_print(R); expr_print(e->right); printf(". This operator can only be used on two integers.\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_GT: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot use operator > to compare "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf(". This operator can only be used on two integers.\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_LT: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot use operator < to compare "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf(". This operator can only be used on two integers.\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_EQ: if(L->kind == TYPE_ARRAY){ printf("type error: cannot use operator == on array "); expr_print(e->left); printf("\n"); error_count++; } else if(L->kind == TYPE_FUNCTION){ printf("type error: cannot use operator == on function "); expr_print(e->left); printf("\n"); error_count++; } if(R->kind == TYPE_ARRAY){ printf("type error: cannot use operator == on array "); expr_print(e->right); printf("\n"); error_count++; } else if(R->kind == TYPE_FUNCTION){ printf("type error: cannot use operator == on function "); expr_print(e->right); printf("\n"); error_count++; } if(L->kind != R->kind){ printf("type error: cannot use operator == to compare "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_NE: if(L->kind == TYPE_ARRAY){ printf("type error: cannot use operator != on array "); expr_print(e->left); printf("\n"); error_count++; } else if(L->kind == TYPE_FUNCTION){ printf("type error: cannot use operator != on function "); expr_print(e->left); printf("\n"); error_count++; } if(R->kind == TYPE_ARRAY){ printf("type error: cannot use operator != on array "); expr_print(e->right); printf("\n"); error_count++; } else if(R->kind == TYPE_FUNCTION){ printf("type error: cannot use operator != on function "); expr_print(e->right); printf("\n"); error_count++; } if(L->kind != R->kind){ printf("type error: cannot use operator != to compare "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_ADD: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot add "); type_print(L); printf(" "); expr_print(e->left); printf(" to "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_SUB: if((L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) && L->kind != TYPE_VOID){ printf("type error: cannot subtract "); type_print(R); printf(" "); expr_print(e->right); printf(" from "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_MUL: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot multiply "); type_print(L); printf(" "); expr_print(e->left); printf(" with "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_DIV: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot divide "); type_print(R); printf(" "); expr_print(e->right); printf(" from "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_MOD: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot perform modular division "); type_print(L); printf(" "); expr_print(e->left); printf(" mod "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_POW: if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){ printf("type error: cannot exponentiate "); type_print(L); printf(" "); expr_print(e->left); printf(" ^ "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_POSTFIX_PLUS: if(L->kind != TYPE_INTEGER){ printf("type error: cannot increment "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } if(e->left->kind != EXPR_IDENT) { printf("type error: cannot increment non-variable "); expr_print(e->left); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_POSTFIX_MINUS: if(L->kind != TYPE_INTEGER){ printf("type error: cannot decrement "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } if(e->left->kind != EXPR_IDENT) { printf("type error: cannot decrement non-variable "); expr_print(e->left); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_LOGICAL_NOT: if(R->kind != TYPE_BOOLEAN){ printf("type error: cannot negate non-boolean "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_LOGICAL_AND: if(L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN){ printf("type error: cannot use && to compare non-boolean "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_LOGICAL_OR: if(L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN){ printf("type error: cannot use && to compare non-boolean "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf("\n"); error_count++; } return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_INTEGER_LITERAL: return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_STRING_LITERAL: return type_create(TYPE_STRING, 0, 0, 0); break; case EXPR_CHAR_LITERAL: return type_create(TYPE_CHARACTER, 0, 0, 0); break; case EXPR_TRUE: return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_FALSE: return type_create(TYPE_BOOLEAN, 0, 0, 0); break; case EXPR_IDENT: return e->symbol->type; break; case EXPR_FCALL: if(L->kind != TYPE_FUNCTION) { printf("type error: cannot execute function call to non-function "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } function_typecheck(e->left->name, e->right, e->left->symbol->type->params, 1, function_params(e)+1); return L->subtype; break; case EXPR_ARRCALL: if(L->kind != TYPE_ARRAY) { printf("type error: cannot index into non-array "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } //return the number of subtypes that the index requires int i; struct type *T = L; for(i = 0; i < array_call_subtypes(e->right); i++){ T = T->subtype; } return T; break; case EXPR_ARRINDEX: if(L->kind != TYPE_INTEGER){ printf("type error: cannot index an array using non-integer "); type_print(L); printf(" "); expr_print(e->left); printf("\n"); error_count++; } return type_create(TYPE_INTEGER, 0, 0, 0); break; case EXPR_PARENS: return R; break; case EXPR_BLOCK: return type_create(TYPE_ARRAY, 0, R, exprs_in_block(e)-1); break; case EXPR_BLOCK_COMMA: if(L->kind != R->kind && R->kind != TYPE_VOID){ printf("type error: cannot have "); type_print(L); printf(" "); expr_print(e->left); printf(" and "); type_print(R); printf(" "); expr_print(e->right); printf(" in the same expression list\n"); error_count++; return type_create(TYPE_VOID,0,0,0); } return L; break; case EXPR_COMMA: return R; break; } }