Beispiel #1
0
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);
}
Beispiel #2
0
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);
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
}
Beispiel #8
0
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);
}
Beispiel #10
0
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;
}
Beispiel #11
0
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;
}
Beispiel #12
0
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;
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
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);
}
Beispiel #16
0
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;
}
Beispiel #17
0
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;
    }
}