diff --git a/hawk/lib/parse.c b/hawk/lib/parse.c index 158bdfe6..bb65321b 100644 --- a/hawk/lib/parse.c +++ b/hawk/lib/parse.c @@ -1708,9 +1708,9 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop) { hawk_nde_t* head, * curr, * nde; hawk_nde_blk_t* block; - hawk_oow_t nlcls, nlcls_max, tmp; + hawk_oow_t nlcls_outer, nlcls_max, tmp; - nlcls = HAWK_ARR_SIZE(hawk->parse.lcls); + nlcls_outer = HAWK_ARR_SIZE(hawk->parse.lcls); nlcls_max = hawk->parse.nlcls_max; /* local variable declarations */ @@ -1750,13 +1750,13 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop) /* @local ... */ if (get_token(hawk) <= -1) { - hawk_arr_delete (hawk->parse.lcls, nlcls, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls); + hawk_arr_delete (hawk->parse.lcls, nlcls_outer, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls_outer); return HAWK_NULL; } - if (collect_locals(hawk, nlcls, istop) == HAWK_NULL) + if (collect_locals(hawk, nlcls_outer, istop) == HAWK_NULL) { - hawk_arr_delete (hawk->parse.lcls, nlcls, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls); + hawk_arr_delete (hawk->parse.lcls, nlcls_outer, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls_outer); return HAWK_NULL; } } @@ -1777,7 +1777,7 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop) /* if EOF is met before the right brace, this is an error */ if (MATCH(hawk,TOK_EOF)) { - hawk_arr_delete (hawk->parse.lcls, nlcls, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls); + hawk_arr_delete (hawk->parse.lcls, nlcls_outer, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls_outer); if (head) hawk_clrpt (hawk, head); hawk_seterrnum (hawk, &hawk->tok.loc, HAWK_EEOF); return HAWK_NULL; @@ -1788,7 +1788,7 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop) { if (get_token(hawk) <= -1) { - hawk_arr_delete (hawk->parse.lcls, nlcls, HAWK_ARR_SIZE(hawk->parse.lcls)-nlcls); + hawk_arr_delete (hawk->parse.lcls, nlcls_outer, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls_outer); if (head) hawk_clrpt (hawk, head); return HAWK_NULL; } @@ -1829,7 +1829,7 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop) if (HAWK_UNLIKELY(!nde)) { - hawk_arr_delete (hawk->parse.lcls, nlcls, HAWK_ARR_SIZE(hawk->parse.lcls)-nlcls); + hawk_arr_delete (hawk->parse.lcls, nlcls_outer, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls_outer); if (head) hawk_clrpt (hawk, head); return HAWK_NULL; } @@ -1856,7 +1856,7 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop) block = (hawk_nde_blk_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*block)); if (HAWK_UNLIKELY(!block)) { - hawk_arr_delete (hawk->parse.lcls, nlcls, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls); + hawk_arr_delete (hawk->parse.lcls, nlcls_outer, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls_outer); hawk_clrpt (hawk, head); ADJERR_LOC (hawk, xloc); return HAWK_NULL; @@ -1866,7 +1866,7 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop) if (tmp > hawk->parse.nlcls_max) hawk->parse.nlcls_max = tmp; /* remove all lcls to move them up to the top level */ - hawk_arr_delete (hawk->parse.lcls, nlcls, tmp - nlcls); + hawk_arr_delete (hawk->parse.lcls, nlcls_outer, tmp - nlcls_outer); /* adjust the number of lcls for a block without any statements */ /* if (head == HAWK_NULL) tmp = 0; */ @@ -1875,21 +1875,29 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop) block->loc = *xloc; block->body = head; + block->org_nlcls = tmp - nlcls_outer; /* number of locals defined in this block */ + block->outer_nlcls = nlcls_outer; /* number of locals defined in outer blocks */ + +#if 1 /* TODO: not only local variables but also nested blocks, unless it is part of other constructs such as if, can be promoted and merged to top-level block */ - /* migrate all block-local variables to a top-level block */ + /* migrate all block-local variables to the outermost block */ if (istop) { - block->nlcls = hawk->parse.nlcls_max - nlcls; - hawk->parse.nlcls_max = nlcls_max; + HAWK_ASSERT (nlcls_outer == 0 && nlcls_max == 0); + block->nlcls = hawk->parse.nlcls_max - nlcls_outer; + hawk->parse.nlcls_max = nlcls_max; /* restore */ } else { - /*block->nlcls = tmp - nlcls;*/ block->nlcls = 0; } +#else + /* no migration */ + block->nlcls = block->org_nlcls; +#endif return (hawk_nde_t*)block; } @@ -7113,6 +7121,7 @@ static int deparse (hawk_t* hawk) if (hawk_putsrcoochars(hawk, kw.ptr, kw.len) <= -1) EXIT_DEPARSE (); if (hawk_putsrcoocstr(hawk, HAWK_T(" ")) <= -1) EXIT_DEPARSE (); + if (hawk_prnnde(hawk, nde) <= -1) EXIT_DEPARSE (); if (hawk->opt.trait & HAWK_CRLF) @@ -7124,7 +7133,7 @@ static int deparse (hawk_t* hawk) } chain = hawk->tree.chain; - while (chain != HAWK_NULL) + while (chain) { if (chain->pattern != HAWK_NULL) { @@ -7143,7 +7152,7 @@ static int deparse (hawk_t* hawk) } else { - if (chain->pattern != HAWK_NULL) + if (chain->pattern) { if (put_char(hawk, HAWK_T(' ')) <= -1) EXIT_DEPARSE (); } @@ -7168,6 +7177,7 @@ static int deparse (hawk_t* hawk) if (hawk_putsrcoochars(hawk, kw.ptr, kw.len) <= -1) EXIT_DEPARSE (); if (hawk_putsrcoocstr(hawk, HAWK_T(" ")) <= -1) EXIT_DEPARSE (); + if (hawk_prnnde(hawk, nde) <= -1) EXIT_DEPARSE (); /* diff --git a/hawk/lib/run.c b/hawk/lib/run.c index 6317c06c..9634e94a 100644 --- a/hawk/lib/run.c +++ b/hawk/lib/run.c @@ -2093,35 +2093,60 @@ static HAWK_INLINE int run_block0 (hawk_rtx_t* rtx, hawk_nde_blk_t* nde) } HAWK_ASSERT (nde->type == HAWK_NDE_BLK); - - p = nde->body; - nlcls = nde->nlcls; - -#if defined(DEBUG_RUN) - hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("securing space for local variables nlcls = %d\n"), (int)nlcls); -#endif - - /* secure space for local variables */ - if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < nlcls)) - { - hawk_rtx_seterrnum (rtx, &nde->loc, HAWK_ESTACK); - return -1; - } - saved_stack_top = rtx->stack_top; - while (nlcls > 0) +#if defined(DEBUG_RUN) + hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("securing space for local variables nlcls = %d\n"), (int)nde->nlcls); +#endif + + if (nde->nlcls > 0) { - --nlcls; - HAWK_RTX_STACK_PUSH (rtx, hawk_val_nil); - /* refupval is not required for hawk_val_nil */ + hawk_oow_t tmp = nde->nlcls; + + /* ensure sufficient space for local variables */ + if (HAWK_UNLIKELY(HAWK_RTX_STACK_AVAIL(rtx) < tmp)) + { + hawk_rtx_seterrnum (rtx, &nde->loc, HAWK_ESTACK); + return -1; + } + + do + { + --tmp; + HAWK_RTX_STACK_PUSH (rtx, hawk_val_nil); + /* refupval is not required for hawk_val_nil */ + } + while (tmp > 0); + } + else if (nde->nlcls != nde->org_nlcls) + { + /* this part can be reached if: + * - the block is nested + * - the block declares local variables + * - the local variables have been migrated to the outer-most block by the parser. + * + * if the parser skips migrations, this part isn't reached but the normal push/pop + * will take place for a nested block with local variable declaration. + */ + hawk_oow_t tmp, end; + + /* when the outer-most block has been entered, the space large enough for all local + * variables defined has been secured. nullify part of the stack to initialze local + * variables defined for a nested block */ + end = nde->outer_nlcls + nde->org_nlcls; + for (tmp = nde->outer_nlcls; tmp < end; tmp++) + { + hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_LCL(rtx, tmp)); + HAWK_RTX_STACK_LCL(rtx, tmp) = hawk_val_nil; + } } #if defined(DEBUG_RUN) hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("executing block statements\n")); #endif - while (p != HAWK_NULL && rtx->exit_level == EXIT_NONE) + p = nde->body; + while (p && rtx->exit_level == EXIT_NONE) { if (HAWK_UNLIKELY(run_statement(rtx, p) <= -1)) { @@ -2135,12 +2160,18 @@ static HAWK_INLINE int run_block0 (hawk_rtx_t* rtx, hawk_nde_blk_t* nde) #if defined(DEBUG_RUN) hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("popping off local variables\n")); #endif - nlcls = nde->nlcls; - while (nlcls > 0) + + if (nde->nlcls > 0) { - --nlcls; - hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_LCL(rtx, nlcls)); - HAWK_RTX_STACK_POP (rtx); + hawk_oow_t tmp = nde->nlcls; + + do + { + --tmp; + hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_LCL(rtx, tmp)); + HAWK_RTX_STACK_POP (rtx); + } + while (tmp > 0); } return n; @@ -6206,7 +6237,7 @@ static hawk_val_t* eval_fncall_var (hawk_rtx_t* rtx, hawk_nde_t* nde) ADJERR_LOC (rtx, &nde->loc); rv = HAWK_NULL; } - else if (call->nargs > fun->nargs) + else if (call->nargs > fun->nargs) { /* TODO: is this correct? what if i want to * allow arbitarary numbers of arguments? */ diff --git a/hawk/lib/std.c b/hawk/lib/std.c index 35d566ae..8614389e 100644 --- a/hawk/lib/std.c +++ b/hawk/lib/std.c @@ -729,7 +729,10 @@ static void log_write (hawk_t* hawk, hawk_bitmask_t mask, const hawk_ooch_t* msg { logfd = xtn->log.fd; #if !defined(EMSCRIPTEN) - if (logfd <= -1) return; + if (logfd <= -1) + { + return; + } #endif } diff --git a/hawk/lib/tree-prv.h b/hawk/lib/tree-prv.h index 4335a530..ac8d5cf6 100644 --- a/hawk/lib/tree-prv.h +++ b/hawk/lib/tree-prv.h @@ -88,6 +88,8 @@ struct hawk_nde_blk_t { HAWK_NDE_HDR; hawk_oow_t nlcls; /* number of local variables */ + hawk_oow_t org_nlcls; /* the original number of local variables before pushing to the top-level block */ + hawk_oow_t outer_nlcls; /* the number of local variables in the outer blocks accumulated */ hawk_nde_t* body; }; diff --git a/hawk/lib/tree.c b/hawk/lib/tree.c index ac21bc40..af28f73e 100644 --- a/hawk/lib/tree.c +++ b/hawk/lib/tree.c @@ -638,6 +638,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde) break; } + case HAWK_NDE_LCL: { hawk_oow_t n; @@ -834,7 +835,7 @@ static int print_stmt (hawk_t* hawk, hawk_nde_t* p, int depth) PUT_SRCSTR (hawk, HAWK_T("{")); PUT_NL (hawk); - if (px->nlcls > 0) + if (px->org_nlcls > 0) { PRINT_TABS (hawk, depth + 1); @@ -842,16 +843,18 @@ static int print_stmt (hawk_t* hawk, hawk_nde_t* p, int depth) PUT_SRCSTRN (hawk, kw.ptr, kw.len); PUT_SRCSTR (hawk, HAWK_T(" ")); - for (i = 0; i < px->nlcls - 1; i++) + /* though the parser pushed up all local variables to the outer-most level, + * the code here restores the original declarations with org_nlcls and prv_nlcls */ + for (i = 0; i < px->org_nlcls - 1; i++) { PUT_SRCSTR (hawk, HAWK_T("__l")); - n = hawk_int_to_oocstr(i, 10, HAWK_NULL, hawk->tmp.fmt, HAWK_COUNTOF(hawk->tmp.fmt)); + n = hawk_int_to_oocstr(px->outer_nlcls + i, 10, HAWK_NULL, hawk->tmp.fmt, HAWK_COUNTOF(hawk->tmp.fmt)); PUT_SRCSTRN (hawk, hawk->tmp.fmt, n); PUT_SRCSTR (hawk, HAWK_T(", ")); } PUT_SRCSTR (hawk, HAWK_T("__l")); - n = hawk_int_to_oocstr(i, 10, HAWK_NULL, hawk->tmp.fmt, HAWK_COUNTOF(hawk->tmp.fmt)); + n = hawk_int_to_oocstr(px->outer_nlcls + i, 10, HAWK_NULL, hawk->tmp.fmt, HAWK_COUNTOF(hawk->tmp.fmt)); PUT_SRCSTRN (hawk, hawk->tmp.fmt, n); PUT_SRCSTR (hawk, HAWK_T(";")); PUT_NL (hawk); @@ -1148,7 +1151,7 @@ static int print_stmts (hawk_t* hawk, hawk_nde_t* tree, int depth) while (p) { - if (print_stmt(hawk, p, depth) == -1) return -1; + if (print_stmt(hawk, p, depth) <= -1) return -1; p = p->next; } @@ -1171,8 +1174,8 @@ int hawk_prnptnpt (hawk_t* hawk, hawk_nde_t* tree) while (nde) { - if (print_expr (hawk, nde) == -1) return -1; - if (nde->next == HAWK_NULL) break; + if (print_expr(hawk, nde) <= -1) return -1; + if (!nde->next) break; PUT_SRCSTR (hawk, HAWK_T(",")); nde = nde->next; diff --git a/hawk/t/h-002.hawk b/hawk/t/h-002.hawk index 9fd737ed..f016715a 100644 --- a/hawk/t/h-002.hawk +++ b/hawk/t/h-002.hawk @@ -244,7 +244,8 @@ function main() { @local bool, b, c; - c = @nil; + ensure ((c === @nil), 1, @SCRIPTNAME, @SCRIPTLINE); ## ensure local variable initialization + bool = ((b = 1) in c); ensure (bool, 0, @SCRIPTNAME, @SCRIPTLINE); ensure (b, 1, @SCRIPTNAME, @SCRIPTLINE);