} END_TEST START_TEST (test_string_buffer_fillfmt) { unsigned int size; RFS_PUSH(); char *buff1; char *buff2; ck_assert(test_rf_strings_buffer_fillfmt( "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz%d%s", &size, &buff1, 42, "ABCD")); ck_assert_uint_eq(size, 58); ck_assert_nnt_str_eq_cstr( buff1, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz42ABCD"); RFS_PUSH(); ck_assert(test_rf_strings_buffer_fillfmt( "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ%s", &size, &buff2, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz")); ck_assert_uint_eq(size, 104); ck_assert_nnt_str_eq_cstr( buff2, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); RFS_POP(); RFS_POP(); } END_TEST
} END_TEST START_TEST (test_RFS_realloc_vararg_at_second_use) { struct RFstring *s1; struct RFstring *s2; RFS_PUSH(); s1 = RFS("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz%d%d", 23, 24); ck_assert_rf_str_eq_cstr(s1, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz2324"); RFS_PUSH(); s2 = RFS("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ%s%d", "eleos", 124); ck_assert_rf_str_eq_cstr(s1, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz2324"); ck_assert_rf_str_eq_cstr(s2, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZeleos124"); RFS_POP(); RFS_POP(); } END_TEST
} END_TEST START_TEST (test_type_to_str) { struct type *t_u32 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_UINT_32); 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_prod_1 = testsupport_analyzer_type_create_operator(TYPEOP_PRODUCT, t_u32, t_f64); struct type *t_sum_1 = testsupport_analyzer_type_create_operator(TYPEOP_SUM, t_f64, t_string); static const struct RFstring id_person = RF_STRING_STATIC_INIT("person"); struct type *t_defined_1 = testsupport_analyzer_type_create_defined(&id_person, t_sum_1); struct RFstring *ts; RFS_PUSH(); ck_assert((ts = type_str(t_u32, TSTR_DEFAULT))); ck_assert_rf_str_eq_cstr(ts, "u32"); ck_assert((ts = type_str(t_prod_1, TSTR_DEFAULT))); ck_assert_rf_str_eq_cstr(ts, "u32,f64"); ck_assert((ts = type_str(t_defined_1, TSTR_DEFAULT))); ck_assert_rf_str_eq_cstr(ts, "person"); RFS_POP(); } END_TEST
static void test_RFS_in_recursive_functions() { RFS_PUSH(); struct RFstring *s1; s1 = get_str_rec(NULL, 0, true); ck_assert_rf_str_eq_cstr( s1, "0abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); RFS_POP(); RFS_PUSH(); struct RFstring *s2; s2 = get_str_rec(NULL, 1, true); ck_assert_rf_str_eq_cstr( s2, "1abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "0abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); RFS_POP(); }
} END_TEST START_TEST (test_type_op_create_str) { struct type *t_u32 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_UINT_32); struct type *t_f64 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_FLOAT_64); RFS_PUSH(); ck_assert_rf_str_eq_cstr(type_op_create_str(t_u32, t_f64, TYPEOP_PRODUCT), "u32,f64"); ck_assert_rf_str_eq_cstr(type_op_create_str(t_u32, t_f64, TYPEOP_SUM), "u32|f64"); ck_assert_rf_str_eq_cstr(type_op_create_str(t_u32, t_f64, TYPEOP_IMPLICATION), "u32->f64"); RFS_POP(); } END_TEST
static void test_RFS_in_recursive_functions_with_local() { RFS_PUSH(); struct RFstring *s1; s1 = get_str_rec_with_local(NULL, 0); ck_assert_rf_str_eq_cstr( s1, "pre0abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); RFS_POP(); RFS_PUSH(); struct RFstring *s2; s2 = get_str_rec_with_local(NULL, 1); ck_assert_rf_str_eq_cstr( s2, "pre0abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "pre1abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" ); RFS_POP(); RFS_PUSH(); struct RFstring *s3; s3 = get_str_rec_with_local(NULL, 2); ck_assert_rf_str_eq_cstr( s3, "pre0abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "pre1abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "pre2abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" ); RFS_POP(); RFS_PUSH(); struct RFstring *s4; s4 = get_str_rec_with_local(NULL, 3); ck_assert_rf_str_eq_cstr( s4, "pre0abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "pre1abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "pre2abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "pre3abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" ); RFS_POP(); }
} END_TEST START_TEST (test_RFS_same_ptr) { struct RFstring *s1; RFS_PUSH(); s1 = RFS("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); ck_assert_rf_str_eq_cstr(s1, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); s1 = RFS(RFS_PF "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ", RFS_PA(s1)); ck_assert_rf_str_eq_cstr(s1, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"); RFS_POP(); } END_TEST
} END_TEST START_TEST (test_RFS_realloc_at_first_use) { struct RFstring *s1; struct RFstring *s2; RFS_PUSH(); s1 = RFS( "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); ck_assert_rf_str_eq_cstr( s1, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); RFS_PUSH(); s2 = RFS("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"); ck_assert_rf_str_eq_cstr( s1, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); ck_assert_rf_str_eq_cstr(s2, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"); RFS_POP(); RFS_POP(); } END_TEST
bool rir_binaryop_tostring(struct rirtostr_ctx *ctx, const struct rir_expression *e) { bool ret = false; RFS_PUSH(); const struct RFstring *memtype_s = rir_type_string(e->binaryop.a->type); if (e->val.category == RIR_VALUE_NIL) { if (!rf_stringx_append( ctx->rir->buff, RFS(RIRTOSTR_INDENT RF_STR_PF_FMT"(" RF_STR_PF_FMT ", "RF_STR_PF_FMT ", " RF_STR_PF_FMT ")\n", RF_STR_PF_ARG(&rir_bop_type_strings[e->type]), RF_STR_PF_ARG(memtype_s), RF_STR_PF_ARG(rir_value_string(e->binaryop.a)), RF_STR_PF_ARG(rir_value_string(e->binaryop.b))) )) { goto end; } } else { if (!rf_stringx_append( ctx->rir->buff, RFS(RIRTOSTR_INDENT RF_STR_PF_FMT" = "RF_STR_PF_FMT"(" RF_STR_PF_FMT ", "RF_STR_PF_FMT ", " RF_STR_PF_FMT ")\n", RF_STR_PF_ARG(rir_value_string(&e->val)), RF_STR_PF_ARG(&rir_bop_type_strings[e->type]), RF_STR_PF_ARG(memtype_s), RF_STR_PF_ARG(rir_value_string(e->binaryop.a)), RF_STR_PF_ARG(rir_value_string(e->binaryop.b))) )) { goto end; } } ret = true; end: RFS_POP(); return ret; }
static struct rir_object *rir_convert_init(const struct rir_value *convval, const struct rir_type *totype, struct rir_ctx *ctx) { struct rir_object *retobj = NULL; // at the moment only conversion to string requires special work if (!rir_type_is_specific_elementary(totype, ELEMENTARY_TYPE_STRING)) { if ((!(retobj = rir_object_create(RIR_OBJ_EXPRESSION, ctx->rir)))) { return NULL; } retobj->expr.convert.val = convval; retobj->expr.convert.type = totype; retobj->expr.type = RIR_EXPRESSION_PLACEHOLDER; // to signify we must continue return retobj; } // from here and down it's only about conversion to string if (convval->category == RIR_VALUE_CONSTANT) { // constant value to string conversion can be done easily here at compile time RFS_PUSH(); const struct RFstring *temps = rir_constant_string(convval); if (!(retobj = rir_global_addorget_string(ctx, temps))) { RF_ERROR("Failed to add or get a global string literal to the RIR"); } RFS_POP(); return retobj; } else if (rir_type_is_specific_elementary(convval->type, ELEMENTARY_TYPE_BOOL)) { struct rir_object *obj; // boolean to string conversion requires some branching logic retobj = rir_alloca_create_obj( rir_type_elem_create(ELEMENTARY_TYPE_STRING, false), 0, ctx ); if (!retobj) { return NULL; } rirctx_block_add(ctx, &retobj->expr); struct rir_value *allocv = rir_object_value(retobj); // create the blocks struct rir_block *prev_block = ctx->current_block; struct rir_block *taken_block = rir_block_create(NULL, false, ctx); if (!taken_block) { return NULL; } struct rir_block *fallthrough_block = rir_block_create(NULL, false, ctx); if (!fallthrough_block) { return NULL; } struct rir_block *after_block = rir_block_create(NULL, false, ctx); if (!after_block) { return NULL; } // create the conditional branch to connect to if/else if (!rir_block_exit_init_condbranch( &prev_block->exit, convval, &taken_block->label, &fallthrough_block->label )) { return NULL; } // populate taken block ctx->current_block = taken_block; if (!(obj = rir_global_addorget_string(ctx, &g_str_true))) { RF_ERROR("Failed to add a global string literal to the RIR"); return NULL; } struct rir_expression *e = rir_write_create(allocv, rir_object_value(obj), ctx); if (!e) { return NULL; } rirctx_block_add(ctx, e); if (!rir_block_exit_init_branch(&taken_block->exit, &after_block->label)) { return NULL; } rir_fndef_add_block(ctx->current_fn, taken_block); // populate fallthrough block ctx->current_block = fallthrough_block; if (!(obj = rir_global_addorget_string(ctx, &g_str_false))) { RF_ERROR("Failed to add a global string literal to the RIR"); return NULL; } if (!(e = rir_write_create(allocv, rir_object_value(obj), ctx))) { return NULL; } rirctx_block_add(ctx, e); if (!rir_block_exit_init_branch(&fallthrough_block->exit, &after_block->label)) { return NULL; } rir_fndef_add_block(ctx->current_fn, fallthrough_block); // finally let's go to the after block and return the populated alloca which // should hold the value of the conversion rir_fndef_add_block(ctx->current_fn, after_block); ctx->current_block = after_block; return retobj; } else { RF_CRITICAL_FAIL("Unexpected conversion at RIR formation"); return NULL; } }
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; }