diff --git a/src/compile.c b/src/compile.c index 68eefd7..57a6255 100644 --- a/src/compile.c +++ b/src/compile.c @@ -303,10 +303,28 @@ tmp_ilist(struct compiler *compiler, int line) return ilist; } +static struct matcher_instruction_list * +tmp_milist(struct compiler *compiler) +{ + struct matcher_instruction_list *milist; + if ( + (milist = apfl_matcher_instructions_new(compiler->gc)) == NULL + || !apfl_gc_tmproot_add( + compiler->gc, + GC_OBJECT_FROM(milist, GC_TYPE_MATCHER_INSTRUCTIONS) + ) + ) { + return NULL; + } + + return milist; +} + struct compile_assignable_ilists { struct instruction_list *prelude; struct instruction_list *newvars; struct instruction_list *setvars; + struct matcher_instruction_list *matcher; }; static bool @@ -315,7 +333,6 @@ compile_assignable( bool local, struct apfl_position position, struct apfl_expr_assignable *assignable, - struct matcher_instruction_list *milist, struct compile_assignable_ilists ilists ); @@ -324,10 +341,9 @@ compile_assignable_var_or_member( struct compiler *compiler, bool local, struct apfl_expr_assignable_var_or_member *var_or_member, - struct matcher_instruction_list *milist, struct compile_assignable_ilists ilists ) { - size_t index = milist->capture_count++; + size_t index = ilists.matcher->capture_count++; if (var_or_member->type != APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR) { compiler->error = apfl_error_simple(APFL_ERR_NOT_IMPLEMENTED); // TODO: Implement me @@ -346,9 +362,9 @@ compile_assignable_var_or_member( * } */ - TRY(milist_ensure_cap(compiler, milist, 2)); - milist_put_insn(milist, MATCHER_CAPTURE); - milist_put_index(milist, index); + TRY(milist_ensure_cap(compiler, ilists.matcher, 2)); + milist_put_insn(ilists.matcher, MATCHER_CAPTURE); + milist_put_index(ilists.matcher, index); TRY(ilist_ensure_cap(compiler, ilists.newvars, 2)); @@ -370,20 +386,19 @@ static bool compile_assignable_constant( struct compiler *compiler, struct apfl_expr_const *constant, - struct matcher_instruction_list *milist, struct compile_assignable_ilists ilists ) { - size_t index = milist->value_count++; + size_t index = ilists.matcher->value_count++; TRY(compile_constant(compiler, constant, ilists.prelude)); TRY(ilist_ensure_cap(compiler, ilists.prelude, 2)); ilist_put_insn(ilists.prelude, INSN_MATCHER_SET_VAL); ilist_put_index(ilists.prelude, index); - TRY(milist_ensure_cap(compiler, milist, 3)); - milist_put_insn(milist, MATCHER_CHECK_CONST); - milist_put_index(milist, index); - milist_put_insn(milist, MATCHER_IGNORE); + TRY(milist_ensure_cap(compiler, ilists.matcher, 3)); + milist_put_insn(ilists.matcher, MATCHER_CHECK_CONST); + milist_put_index(ilists.matcher, index); + milist_put_insn(ilists.matcher, MATCHER_IGNORE); return true; } @@ -394,21 +409,20 @@ compile_assignable_predicate( bool local, struct apfl_position position, struct apfl_expr_assignable_predicate *predicate, - struct matcher_instruction_list *milist, struct compile_assignable_ilists ilists ) { - size_t index = milist->value_count++; + size_t index = ilists.matcher->value_count++; TRY(compile_expr(compiler, predicate->rhs, ilists.prelude)); TRY(ilist_ensure_cap(compiler, ilists.prelude, 2)); ilist_put_insn(ilists.prelude, INSN_MATCHER_SET_VAL); ilist_put_index(ilists.prelude, index); - TRY(milist_ensure_cap(compiler, milist, 2)); - milist_put_insn(milist, MATCHER_CHECK_PRED); - milist_put_index(milist, index); + TRY(milist_ensure_cap(compiler, ilists.matcher, 2)); + milist_put_insn(ilists.matcher, MATCHER_CHECK_PRED); + milist_put_index(ilists.matcher, index); - return compile_assignable(compiler, local, position, predicate->lhs, milist, ilists); + return compile_assignable(compiler, local, position, predicate->lhs, ilists); } static bool @@ -417,7 +431,6 @@ compile_assignable_list_expand( bool local, struct apfl_position position, struct apfl_expr_assignable_list *list, - struct matcher_instruction_list *milist, struct compile_assignable_ilists ilists, size_t expand_at ) { @@ -425,8 +438,8 @@ compile_assignable_list_expand( struct apfl_expr_assignable_list_item *expand_item = &list->items[expand_at]; assert(expand_item->expand); - TRY(milist_ensure_cap(compiler, milist, 1)); - milist_put_insn(milist, MATCHER_CONTINUE_FROM_END); + TRY(milist_ensure_cap(compiler, ilists.matcher, 1)); + milist_put_insn(ilists.matcher, MATCHER_CONTINUE_FROM_END); for (size_t i = list->len; i-- > expand_at+1; ) { struct apfl_expr_assignable_list_item *item = &list->items[i]; @@ -439,13 +452,13 @@ compile_assignable_list_expand( return false; } - TRY(compile_assignable(compiler, local, position, &item->assignable, milist, ilists)); + TRY(compile_assignable(compiler, local, position, &item->assignable, ilists)); } - TRY(milist_ensure_cap(compiler, milist, 1)); - milist_put_insn(milist, MATCHER_REMAINDING); + TRY(milist_ensure_cap(compiler, ilists.matcher, 1)); + milist_put_insn(ilists.matcher, MATCHER_REMAINDING); - TRY(compile_assignable(compiler, local, position, &expand_item->assignable, milist, ilists)); + TRY(compile_assignable(compiler, local, position, &expand_item->assignable, ilists)); return true; } @@ -456,11 +469,10 @@ compile_assignable_list( bool local, struct apfl_position position, struct apfl_expr_assignable_list *list, - struct matcher_instruction_list *milist, struct compile_assignable_ilists ilists ) { - TRY(milist_ensure_cap(compiler, milist, 1)); - milist_put_insn(milist, MATCHER_ENTER_LIST); + TRY(milist_ensure_cap(compiler, ilists.matcher, 1)); + milist_put_insn(ilists.matcher, MATCHER_ENTER_LIST); for (size_t i = 0; i < list->len; i++) { struct apfl_expr_assignable_list_item *item = &list->items[i]; @@ -471,17 +483,16 @@ compile_assignable_list( local, position, list, - milist, ilists, i ); } - TRY(compile_assignable(compiler, local, position, &item->assignable, milist, ilists)); + TRY(compile_assignable(compiler, local, position, &item->assignable, ilists)); } - TRY(milist_ensure_cap(compiler, milist, 1)); - milist_put_insn(milist, MATCHER_LEAVE_LIST); + TRY(milist_ensure_cap(compiler, ilists.matcher, 1)); + milist_put_insn(ilists.matcher, MATCHER_LEAVE_LIST); return true; } @@ -491,21 +502,20 @@ compile_assignable( bool local, struct apfl_position position, struct apfl_expr_assignable *assignable, - struct matcher_instruction_list *milist, struct compile_assignable_ilists ilists ) { switch (assignable->type) { case APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER: - return compile_assignable_var_or_member(compiler, local, &assignable->var_or_member, milist, ilists); + return compile_assignable_var_or_member(compiler, local, &assignable->var_or_member, ilists); case APFL_EXPR_ASSIGNABLE_CONSTANT: - return compile_assignable_constant(compiler, &assignable->constant, milist, ilists); + return compile_assignable_constant(compiler, &assignable->constant, ilists); case APFL_EXPR_ASSIGNABLE_PREDICATE: - return compile_assignable_predicate(compiler, local, position, &assignable->predicate, milist, ilists); + return compile_assignable_predicate(compiler, local, position, &assignable->predicate, ilists); case APFL_EXPR_ASSIGNABLE_LIST: - return compile_assignable_list(compiler, local, position, &assignable->list, milist, ilists); + return compile_assignable_list(compiler, local, position, &assignable->list, ilists); case APFL_EXPR_ASSIGNABLE_BLANK: - TRY(milist_ensure_cap(compiler, milist, 1)); - milist_put_insn(milist, MATCHER_IGNORE); + TRY(milist_ensure_cap(compiler, ilists.matcher, 1)); + milist_put_insn(ilists.matcher, MATCHER_IGNORE); return true; } @@ -547,23 +557,18 @@ compile_complex_assignment( TRY(ilist_ensure_cap(compiler, ilist, 2)); - struct matcher_instruction_list *milist; - if ((milist = apfl_matcher_instructions_new(compiler->gc)) == NULL) { - compiler->error = apfl_error_simple(APFL_ERR_MALLOC_FAILED); - return false; - } - - ilist_put_insn(ilist, INSN_MATCHER_LOAD); - ilist_put_matcher(ilist, milist); - struct compile_assignable_ilists ilists = { .prelude = ilist, }; + MALLOC_FAIL_IF_NULL(compiler, (ilists.matcher = tmp_milist(compiler))); MALLOC_FAIL_IF_NULL(compiler, (ilists.newvars = tmp_ilist(compiler, position.line))); MALLOC_FAIL_IF_NULL(compiler, (ilists.setvars = tmp_ilist(compiler, position.line))); - TRY(compile_assignable(compiler, assignment->local, position, &assignment->lhs, milist, ilists)); + ilist_put_insn(ilist, INSN_MATCHER_LOAD); + ilist_put_matcher(ilist, ilists.matcher); + + TRY(compile_assignable(compiler, assignment->local, position, &assignment->lhs, ilists)); TRY(concat_ilists(compiler, ilist, ilists.newvars));