From 2157fdbaca0b80e488c4f77ad5c0d04b051175cf Mon Sep 17 00:00:00 2001 From: Kimplul Date: Mon, 12 Aug 2024 18:55:46 +0300 Subject: make defer work better with generic code --- src/actualize.c | 137 +++++++++++++++++++++++++++++++++++++++++--------------- src/ast.c | 27 +++++++++++ src/debug.c | 2 +- src/lower.c | 73 +++++++++++++++++++++++++++++- src/parser.y | 44 ++++-------------- src/scope.c | 17 ++++--- 6 files changed, 221 insertions(+), 79 deletions(-) (limited to 'src') diff --git a/src/actualize.c b/src/actualize.c index 591333a..3837d00 100644 --- a/src/actualize.c +++ b/src/actualize.c @@ -35,6 +35,7 @@ struct act_state { struct ast *cur_proc; struct act_stack *defer_stack; + struct act_stack *loop_stack; struct act_stack *goto_stack; struct act_stack *label_stack; }; @@ -436,6 +437,14 @@ static void replace_ast(struct ast *n, struct ast *t) t->scope = scope; } +static void replace_slice_ast(struct ast *n, struct ast *t) +{ + struct ast *next = n->n; + replace_ast(n, t); + n->n = next; + /** @todo scope as well? */ +} + static struct ast *analyze_type_expand(struct scope *scope, struct ast *n) { @@ -549,7 +558,7 @@ int types_match(struct type *a, struct type *b) if (a->k == TYPE_CALLABLE) return types_match(callable_rtype(a), callable_rtype(b)) - && types_match(callable_ptypes(a), callable_ptypes(b)); + && types_match(callable_ptypes(a), callable_ptypes(b)); if (is_primitive(a) && is_primitive(b)) return 1; @@ -595,7 +604,7 @@ static int _replace_id(struct ast *node, void *data) clone->n = node->n; clone->scope = node->scope; - replace_ast(node, clone); + replace_slice_ast(node, clone); /* a succesful replacement needs no futher replacements, I think */ return 0; @@ -638,7 +647,8 @@ static int implements(struct type *trait, struct type *type) return 0; } -static int should_implement_list(struct scope *scope, struct ast *params, struct src_loc loc, struct type *types) +static int should_implement_list(struct scope *scope, struct ast *params, + struct src_loc loc, struct type *types) { while (params && types) { assert(params->k == AST_VAR_DEF); @@ -647,9 +657,9 @@ static int should_implement_list(struct scope *scope, struct ast *params, struct char *type1 = type_str(types); char *type2 = type_str(t); type_error(scope->fctx, types, - "%s does not implement %s", - type1, - type2); + "%s does not implement %s", + type1, + type2); free(type1); free(type2); return 0; @@ -664,13 +674,13 @@ static int should_implement_list(struct scope *scope, struct ast *params, struct if (params != NULL) { loc_error(scope->fctx, loc, - "too few type params"); + "too few type params"); return 0; } if (types != NULL) { loc_error(scope->fctx, loc, - "too many type params"); + "too many type params"); return 0; } @@ -704,7 +714,7 @@ static int expand_type(struct ast *expd, struct ast *params, struct type *types) struct scope *p = expd->scope->parent; reset(expd); - + foreach_node(n, params) { struct ast *p = clone_ast(n); var_type(p) = clone_type(types); @@ -726,7 +736,8 @@ static int expand_type(struct ast *expd, struct ast *params, struct type *types) return ret; } -static struct ast *maybe_expand_struct(struct scope *scope, struct ast *def, struct src_loc loc, struct type *args) +static struct ast *maybe_expand_struct(struct scope *scope, struct ast *def, + struct src_loc loc, struct type *args) { assert(def->k == AST_STRUCT_DEF); if (struct_params(def) == NULL) { @@ -734,8 +745,8 @@ static struct ast *maybe_expand_struct(struct scope *scope, struct ast *def, str return def; loc_error(scope->fctx, loc, - "passing types to non-generic struct %s", - struct_id(def)); + "passing types to non-generic struct %s", + struct_id(def)); return NULL; } @@ -754,14 +765,15 @@ static struct ast *maybe_expand_struct(struct scope *scope, struct ast *def, str return expd; } -static struct ast *maybe_expand_trait(struct scope *scope, struct ast *def, struct src_loc loc, struct type *args) +static struct ast *maybe_expand_trait(struct scope *scope, struct ast *def, + struct src_loc loc, struct type *args) { assert(def->k == AST_TRAIT_DEF); if (trait_params(def) == NULL) { if (args != NULL) { loc_error(scope->fctx, loc, - "passing types to non-generic trait %s", - trait_id(def)); + "passing types to non-generic trait %s", + trait_id(def)); return NULL; } @@ -772,7 +784,8 @@ static struct ast *maybe_expand_trait(struct scope *scope, struct ast *def, stru return NULL; } -static struct ast *maybe_expand_type(struct scope *scope, struct ast *def, struct src_loc loc, struct type *args) +static struct ast *maybe_expand_type(struct scope *scope, struct ast *def, + struct src_loc loc, struct type *args) { assert(def->k == AST_STRUCT_DEF || def->k == AST_TRAIT_DEF); if (def->k == AST_STRUCT_DEF) @@ -842,8 +855,7 @@ static int actualize_macro_expand(struct act_state *state, arg = arg->n = next_arg; } - free(macro_expand_id(macro_expand)); - replace_ast(macro_expand, body); + replace_slice_ast(macro_expand, body); /* actualize the new content */ if (actualize(state, scope, macro_expand)) { @@ -863,18 +875,19 @@ static int simplify_refderef(struct act_state *state, struct scope *scope, struct ast *e = unop_expr(n); if (n->k == AST_REF && e->k == AST_DEREF) { - replace_ast(n, unop_expr(e)); + replace_slice_ast(n, unop_expr(e)); return simplify_refderef(state, scope, n); } if (n->k == AST_DEREF && e->k == AST_REF) { - replace_ast(n, unop_expr(e)); + replace_slice_ast(n, unop_expr(e)); return simplify_refderef(state, scope, n); } return 0; } +/* not really ufcs at the moment */ static int maybe_ufcs(struct act_state *state, struct scope *scope, struct ast *call) { @@ -883,6 +896,11 @@ static int maybe_ufcs(struct act_state *state, struct scope *scope, if (dot->k != AST_DOT) return 0; + struct type *ptypes = callable_ptypes(dot->t); + if (!ptypes) + /* no ufcs */ + return 0; + struct ast *expr = dot_expr(dot); char *id = strdup(dot_id(dot)); call_expr(call) = gen_fetch(id, clone_type(expr->t), dot->loc); @@ -890,7 +908,7 @@ static int maybe_ufcs(struct act_state *state, struct scope *scope, (call_expr(call))->scope = scope; struct ast *ref = NULL; - struct type *ptypes = callable_ptypes(dot->t); + if (ptypes->k == TYPE_PTR) { /* is ufcs expects reference to member, try to take address */ ref = gen_unop(AST_REF, expr, dot->loc); @@ -1057,11 +1075,12 @@ static int actualize_proc(struct act_state *state, return -1; } - /* add 'implicit' return */ + /* add 'implicit' return as the last defer statement to be executed in a block*/ struct ast *body = proc_body(proc); struct ast *r = gen_return(NULL, NULL, NULL_LOC()); r->scope = body->scope; - ast_append(&block_body(body), r); + r->n = block_defers(body); + block_defers(body) = r; } else if (ast_block_last(proc_body(proc))->k != AST_RETURN) { /* TODO: something more sophisticated than this */ @@ -1151,6 +1170,10 @@ static int actualize_block(struct act_state *state, /* TODO: currently defers are sort of duplicated after a return, unsure * if they should be handled here or somewhere else */ if (state->defer_stack) { + /* no new defers, no need to clone anything */ + if (state->defer_stack == defers) + return 0; + block_defers(node) = clone_defers(state, defers); if (!block_defers(node)) { internal_error("failed cloning defers"); @@ -1369,7 +1392,7 @@ static int actualize_tstruct(struct act_state *state, struct scope *scope, } static int actualize_ttrait(struct act_state *state, struct scope *scope, - struct type *t) + struct type *t) { UNUSED(state); /* not much to do */ @@ -1387,8 +1410,8 @@ static int actualize_ttrait(struct act_state *state, struct scope *scope, } static int actualize_tconstruct(struct act_state *state, - struct scope *scope, - struct type *t) + struct scope *scope, + struct type *t) { assert(t->k == TYPE_CONSTRUCT); struct ast *d = file_scope_find_type(scope, construct_id(t)); @@ -1604,8 +1627,6 @@ static int actualize_defer(struct act_state *state, struct scope *scope, struct ast *node) { struct ast *expr = defer_expr(node); - /* TODO: should the actualization only happen when the defers are - * called? */ if (actualize(state, scope, expr)) return -1; @@ -1655,6 +1676,8 @@ static int actualize_return(struct act_state *state, struct scope *scope, * nonetheless. */ static void actualize_goto_defer(struct ast *got, struct ast *label) { + goto_label_ref(got) = label; + struct ast *goto_defers = goto_defers(got); struct ast *label_defers = label_defers(label); /* since we're dealing with singly linked lists, keep a reference to one @@ -1884,7 +1907,7 @@ static int _replace_type_id(struct type *type, void *data) return 0; } -static int _replace_ast_type_id(struct ast *node, void *data) +static int _replace_slice_ast_type_id(struct ast *node, void *data) { if (!node) return 0; @@ -1902,7 +1925,7 @@ static int replace_type_id(struct ast *nodes, char *id, struct type *replacement) { struct replace_data pair = {id, replacement}; - return ast_visit_list(_replace_ast_type_id, NULL, nodes, &pair); + return ast_visit_list(_replace_slice_ast_type_id, NULL, nodes, &pair); } static int _clear_scope(struct ast *node, void *data) @@ -2054,7 +2077,8 @@ static int actualize_struct(struct act_state *state, type_append(&tstruct_params(node->t), type); - struct ast *alias = gen_alias(strdup(id), clone_type(type), n->loc); + struct ast *alias = gen_alias(strdup(id), clone_type(type), + n->loc); if (analyze_visibility(struct_scope, alias)) return -1; @@ -2346,7 +2370,7 @@ static int actualize_enum_fetch(struct act_state *state, struct scope *scope, return -1; } - replace_ast(fetch, val_val(member)); + replace_slice_ast(fetch, val_val(member)); set_type(fetch, def->t); return 0; } @@ -2465,19 +2489,60 @@ static int actualize_for(struct act_state *state, struct scope *scope, struct ast *node) { assert(node->k == AST_FOR); + struct act_stack *prev = state->loop_stack; + enum act_flags flags = state->flags; + node->t = void_type(); + if (actualize_list(state, scope, for_pre(node))) - return -1; + goto err; if (actualize_list(state, scope, for_post(node))) - return -1; + goto err; if (actualize_list(state, scope, for_cond(node))) - return -1; + goto err; + state->flags |= ACT_IN_LOOP; if (actualize_list(state, scope, for_body(node))) + goto err; + + state->loop_stack = prev; + state->flags = flags; + return 0; + +err: + state->loop_stack = prev; + state->flags = flags; + return -1; +} + +static int actualize_continue(struct act_state *state, struct scope *scope, + struct ast *node) +{ + UNUSED(scope); + node->t = void_type(); + if (!state->flags & ACT_IN_LOOP) { + semantic_error(scope->fctx, node, + "continue outside of loop"); return -1; + } + + continue_defers(node) = clone_defers(state, state->loop_stack); + return 0; +} +static int actualize_break(struct act_state *state, struct scope *scope, + struct ast *node) +{ + UNUSED(scope); node->t = void_type(); + if (!state->flags & ACT_IN_LOOP) { + semantic_error(scope->fctx, node, + "break outside of loop"); + return -1; + } + + break_defers(node) = clone_defers(state, state->loop_stack); return 0; } @@ -2579,6 +2644,8 @@ static int actualize(struct act_state *state, struct scope *scope, case AST_FETCH: ret = actualize_fetch(state, scope, node); break; case AST_IF: ret = actualize_if(state, scope, node); break; case AST_FOR: ret = actualize_for(state, scope, node); break; + case AST_CONTINUE: ret = actualize_continue(state, scope, node); break; + case AST_BREAK: ret = actualize_break(state, scope, node); break; case AST_MACRO_EXPAND: ret = actualize_macro_expand(state, scope, node); break; case AST_MACRO_DEF: ret = actualize_macro_def(state, scope, node); diff --git a/src/ast.c b/src/ast.c index 890196b..c36d7a7 100644 --- a/src/ast.c +++ b/src/ast.c @@ -753,3 +753,30 @@ size_t type_offsetof(struct type *t, char *m) return offset; } + +struct ast *reverse_ast_list(struct ast *root) +{ + struct ast *new_root = NULL; + while (root) { + struct ast *next = root->n; + root->n = new_root; + new_root = root; + root = next; + } + + return new_root; +} + +struct type *reverse_type_list(struct type *root) +{ + struct type *new_root = NULL; + while (root) { + struct type *next = root->n; + root->n = new_root; + new_root = root; + root = next; + } + + return new_root; +} + diff --git a/src/debug.c b/src/debug.c index 0d11473..47e53f2 100644 --- a/src/debug.c +++ b/src/debug.c @@ -147,7 +147,7 @@ void type_error(struct file_ctx fctx, struct type *node, } void loc_error(struct file_ctx fctx, struct src_loc loc, - const char *fmt, ...) + const char *fmt, ...) { va_list args; va_start(args, fmt); diff --git a/src/lower.c b/src/lower.c index 630cb1d..18d0576 100644 --- a/src/lower.c +++ b/src/lower.c @@ -226,6 +226,7 @@ static ssize_t visit_struct(struct lower_state *s, struct ast *def, size_t base, static int lower_expr(struct lower_state *s, struct ast *e, struct retval *retval); + static int lower_statement(struct lower_state *s, struct ast *n); static void output_ast_id(struct ast *id) @@ -502,6 +503,7 @@ static int lower_assign(struct lower_state *s, struct ast *a, } printf("i27 %s = %s;\n", loc.s, retval->s); + retval_destroy(&loc); return 0; } @@ -546,16 +548,29 @@ static int lower_struct_return(struct lower_state *s, struct ast *n, size_t o, return 0; } +static int lower_deferred(struct lower_state *s, struct ast *d) +{ + struct ast *t = reverse_ast_list(d); + foreach_node(n, t) { + if (lower_statement(s, n)) + return -1; + } + + return 0; +} + static int lower_return(struct lower_state *s, struct ast *r, struct retval *retval) { assert(r->k == AST_RETURN); + if (lower_deferred(s, return_defers(r))) + return -1; + if (!return_expr(r)) { printf("=> ();\n"); return 0; } - /** @todo defers, should they be handled here or in ast? */ if (lower_expr(s, return_expr(r), retval)) return -1; @@ -1131,6 +1146,9 @@ static int lower_block(struct lower_state *s, struct ast *block) return -1; } + if (lower_deferred(s, block_defers(block))) + return -1; + assert(deallocs_top <= vec_len(&s->dealloc)); s->deallocs = deallocs_parent; @@ -1150,6 +1168,54 @@ static int lower_block(struct lower_state *s, struct ast *block) return 0; } +static int lower_continue(struct lower_state *s, struct ast *n) +{ + assert(n->k == AST_CONTINUE); + if (lower_deferred(s, continue_defers(n))) + return -1; + + char *bottom = label_peek(s->bottom); + printf("-> %s\n", bottom); + return 0; +} + +static int lower_break(struct lower_state *s, struct ast *n) +{ + assert(n->k == AST_BREAK); + if (lower_deferred(s, break_defers(n))) + return -1; + + char *out = label_peek(s->out); + printf("-> %s;\n", out); + return 0; +} + +static int lower_goto(struct lower_state *s, struct ast *n) +{ + assert(n->k == AST_GOTO); + if (lower_deferred(s, goto_defers(n))) + return -1; + + struct ast *label = goto_label_ref(n); + assert(label); + + char *out = mangle_scope(label, label->scope); + printf("-> %s;\n", out); + free(out); + return 0; +} + +static int lower_label(struct lower_state *s, struct ast *n) +{ + UNUSED(s); + + assert(n->k == AST_LABEL); + char *out = mangle_scope(n, n->scope); + printf("-> %s\n", out); + free(out); + return 0; +} + static int lower_statement(struct lower_state *s, struct ast *n) { struct retval retval = retval_create(); @@ -1160,6 +1226,11 @@ static int lower_statement(struct lower_state *s, struct ast *n) case AST_IF: ret = lower_if(s, n, &retval); break; case AST_FOR: ret = lower_for(s, n, &retval); break; case AST_BLOCK: ret = lower_block(s, n); break; + case AST_CONTINUE: ret = lower_continue(s, n); break; + case AST_BREAK: ret = lower_break(s, n); break; + case AST_GOTO: ret = lower_goto(s, n); break; + case AST_LABEL: ret = lower_label(s, n); break; + case AST_DEFER: break; case AST_EMPTY: break; default: ret = lower_expr(s, n, &retval); break; } diff --git a/src/parser.y b/src/parser.y index a51eb9a..62afcac 100644 --- a/src/parser.y +++ b/src/parser.y @@ -134,7 +134,7 @@ %nterm var_init proc %nterm alias trait enum_val enums enum top unit id %nterm embed param_decl members -%nterm top_if const_if const_for defer goto assign +%nterm top_if const_if const_for goto assign %nterm construct construct_args construct_arg %nterm statelet @@ -157,6 +157,7 @@ %nterm opt_types opt_sign_decls sign_decls sign_decl sign_var_decl %nterm opt_construct_args %nterm opt_behaviours behaviours behaviour +%nterm opt_deferred_statement /* reverse lists */ %nterm rev_sign_decls; @@ -241,9 +242,6 @@ static char match_escape(char c); */ static char *strip(const char *s); -static struct ast *reverse_ast_list(struct ast *root); -static struct type *reverse_type_list(struct type *root); - %} %start input; @@ -344,9 +342,6 @@ opt_decls : decls | {$$ = NULL;} -defer - : "defer" body { $$ = gen_defer($2, src_loc(@$)); } - const_binop : const_expr "+" const_expr { $$ = gen_binop(AST_ADD, $1, $3, src_loc(@$)); @@ -480,16 +475,19 @@ statement | struct | struct_cont | for - | defer | if | const | enum | macro | ID ":" { $$ = gen_label($[ID], NULL, src_loc(@$)); } +opt_deferred_statement + : statement + | "defer" statement { $$ = gen_defer($2, src_loc(@$)); } + rev_statements - : rev_statements statement { $$ = $2; $2->n = $1; } - | statement + : rev_statements opt_deferred_statement { $$ = $2; $2->n = $1; } + | opt_deferred_statement statements : rev_statements { $$ = reverse_ast_list($1); } @@ -1002,32 +1000,6 @@ static char *strip(const char *str) } -static struct ast *reverse_ast_list(struct ast *root) -{ - struct ast *new_root = NULL; - while (root) { - struct ast *next = root->n; - root->n = new_root; - new_root = root; - root = next; - } - - return new_root; -} - -static struct type *reverse_type_list(struct type *root) -{ - struct type *new_root = NULL; - while (root) { - struct type *next = root->n; - root->n = new_root; - new_root = root; - root = next; - } - - return new_root; -} - struct parser *create_parser() { return calloc(1, sizeof(struct parser)); diff --git a/src/scope.c b/src/scope.c index 5cd7075..f17b8ed 100644 --- a/src/scope.c +++ b/src/scope.c @@ -113,7 +113,8 @@ struct visible *create_type(struct scope *scope, char *id, struct ast *type) return n; } -struct expanded *create_expanded(struct scope *scope, struct ast *def, struct type *types, struct ast *expd) +struct expanded *create_expanded(struct scope *scope, struct ast *def, + struct type *types, struct ast *expd) { struct expanded *n = calloc(1, sizeof(struct expanded)); if (!n) @@ -257,14 +258,15 @@ int scope_add_trait(struct scope *scope, struct ast *trait) return 0; } -int scope_add_expd_struct(struct scope *scope, struct ast *def, struct type *types, struct ast *expd) +int scope_add_expd_struct(struct scope *scope, struct ast *def, + struct type *types, struct ast *expd) { assert(def->k == AST_STRUCT_DEF); assert(file_scope_find_expd_struct(scope, def, types) == NULL); create_expanded(scope, def, types, expd); if (scope->parent && - scope_flags(scope, SCOPE_FILE) && ast_flags(def, AST_FLAG_PUBLIC)) + scope_flags(scope, SCOPE_FILE) && ast_flags(def, AST_FLAG_PUBLIC)) return scope_add_expd_struct(scope->parent, def, types, expd); return 0; @@ -284,7 +286,8 @@ static struct ast *scope_find_visible(struct visible *v, char *id) return NULL; } -static struct ast *scope_find_expanded(struct expanded *e, struct ast *def, struct type *types) +static struct ast *scope_find_expanded(struct expanded *e, struct ast *def, + struct type *types) { if (!e) return NULL; @@ -411,7 +414,8 @@ struct ast *file_scope_find_var(struct scope *scope, char *id) return NULL; } -struct ast *scope_find_expd_struct(struct scope *scope, struct ast *def, struct type *types) +struct ast *scope_find_expd_struct(struct scope *scope, struct ast *def, + struct type *types) { assert(def->k == AST_STRUCT_DEF); struct ast *exists = scope_find_expanded(scope->expanded, def, types); @@ -422,7 +426,8 @@ struct ast *scope_find_expd_struct(struct scope *scope, struct ast *def, struct return exists; } -struct ast *file_scope_find_expd_struct(struct scope *scope, struct ast *def, struct type *types) +struct ast *file_scope_find_expd_struct(struct scope *scope, struct ast *def, + struct type *types) { assert(def->k == AST_STRUCT_DEF); struct ast *found = scope_find_expd_struct(scope, def, types); -- cgit v1.3