static bool rir_process_memberaccess(const struct ast_binaryop *op, struct rir_ctx *ctx) { if (op->left->type != AST_IDENTIFIER) { RF_ERROR("Left part of a member access was not an identifier"); goto fail; } if (!rir_process_identifier(op->left, ctx)) { goto fail; } const struct rir_value *lhs_val = rir_ctx_lastval_get(ctx); const struct RFstring *rightstr = ast_identifier_str(op->right); const struct type *owner_type = ast_node_get_type_or_die(op->left); struct rir_typedef *def = rir_typedef_frommap(ctx->rir, type_defined_get_name(owner_type)); if (!def) { RF_ERROR("Could not find rir typedef for a member access type"); goto fail; } // find the index of the right part of member access const struct ast_node *ast_desc = symbol_table_lookup_node( rir_ctx_curr_st(ctx), ast_identifier_str(op->left), NULL ); if (!ast_desc) { RF_ERROR("Could not find ast type description for left part of member access"); goto fail; } struct rir_member_access_ctx cbctx; rir_member_access_ctx_init(&cbctx, rightstr); ast_type_foreach_arg( ast_desc, (struct type*)ast_node_get_type_or_die(ast_desc), (ast_type_cb)rir_member_access_cb, &cbctx ); if (cbctx.found_idx == -1) { RF_ERROR("Could not find argument in typedef"); goto fail; } // create a rir expression to read the object value at the assignee's index position struct rir_object *member_ptr_obj = rir_objmemberat_create_obj(lhs_val, cbctx.found_idx, ctx); if (!member_ptr_obj) { goto fail; } rirctx_block_add(ctx, &member_ptr_obj->expr); member_ptr_obj = rir_getread_obj(member_ptr_obj, ctx); if (!member_ptr_obj) { goto fail; } // return the memberobjat to be used by other rir expressions RIRCTX_RETURN_EXPR(ctx, true, member_ptr_obj); fail: RIRCTX_RETURN_EXPR(ctx, false, NULL); }
bool rir_process_binaryop(const struct ast_binaryop *op, struct rir_ctx *ctx) { struct rir_object *obj = NULL; // special treatment for member access if (op->type == BINARYOP_MEMBER_ACCESS) { return rir_process_memberaccess(op, ctx); } const struct rir_value *lval = rir_process_ast_node_getval(op->left, ctx); if (!lval) { RF_ERROR("A left value should have been created for a binary operation"); goto fail; } if (op->type == BINARYOP_ASSIGN) { // set the last assigned to object ctx->last_assign_obj = ctx->returned_obj; } struct rir_value *rval = rir_process_ast_node_getval(op->right, ctx); if (!rval) { goto fail; } if (op->type == BINARYOP_ASSIGN) { // assignment is a special case if (op->right->type == AST_MATCH_EXPRESSION || (op->right->type == AST_FUNCTION_CALL && (ast_fncall_is_ctor(op->right) || !ast_fncall_is_conversion(op->right) ))) { // assignment from match expression, constructor calll need no more processing RIRCTX_RETURN_EXPR(ctx, true, NULL); } // else, create a rir_write if (!(obj = rir_write_create_obj(lval, rval, ctx))) { goto fail; } } else { // normal binary operator processing if (!(obj = rir_binaryop_create_obj(op, lval, rval, ctx))) { RF_ERROR("Failed to create a rir binary operation"); goto fail; } } rirctx_block_add(ctx, &obj->expr); ctx->last_assign_obj = NULL; RIRCTX_RETURN_EXPR(ctx, true, obj); fail: ctx->last_assign_obj = NULL; RIRCTX_RETURN_EXPR(ctx, false, NULL); }
static bool analyzer_populate_symbol_module(struct analyzer_traversal_ctx *ctx, struct ast_node *n) { const struct ast_node *search_node; bool symbol_found_at_first_st; const struct RFstring *name = ast_module_name(n); search_node = symbol_table_lookup_node(ctx->current_st, name, &symbol_found_at_first_st); if (search_node && symbol_found_at_first_st) { analyzer_err(ctx->m, ast_node_startmark(n), ast_node_endmark(n), "Identifier \""RF_STR_PF_FMT"\" was already used in scope " "at "INPLOCATION_FMT, RF_STR_PF_ARG(name), INPLOCATION_ARG(module_get_file(ctx->m), ast_node_location(search_node))); return false; } if (!symbol_table_add_node(ctx->current_st, ctx->m, name, n)) { RF_ERROR("Could not add a module to a symbol table"); return false; } return true; }
static bool analyzer_populate_symbol_table_typedecl(struct analyzer_traversal_ctx *ctx, struct ast_node *n) { const struct ast_node *search_node; bool symbol_found_at_first_st; const struct RFstring *type_name; AST_NODE_ASSERT_TYPE(n, AST_TYPE_DECLARATION); type_name = ast_typedecl_name_str(n); search_node = symbol_table_lookup_node(ctx->current_st, type_name, &symbol_found_at_first_st); if (search_node && symbol_found_at_first_st) { analyzer_err(ctx->m, ast_node_startmark(n), ast_node_endmark(n), "Type \""RF_STR_PF_FMT"\" was already declared in scope " "at "INPLOCATION_FMT, RF_STR_PF_ARG(type_name), INPLOCATION_ARG(module_get_file(ctx->m), ast_node_location(search_node))); return false; } if (!symbol_table_add_node(ctx->current_st, ctx->m, type_name, n)) { if (!module_have_errors(ctx->m)) { RF_ERROR("Could not add a typedecl node to a symbol table"); } return false; } return true; }
static bool analyzer_populate_symbol_table_typeleaf(struct analyzer_traversal_ctx *ctx, struct ast_node *n) { const struct ast_node *search_node; bool symbol_found_at_first_st; const struct RFstring *id_name; struct ast_node *left; AST_NODE_ASSERT_TYPE(n, AST_TYPE_LEAF); left = ast_typeleaf_left(n); id_name = ast_identifier_str(left); search_node = symbol_table_lookup_node(ctx->current_st, id_name, &symbol_found_at_first_st); if (search_node && symbol_found_at_first_st) { analyzer_err(ctx->m, ast_node_startmark(n), ast_node_endmark(n), "Identifier \""RF_STR_PF_FMT"\" was already used in scope " "at "INPLOCATION_FMT, RF_STR_PF_ARG(id_name), INPLOCATION_ARG(module_get_file(ctx->m), ast_node_location(search_node))); return false; } if (!symbol_table_add_node(ctx->current_st, ctx->m, id_name, n)) { RF_ERROR("Could not add a type leaf's node to a symbol table"); return false; } return true; }
static bool analyzer_symbol_table_add_fndecl(struct analyzer_traversal_ctx *ctx, struct ast_node *n) { struct symbol_table_record *rec; const struct RFstring *fn_name; fn_name = ast_fndecl_name_str(n); rec = symbol_table_lookup_record(ctx->current_st, fn_name, NULL); if (rec && type_is_function(rec->data)) { analyzer_err(ctx->m, ast_node_startmark(n), ast_node_endmark(n), "Function \""RF_STR_PF_FMT"\" was already declared " "at "INPLOCATION_FMT, RF_STR_PF_ARG(fn_name), INPLOCATION_ARG( module_get_file(ctx->m), ast_node_location(symbol_table_record_node(rec)))); return false; } if (!symbol_table_add_node(ctx->current_st, ctx->m, fn_name, n)) { RF_ERROR("Could not add a function node to a symbol table"); return false; } // function's arguments are added to the symbol table by type creation return true; }
static struct ast_node *ast_parser_acc_return_statement(struct ast_parser *p) { struct token *tok; struct ast_node *expr; struct ast_node *n = NULL; const struct inplocation_mark *start; tok = lexer_lookahead(parser_lexer(p), 1); if (!tok) { return NULL; } if (tok->type != TOKEN_KW_RETURN) { return NULL; } start = token_get_start(tok); //consume the return keyword lexer_curr_token_advance(parser_lexer(p)); expr = ast_parser_acc_expression(p); if (!expr) { parser_synerr(p, lexer_last_token_end(parser_lexer(p)), NULL, "Expected an expression for the return statement"); goto end; } n = ast_returnstmt_create(start, ast_node_endmark(expr), expr); if (!n) { RF_ERROR("Could not create a return statement during parsing"); } end: return n; }
static bool analyzer_create_symbol_table_fndecl(struct analyzer_traversal_ctx *ctx, struct ast_node *n) { AST_NODE_ASSERT_TYPE(n, AST_FUNCTION_DECLARATION); if (!ast_fndecl_symbol_table_init(n, ctx->m)) { RF_ERROR("Could not initialize symbol table for function declaration node"); return false; } // add function to the symbol table return analyzer_symbol_table_add_fndecl(ctx, n); }
static struct rir_block *rir_process_conditional_ast(const struct ast_node *ast_cond, const struct ast_node *ast_taken, const struct ast_node *ast_fallthrough, struct rir_block *old_block, struct rir_ctx *ctx) { const struct rir_value *cond = rir_process_ast_node_getreadval(ast_cond, ctx); if (!cond) { RF_ERROR("A condition value must have been created"); return NULL; } return rir_process_conditional((struct rir_value*)cond, ast_taken, ast_fallthrough, old_block, ctx); }
struct rir_object *rir_convert_create_obj_maybeadd(const struct rir_value *convval, const struct rir_type *totype, struct rir_ctx *ctx) { struct rir_object *obj = rir_convert_create_obj(convval, totype, ctx); if (!obj) { RF_ERROR("Failed to create convert rir instruction object"); return NULL; } if (obj->category == RIR_OBJ_EXPRESSION && obj->expr.type == RIR_EXPRESSION_CONVERT) { rirctx_block_add(ctx, &obj->expr); } return obj; }
struct rir_value *rirctx_getread_val(struct rir_value *v, struct rir_ctx *ctx) { // if a pointer and not a string, also perform a read if (!v->type->is_pointer || rir_type_no_read_required(v->type)) { return v; } struct rir_expression *read; read = rir_read_create(v, RIRPOS_AST, ctx); if (!read) { RF_ERROR("Failed to create a read RIR instruction"); return NULL; } rir_common_block_add(&ctx->common, read); return &read->val; }
struct type *type_function_create( struct module *m, struct type *arg_type, struct type *ret_type ) { struct type *t; t = type_alloc(m); if (!t) { RF_ERROR("Type allocation failed"); return NULL; } type_function_init(t, arg_type, ret_type); return t; }
enum traversal_cb_res typecheck_fndecl( struct ast_node *n, struct analyzer_traversal_ctx *ctx) { const struct type *t; t = type_lookup_identifier_string(ast_fndecl_name_str(n), ctx->current_st); if (!t) { RF_ERROR( "Function declaration name not found in the symbol table at " "impossible point" ); return TRAVERSAL_CB_ERROR; } traversal_node_set_type(n, t, ctx); return TRAVERSAL_CB_OK; }
struct rir_expression *rirctx_getread_expr(struct rir_expression *e, struct rir_ctx *ctx) { struct rir_expression *ret = NULL; // gotta read the memory value from an alloca // unless it's a string, which is passed by pointer at least at the moment if (e->type == RIR_EXPRESSION_ALLOCA && !rir_type_no_read_required(e->alloca.type)) { struct rir_expression *read; read = rir_read_create(&e->val, RIRPOS_AST, ctx); if (!read) { RF_ERROR("Failed to create a read RIR instruction"); return NULL; } rir_common_block_add(&ctx->common, read); ret = read; } else { ret = e; } return ret; }
bool rir_process_convertcall(const struct ast_node *n, struct rir_ctx *ctx) { struct ast_node *args = ast_fncall_args(n); RF_ASSERT(ast_node_get_type(args)->category != TYPE_CATEGORY_OPERATOR, "A conversion call should only have a single argument"); // process that argument const struct rir_value *argexprval = rir_process_ast_node_getreadval(args, ctx); if (!argexprval) { RF_ERROR("Could not create rir expression from conversion call argument"); RIRCTX_RETURN_EXPR(ctx, false, NULL); } // create the conversion struct rir_object *obj = rir_convert_create_obj_maybeadd( argexprval, rir_type_create_from_type(ast_node_get_type(n), ctx), ctx ); if (!obj) { RIRCTX_RETURN_EXPR(ctx, false, NULL); } RIRCTX_RETURN_EXPR(ctx, true, obj); }
static bool analyzer_first_pass_do(struct ast_node *n, void *user_arg) { struct analyzer_traversal_ctx *ctx = user_arg; analyzer_traversal_ctx_push_parent(ctx, n); // act depending on the node type switch(n->type) { // nodes that change the current symbol table case AST_BLOCK: if (!ast_block_symbol_table_init(n, ctx->m)) { RF_ERROR("Could not initialize symbol table for block node"); return false; } symbol_table_swap_current(&ctx->current_st, ast_block_symbol_table_get(n)); break; case AST_MODULE: // input the module's name to the symbol table if (!analyzer_populate_symbol_module(ctx, n)) { return false; } symbol_table_swap_current(&ctx->current_st, ast_module_symbol_table_get(n)); break; case AST_FUNCTION_DECLARATION: if (!analyzer_create_symbol_table_fndecl(ctx, n)) { return false; } symbol_table_swap_current(&ctx->current_st, ast_fndecl_symbol_table_get(n)); symbol_table_set_fndecl(ctx->current_st, n); break; case AST_FUNCTION_IMPLEMENTATION: // function implementation symbol table should point to its decl table ast_fnimpl_symbol_table_set(n, ast_fndecl_symbol_table_get(n->fnimpl.decl)); break; case AST_MATCH_CASE: // match case symbol table should point to its pattern typedesc table ast_matchcase_symbol_table_set(n, ast_typedesc_symbol_table_get(n->matchcase.pattern)); break; case AST_TYPE_DESCRIPTION: // initialize the type description's symbol table if (!symbol_table_init(&n->typedesc.st, ctx->m)) { RF_ERROR("Could not initialize symbol table for top level type description node"); return false; } symbol_table_swap_current(&ctx->current_st, ast_typedesc_symbol_table_get(n)); // also populate the type description's symbol table if (!analyzer_populate_symbol_table_typedesc(ctx, n)) { RF_ERROR("Could not populate symbol table for top level type description node"); return false; } break; case AST_TYPE_DECLARATION: if (!analyzer_populate_symbol_table_typedecl(ctx, n)) { return false; } break; // nodes that only contribute records to symbol tables case AST_VARIABLE_DECLARATION: if (!analyzer_populate_symbol_table_vardecl(ctx, n)) { RF_ERROR("Could not populate symbol table for variable declaration"); return false; } break; case AST_IDENTIFIER: // create identifier hash and dissasociate from the file RF_ASSERT(n->state == AST_NODE_STATE_AFTER_PARSING, "Attempting to create identifier hash for node in a wrong " "state of processing"); if (!ast_identifier_hash_create(n, ctx->m)) { return false; } break; case AST_STRING_LITERAL: // create literal hash and dissasociate from the file RF_ASSERT(n->state == AST_NODE_STATE_AFTER_PARSING, "Attempting to create literal hash for node in a wrong state " "of processing"); if (!ast_string_literal_hash_create(n, ctx->m)) { return false; } break; default: // do nothing break; } // since this is the very first pass of the analyzer and should happen // only once, change node ownership here n->state = AST_NODE_STATE_ANALYZER_PASS1; return true; }
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; } }