Example #1
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;
}
Example #2
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;
}
Example #3
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;
}
Example #4
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;
}
Example #5
0
struct ast_node *parser_acc_fnimpl(struct parser *p)
{
    struct ast_node *n;
    struct ast_node *decl;
    struct ast_node *body;
    struct token *tok;

    decl = parser_acc_fndecl(p, FNDECL_PARTOF_IMPL);
    if (!decl) {
        return NULL;
    }    
    tok = lexer_lookahead(p->lexer, 1);
    if (!tok) {
        goto fail_free_decl;
    }

    if (tok->type == TOKEN_SM_OCBRACE) {
        // normal function body
        body = parser_acc_block(p, true);
        if (!body) {
            parser_synerr(p, ast_node_endmark(decl), NULL,
                          "Expected a body for \""RF_STR_PF_FMT"\" function "
                          "implementation", RF_STR_PF_ARG(ast_fndecl_name_str(decl)));
            goto fail_free_decl;
        }
    } else {
        // attempt to find a headless match expression as the function body
        body = parser_acc_matchexpr(p, false, true);
        if (!body) {
            parser_synerr(p, ast_node_endmark(decl), NULL,
                          "Expected a body for \""RF_STR_PF_FMT"\" function "
                          "implementation", RF_STR_PF_ARG(ast_fndecl_name_str(decl)));
            goto fail_free_decl;
        }
        // now set the matchexpr's fn_args since this is a headless matchexpr
        ast_matchexpr_set_fnargs(body, ast_fndecl_args_get(decl));
    }
        
    n = ast_fnimpl_create(ast_node_startmark(decl),
                          ast_node_endmark(body),
                          decl,
                          body);
    if (!n) {
        RF_ERRNOMEM();
        ast_node_destroy(body);
        ast_node_destroy(decl);
        return NULL;
    }
    return n;

fail_free_decl:
    ast_node_destroy(decl);
    return NULL;
}
Example #6
0
struct ast_node *ast_iterable_create_identifier(struct ast_node *identifier)
{
    struct ast_node *ret = ast_node_create_marks(
        AST_ITERABLE,
        ast_node_startmark(identifier),
        ast_node_endmark(identifier)
    );
    if (!ret) {
        return NULL;
    }
    ret->iterable.type = ITERABLE_COLLECTION;
    ast_node_register_child(ret, identifier, iterable.identifier);

    return ret;
}
Example #7
0
struct ast_node *ast_iterable_create_range(
    struct ast_node *start_node,
    struct ast_node *step_node,
    struct ast_node *end_node)
{
    struct ast_node *ret = ast_node_create_marks(
        AST_ITERABLE,
        ast_node_startmark(start_node),
        ast_node_endmark(end_node)
    );

    if (!ret) {
        return NULL;
    }
    ret->iterable.type = ITERABLE_RANGE;
    memset(&ret->iterable.range, 0 , sizeof(struct int_range));
    ret->iterable.range.start = -1;
    ret->iterable.range.step = 1; // default step
    ret->iterable.range.end = -1;


    ast_node_register_child(ret, start_node, iterable.range.start_node);
    if (ast_node_type(start_node) == AST_CONSTANT) {
        if (!ast_constant_get_integer(&start_node->constant, &ret->iterable.range.start)) {
            return NULL;
        }
    }

    if (step_node) {
        ast_node_register_child(ret, step_node, iterable.range.step_node);
        if (ast_node_type(step_node) == AST_CONSTANT) {
            if (!ast_constant_get_integer(&step_node->constant, &ret->iterable.range.step)) {
                return NULL;
            }
        }
    }

    ast_node_register_child(ret, end_node, iterable.range.end_node);
    if (ast_node_type(end_node) == AST_CONSTANT) {
        if (!ast_constant_get_integer(&end_node->constant, &ret->iterable.range.end)) {
            return NULL;
        }
    }

    return ret;
}
Example #8
0
static bool analyzer_populate_symbol_table_vardecl(struct analyzer_traversal_ctx *ctx,
                                                   struct ast_node *n)
{
    struct ast_node *left;
    struct ast_node *desc;
    AST_NODE_ASSERT_TYPE(n, AST_VARIABLE_DECLARATION);

    desc = ast_vardecl_desc_get(n);
    left = ast_typeleaf_left(desc);
    if (left->type != AST_IDENTIFIER) {
        analyzer_err(ctx->m, ast_node_startmark(left),
                     ast_node_endmark(left),
                     "Expected an identifier in the left side of a variable's  "
                     "type description node but "
                     "found a \""RF_STR_PF_FMT"\"",
                     RF_STR_PF_ARG(ast_node_str(left)));
            return false;
    }
    return analyzer_populate_symbol_table_typeleaf(ctx, desc);
}
Example #9
0
/* will always post a syntax error if it fails */
static struct ast_node *parser_acc_condbranch(struct parser *p,
                                              struct token *after_tok)
{
    struct ast_node *n;
    struct ast_node *expr;
    struct ast_node *block;

    expr = parser_acc_expression(p);
    if (!expr) {
        parser_synerr(p, token_get_end(after_tok), NULL,
                      "Expected an expression after '"RF_STR_PF_FMT"'",
                      RF_STR_PF_ARG(tokentype_to_str(after_tok->type)));
        return NULL;
    }

    block = parser_acc_block(p, true);
    if (!block) {
        parser_synerr(p, ast_node_endmark(expr), NULL,
                      "Expected a block after \""RF_STR_PF_FMT"\"'s "
                      "conditional expression",
                      RF_STR_PF_ARG(tokentype_to_str(after_tok->type)));
        ast_node_destroy(expr);
        return NULL;
    }

    n = ast_condbranch_create(ast_node_startmark(expr),
                              ast_node_endmark(block),
                              expr, block);
    if (!n) {
        RF_ERRNOMEM();
        ast_node_destroy(expr);
        ast_node_destroy(block);
        return NULL;
    }

    return n;
}
Example #10
0
struct ast_node *ast_parser_acc_block(struct ast_parser *p, bool expect_braces)
{
    struct ast_node *n;
    struct token *tok;
    struct ast_node *element;
    const struct inplocation_mark *start = NULL;
    const struct inplocation_mark *end = NULL;
    lexer_push(parser_lexer(p));

    tok = lexer_lookahead(parser_lexer(p), 1);
    if (!tok) {
        goto err;
    }

    if (expect_braces) {
        if (tok->type != TOKEN_SM_OCBRACE) {
            goto err;
        }
        // consume '{'
        lexer_curr_token_advance(parser_lexer(p));
        start = token_get_start(tok);
    }

    if (!(n = ast_block_create())) {
        goto err;
    }

    //try to parse the first element
    if (!(element = ast_parser_acc_block_element(p))) {
        if (!expect_braces) {
            goto err_free_block;
        }

        //else just find the terminating '}' and return
        tok = lexer_lookahead(parser_lexer(p), 1);
        if (!tok || tok->type != TOKEN_SM_CCBRACE) {
            parser_synerr(
                p,
                lexer_last_token_end(parser_lexer(p)),
                NULL,
                "Expected an expression or a '}' at block end"
            );
            goto err_free_block;
        }
        //consume the '}'
        lexer_curr_token_advance(parser_lexer(p));

        ast_node_set_start(n, start);
        ast_node_set_end(n, token_get_end(tok));
        return n; //empty block
    }

    if (!start) {
        start = ast_node_startmark(element);
    }
    end = ast_node_endmark(element);
    ast_block_add_element(n, element);

    // now add elements to the block
    while ((element = ast_parser_acc_block_element(p))) {
        ast_block_add_element(n, element);
        end = ast_node_endmark(element);
    }

    if (expect_braces) {
        tok = lexer_lookahead(parser_lexer(p), 1);
        if (!tok || tok->type != TOKEN_SM_CCBRACE) {
            parser_synerr(
                p,
                lexer_last_token_end(parser_lexer(p)),
                NULL,
                "Expected an expression or a '}' at block end"
            );
            goto err_free_block;
        }
        //consume the '}'
        lexer_curr_token_advance(parser_lexer(p));

        end = token_get_end(tok);
    }

    ast_node_set_start(n, start);
    ast_node_set_end(n, end);
    lexer_pop(parser_lexer(p));
    return n;

err_free_block:
    ast_node_destroy(n);
err:
    lexer_rollback(parser_lexer(p));
    return NULL;
}
Example #11
0
struct ast_node *parser_acc_fncall(struct parser *p, bool expect_it)
{
    struct ast_node *n;
    struct token *tok;
    struct ast_node *name;
    struct ast_node *genr = NULL;
    struct ast_node *args = NULL;
    lexer_push(p->lexer);

    name = parser_acc_identifier(p);
    if (!name) {
        goto err;
    }

    genr = parser_acc_genrattr(p, false);
    if (!genr && parser_has_syntax_error(p)) {
        // name is an identifier and even in failure does not need to get destroyed here
        goto err;
    }

    tok = lexer_lookahead(p->lexer, 1);
    if (!tok || tok->type != TOKEN_SM_OPAREN) {
        if (expect_it) {
            parser_synerr(p, lexer_last_token_start(p->lexer), NULL,
                          "Expected '('");
        }
        goto err_free_genr;
    }
    //consume '('
    lexer_next_token(p->lexer);

    args = parser_acc_expression(p);
    if (!args) {
        if (parser_has_syntax_error(p)) {
                parser_synerr(p, lexer_last_token_start(p->lexer), NULL,
                              "Expected argument expression for function call");
            goto err_free_genr;
        }
    }

    tok = lexer_lookahead(p->lexer, 1);
    if (!tok || tok->type != TOKEN_SM_CPAREN) {
        if (expect_it) {
            parser_synerr(p, lexer_last_token_end(p->lexer), NULL,
                          "Expected ')' at end of "RF_STR_PF_FMT" function call",
                          RF_STR_PF_ARG(ast_identifier_str(name)));
        }
        goto err_free_args;
    }
    //consume ')'
    lexer_next_token(p->lexer);

    n = ast_fncall_create(ast_node_startmark(name), token_get_end(tok),
                          name, args, genr);
    if (!n) {
        RF_ERRNOMEM();
        goto err_free_args;
    }

    lexer_pop(p->lexer);
    return n;

err_free_args:
    if (args) {
        ast_node_destroy(args);
    }
err_free_genr:
    if (genr) {
        ast_node_destroy(genr);
    }
err:
    lexer_rollback(p->lexer);
    return NULL;
}
Example #12
0
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;
}