From f8607988210b718fb6fd31f66dff104d6bbe7637 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Fri, 24 Apr 2020 15:52:08 +0000 Subject: [PATCH] Added partial code for array support --- hawk/lib/arr.c | 4 +- hawk/lib/err.c | 5 + hawk/lib/fnc.c | 6 +- hawk/lib/hawk-cmn.h | 5 + hawk/lib/hawk.h | 20 +- hawk/lib/run.c | 646 ++++++++++++++++++++++++++++---------------- hawk/lib/val.c | 138 +++++++--- 7 files changed, 552 insertions(+), 272 deletions(-) diff --git a/hawk/lib/arr.c b/hawk/lib/arr.c index 665d7a1e..10fbf65d 100644 --- a/hawk/lib/arr.c +++ b/hawk/lib/arr.c @@ -485,9 +485,9 @@ hawk_oow_t hawk_arr_walk (hawk_arr_t* arr, walker_t walker, void* ctx) while (1) { - if (arr->slot[i] != HAWK_NULL) + if (arr->slot[i]) { - w = walker (arr, i, ctx); + w = walker(arr, i, ctx); nwalks++; } diff --git a/hawk/lib/err.c b/hawk/lib/err.c index e7170e49..4c725cc3 100644 --- a/hawk/lib/err.c +++ b/hawk/lib/err.c @@ -153,6 +153,11 @@ const hawk_ooch_t* hawk_dfl_errstr (hawk_errnum_t errnum) HAWK_T("invalid value to convert to a number"), HAWK_T("invalid value to a character"), HAWK_T("invalid value for hashing"), + HAWK_T("cannot return an array"), /* EARRRET */ + HAWK_T("cannot assign an array to a positional"), /* EARRTOPOS */ + HAWK_T("cannot assign an array to an indexed variable"),/* EARRTOIDX */ + HAWK_T("array index out of allowed range"), + HAWK_T("single-bracketed multidimensional array indices not allowed"), HAWK_T("'next' called from BEGIN block"), HAWK_T("'next' called from END block"), HAWK_T("'nextfile' called from BEGIN block"), diff --git a/hawk/lib/fnc.c b/hawk/lib/fnc.c index 92633a3c..6a2733d1 100644 --- a/hawk/lib/fnc.c +++ b/hawk/lib/fnc.c @@ -704,7 +704,11 @@ int hawk_fnc_length (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) { case HAWK_VAL_MAP: /* map size */ - len = HAWK_HTB_SIZE(((hawk_val_map_t*)v)->map); + len = HAWK_MAP_SIZE(((hawk_val_map_t*)v)->map); + break; + + case HAWK_VAL_ARR: + len = HAWK_ARR_SIZE(((hawk_val_arr_t*)v)->arr); break; case HAWK_VAL_STR: diff --git a/hawk/lib/hawk-cmn.h b/hawk/lib/hawk-cmn.h index 2e9bad10..efebc40f 100644 --- a/hawk/lib/hawk-cmn.h +++ b/hawk/lib/hawk-cmn.h @@ -988,6 +988,11 @@ enum hawk_errnum_t HAWK_EVALTONUM, /**< invalid value to convert to a number */ HAWK_EVALTOCHR, /**< invalid value to convert to a character */ HAWK_EHASHVAL, /**< invalid value to hash */ + HAWK_EARRRET, /**< array cannot be returned */ + HAWK_EARRTOPOS, /**< array cannot be assigned to a positional */ + HAWK_EARRTOIDX, /**< array cannot be assigned to an indexed variable */ + HAWK_EARRIDXRANGE, /**< disallowed array index range */ + HAWK_EARRIDXMULTI, /**< single-bracketed multidimensional array indices not allowed */ HAWK_ERNEXTBEG, /**< 'next' called from BEGIN block */ HAWK_ERNEXTEND, /**< 'next' called from END block */ HAWK_ERNEXTFBEG, /**< 'nextfile' called from BEGIN block */ diff --git a/hawk/lib/hawk.h b/hawk/lib/hawk.h index 84476fbe..c6b449cf 100644 --- a/hawk/lib/hawk.h +++ b/hawk/lib/hawk.h @@ -465,7 +465,7 @@ struct hawk_fun_t hawk_oocs_t name; hawk_oow_t nargs; hawk_ooch_t* argspec; /* similar to the argument spec of hawk_fnc_arg_t. supports v & r only. */ - hawk_nde_t* body; + hawk_nde_t* body; }; typedef struct hawk_fun_t hawk_fun_t; @@ -530,29 +530,29 @@ typedef void (*hawk_log_write_t) ( #if 0 typedef void* (*hawk_buildrex_t) ( - hawk_t* hawk, + hawk_t* hawk, const hawk_ooch_t* ptn, - hawk_oow_t len + hawk_oow_t len ); typedef int (*hawk_matchrex_t) ( - hawk_t* hawk, - void* code, - int option, + hawk_t* hawk, + void* code, + int option, const hawk_ooch_t* str, - hawk_oow_t len, + hawk_oow_t len, const hawk_ooch_t** mptr, - hawk_oow_t* mlen + hawk_oow_t* mlen ); typedef void (*hawk_freerex_t) ( hawk_t* hawk, - void* code + void* code ); typedef int (*hawk_isemptyrex_t) ( hawk_t* hawk, - void* code + void* code ); #endif diff --git a/hawk/lib/run.c b/hawk/lib/run.c index b431beda..13151700 100644 --- a/hawk/lib/run.c +++ b/hawk/lib/run.c @@ -200,6 +200,7 @@ static hawk_val_t* eval_printf (hawk_rtx_t* rtx, hawk_nde_t* nde); static int read_record (hawk_rtx_t* rtx); static hawk_ooch_t* idxnde_to_str (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_ooch_t* buf, hawk_oow_t* len, hawk_nde_t** remidx); +static hawk_ooi_t idxnde_to_int (hawk_rtx_t* rtx, hawk_nde_t* nde); typedef hawk_val_t* (*binop_func_t) (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right); typedef hawk_val_t* (*eval_expr_t) (hawk_rtx_t* rtx, hawk_nde_t* nde); @@ -288,7 +289,7 @@ static int set_global (hawk_rtx_t* rtx, int idx, hawk_nde_var_t* var, hawk_val_t errfmt = HAWK_T("not allowed to change a map '%.*js' to a scalar"); } } - + if (errnum != HAWK_ENOERR) { /* once a variable becomes a map, it cannot be assigned @@ -2480,11 +2481,8 @@ static int run_forin (hawk_rtx_t* rtx, hawk_nde_forin_t* nde) { hawk_nde_exp_t* test; hawk_val_t* rv; - hawk_map_t* map = HAWK_NULL; - hawk_map_pair_t* pair; - hawk_map_itr_t itr; hawk_val_type_t rvtype; - hawk_oow_t old_forin_size, i; + int ret; test = (hawk_nde_exp_t*)nde->test; @@ -2500,89 +2498,182 @@ static int run_forin (hawk_rtx_t* rtx, hawk_nde_forin_t* nde) hawk_rtx_refupval (rtx, rv); rvtype = HAWK_RTX_GETVALTYPE(rtx, rv); - if (rvtype == HAWK_VAL_NIL) + switch (rvtype) { - /* just return without excuting the loop body */ - goto done1; - } - else if (rvtype != HAWK_VAL_MAP) - { - hawk_rtx_seterrnum (rtx, &test->right->loc, HAWK_ENOTMAPIN); - ret = -1; - goto done1; - } + case HAWK_VAL_NIL: + /* just return without excuting the loop body */ + goto done1; - map = ((hawk_val_map_t*)rv)->map; - - old_forin_size = rtx->forin.size; - if (rtx->forin.capa - rtx->forin.size < hawk_map_getsize(map)) - { - hawk_val_t** tmp; - hawk_oow_t newcapa; - - newcapa = rtx->forin.size + hawk_map_getsize(map); - newcapa = HAWK_ALIGN_POW2(newcapa, 128); - tmp = hawk_rtx_reallocmem(rtx, rtx->forin.ptr, newcapa * HAWK_SIZEOF(*tmp)); - if (HAWK_UNLIKELY(!tmp)) + case HAWK_VAL_MAP: { - ADJERR_LOC (rtx, &test->left->loc); + hawk_map_t* map; + hawk_map_pair_t* pair; + hawk_map_itr_t itr; + hawk_oow_t old_forin_size, i; + + map = ((hawk_val_map_t*)rv)->map; + + old_forin_size = rtx->forin.size; + if (rtx->forin.capa - rtx->forin.size < hawk_map_getsize(map)) + { + hawk_val_t** tmp; + hawk_oow_t newcapa; + + newcapa = rtx->forin.size + hawk_map_getsize(map); + newcapa = HAWK_ALIGN_POW2(newcapa, 128); + tmp = hawk_rtx_reallocmem(rtx, rtx->forin.ptr, newcapa * HAWK_SIZEOF(*tmp)); + if (HAWK_UNLIKELY(!tmp)) + { + ADJERR_LOC (rtx, &test->left->loc); + ret = -1; + goto done2; + } + + rtx->forin.ptr = tmp; + rtx->forin.capa = newcapa; + } + + /* take a snapshot of the keys first so that the actual pairs become mutation safe + * this proctection is needed in case the body contains destructive statements like 'delete' or '@reset'*/ + hawk_init_map_itr (&itr, 0); + pair = hawk_map_getfirstpair(map, &itr); + while (pair) + { + hawk_val_t* str; + + str = (hawk_val_t*)hawk_rtx_makenstrvalwithoochars(rtx, HAWK_HTB_KPTR(pair), HAWK_HTB_KLEN(pair)); + if (HAWK_UNLIKELY(!str)) + { + ADJERR_LOC (rtx, &test->left->loc); + ret = -1; + goto done2; + } + + rtx->forin.ptr[rtx->forin.size++] = str; + hawk_rtx_refupval (rtx, str); + + pair = hawk_map_getnextpair(map, &itr); + } + + /* iterate over the keys in the snapshot */ + for (i = old_forin_size; i < rtx->forin.size; i++) + { + if (HAWK_UNLIKELY(!do_assignment(rtx, test->left, rtx->forin.ptr[i])) || HAWK_UNLIKELY(run_statement(rtx, nde->body) <= -1)) + { + ret = -1; + goto done2; + } + + if (rtx->exit_level == EXIT_BREAK) + { + rtx->exit_level = EXIT_NONE; + goto done2; + } + else if (rtx->exit_level == EXIT_CONTINUE) + { + rtx->exit_level = EXIT_NONE; + } + else if (rtx->exit_level != EXIT_NONE) + { + goto done2; + } + } + + done2: + while (rtx->forin.size > old_forin_size) + hawk_rtx_refdownval (rtx, rtx->forin.ptr[--rtx->forin.size]); + + break; + } + + case HAWK_VAL_ARR: + { + hawk_arr_t* arr; + hawk_oow_t arr_size; + hawk_oow_t old_forin_size, i; + + arr = ((hawk_val_arr_t*)rv)->arr; + arr_size = HAWK_ARR_SIZE(arr); + + old_forin_size = rtx->forin.size; + if (rtx->forin.capa - rtx->forin.size < hawk_arr_getsize(arr)) + { + hawk_val_t** tmp; + hawk_oow_t newcapa; + + newcapa = rtx->forin.size + hawk_arr_getsize(arr); + newcapa = HAWK_ALIGN_POW2(newcapa, 128); + tmp = hawk_rtx_reallocmem(rtx, rtx->forin.ptr, newcapa * HAWK_SIZEOF(*tmp)); + if (HAWK_UNLIKELY(!tmp)) + { + ADJERR_LOC (rtx, &test->left->loc); + ret = -1; + goto done3; + } + + rtx->forin.ptr = tmp; + rtx->forin.capa = newcapa; + } + + /* take a snapshot of the keys first so that the actual pairs become mutation safe + * this proctection is needed in case the body contains destructive statements like 'delete' or '@reset'. + * besides, there can be empty slots. after a[1] = 20; a[9] = 30;, a[2], a[3], etc are empty. */ + for (i = 0; i < arr_size; i++) + { + if (HAWK_ARR_SLOT(arr, i)) + { + hawk_val_t* tmp; + + tmp = (hawk_val_t*)hawk_rtx_makeintval(rtx, i); + if (HAWK_UNLIKELY(!tmp)) + { + ADJERR_LOC (rtx, &test->left->loc); + ret = -1; + goto done3; + } + + rtx->forin.ptr[rtx->forin.size++] = tmp; + hawk_rtx_refupval (rtx, tmp); + } + } + + /* iterate over the keys in the snapshot */ + for (i = old_forin_size; i < rtx->forin.size; i++) + { + if (HAWK_UNLIKELY(!do_assignment(rtx, test->left, rtx->forin.ptr[i])) || HAWK_UNLIKELY(run_statement(rtx, nde->body) <= -1)) + { + ret = -1; + goto done3; + } + + if (rtx->exit_level == EXIT_BREAK) + { + rtx->exit_level = EXIT_NONE; + goto done3; + } + else if (rtx->exit_level == EXIT_CONTINUE) + { + rtx->exit_level = EXIT_NONE; + } + else if (rtx->exit_level != EXIT_NONE) + { + goto done3; + } + } + + done3: + while (rtx->forin.size > old_forin_size) + hawk_rtx_refdownval (rtx, rtx->forin.ptr[--rtx->forin.size]); + + break; + } + + default: + hawk_rtx_seterrnum (rtx, &test->right->loc, HAWK_ENOTMAPIN); ret = -1; - goto done2; - } - - rtx->forin.ptr = tmp; - rtx->forin.capa = newcapa; + goto done1; } - /* take a snapshot of the keys first so that the actual pairs become mutation safe - * this proctection is needed in case the body contains destructive statements like 'delete' or '@reset'*/ - hawk_init_map_itr (&itr, 0); - pair = hawk_map_getfirstpair(map, &itr); - while (pair) - { - hawk_val_t* str; - - str = (hawk_val_t*)hawk_rtx_makenstrvalwithoochars(rtx, HAWK_HTB_KPTR(pair), HAWK_HTB_KLEN(pair)); - if (HAWK_UNLIKELY(!str)) - { - ADJERR_LOC (rtx, &test->left->loc); - ret = -1; - goto done2; - } - - rtx->forin.ptr[rtx->forin.size++] = str; - hawk_rtx_refupval (rtx, str); - - pair = hawk_map_getnextpair(map, &itr); - } - - /* iterate over the keys in the snapshot */ - for (i = old_forin_size; i < rtx->forin.size; i++) - { - if (HAWK_UNLIKELY(!do_assignment(rtx, test->left, rtx->forin.ptr[i])) || HAWK_UNLIKELY(run_statement(rtx, nde->body) <= -1)) - { - ret = -1; - goto done2; - } - - if (rtx->exit_level == EXIT_BREAK) - { - rtx->exit_level = EXIT_NONE; - goto done2; - } - else if (rtx->exit_level == EXIT_CONTINUE) - { - rtx->exit_level = EXIT_NONE; - } - else if (rtx->exit_level != EXIT_NONE) - { - goto done2; - } - } - -done2: - while (rtx->forin.size > old_forin_size) - hawk_rtx_refdownval (rtx, rtx->forin.ptr[--rtx->forin.size]); done1: hawk_rtx_refdownval (rtx, rv); @@ -2616,7 +2707,9 @@ static int run_return (hawk_rtx_t* rtx, hawk_nde_return_t* nde) if (!(rtx->hawk->opt.trait & HAWK_FLEXMAP)) { - if (HAWK_RTX_GETVALTYPE(rtx, val) == HAWK_VAL_MAP) + hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE(rtx, val); + + if (vtype == HAWK_VAL_MAP) { /* cannot return a map */ hawk_rtx_refupval (rtx, val); @@ -2624,6 +2717,13 @@ static int run_return (hawk_rtx_t* rtx, hawk_nde_return_t* nde) hawk_rtx_seterrnum (rtx, &nde->loc, HAWK_EMAPRET); return -1; } + else if (vtype == HAWK_VAL_ARR) + { + hawk_rtx_refupval (rtx, val); + hawk_rtx_refdownval (rtx, val); + hawk_rtx_seterrnum (rtx, &nde->loc, HAWK_EARRRET); + return -1; + } } hawk_rtx_refdownval (rtx, HAWK_RTX_STACK_RETVAL(rtx)); @@ -2825,6 +2925,7 @@ static hawk_val_t* assign_topval_to_var (hawk_rtx_t* rtx, hawk_nde_var_t* var, h if (HAWK_UNLIKELY(hawk_htb_upsert(rtx->named, var->id.name.ptr, var->id.name.len, val, 0) == HAWK_NULL)) { hawk_rtx_refdownval (rtx, val); + ADJERR_LOC (rtx, &var->loc); return HAWK_NULL; } break; @@ -2838,7 +2939,11 @@ static hawk_val_t* assign_topval_to_var (hawk_rtx_t* rtx, hawk_nde_var_t* var, h hawk_rtx_refupval (rtx, val); x = hawk_rtx_setgbl(rtx, (int)var->id.idxa, val); hawk_rtx_refdownval (rtx, val); - if (HAWK_UNLIKELY(x <= -1)) return HAWK_NULL; + if (HAWK_UNLIKELY(x <= -1)) + { + ADJERR_LOC (rtx, &var->loc); + return HAWK_NULL; + } break; } @@ -2874,9 +2979,13 @@ static hawk_val_t* assign_newmapval_to_var (hawk_rtx_t* rtx, hawk_nde_var_t* var HAWK_ASSERT (var->type >= HAWK_NDE_NAMED && var->type <= HAWK_NDE_ARGIDX); tmp = hawk_rtx_makemapval(rtx); - if (HAWK_UNLIKELY(!tmp)) return HAWK_NULL; + if (HAWK_UNLIKELY(!tmp)) + { + ADJERR_LOC (rtx, &var->loc); + return HAWK_NULL; + } - return assign_topval_to_var (rtx, var, tmp); + return assign_topval_to_var(rtx, var, tmp); } @@ -3644,27 +3753,41 @@ static hawk_val_t* do_assignment (hawk_rtx_t* rtx, hawk_nde_t* var, hawk_val_t* case HAWK_NDE_LCLIDX: case HAWK_NDE_ARGIDX: #if !defined(HAWK_ENABLE_GC) - if (HAWK_RTX_GETVALTYPE(rtx, val) == HAWK_VAL_MAP) + hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE(rtx, val); + if (vtype == HAWK_VAL_MAP) { /* a map cannot become a member of a map */ errnum = HAWK_EMAPTOIDX; goto exit_on_error; } + else if (vtype == HAWK_VAL_ARR) + { + errnum = HAWK_EARRTOIDX; + goto exit_on_error; + } #endif ret = do_assignment_idx(rtx, (hawk_nde_var_t*)var, val); break; case HAWK_NDE_POS: - if (HAWK_RTX_GETVALTYPE(rtx, val) == HAWK_VAL_MAP) + { + hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE(rtx, val); + if (vtype == HAWK_VAL_MAP) { /* a map cannot be assigned to a positional */ errnum = HAWK_EMAPTOPOS; goto exit_on_error; } + else if (vtype == HAWK_VAL_ARR) + { + errnum = HAWK_EARRTOPOS; + goto exit_on_error; + } ret = do_assignment_pos(rtx, (hawk_nde_pos_t*)var, val); break; + } default: HAWK_ASSERT (!"should never happen - invalid variable type"); @@ -3811,10 +3934,6 @@ static hawk_val_t* do_assignment_idx (hawk_rtx_t* rtx, hawk_nde_var_t* var, hawk hawk_map_t* map; hawk_val_t* vv; /* existing value pointed to by var */ hawk_val_type_t vtype; - hawk_ooch_t* str = HAWK_NULL; - hawk_oow_t len; - hawk_ooch_t idxbuf[IDXBUFSIZE]; - hawk_nde_t* remidx; HAWK_ASSERT ( (var->type == HAWK_NDE_NAMEDIDX || @@ -3822,7 +3941,8 @@ static hawk_val_t* do_assignment_idx (hawk_rtx_t* rtx, hawk_nde_var_t* var, hawk var->type == HAWK_NDE_LCLIDX || var->type == HAWK_NDE_ARGIDX) && var->idx != HAWK_NULL); #if !defined(HAWK_ENABLE_GC) - HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, val) != HAWK_VAL_MAP); + HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, val) != HAWK_VAL_MAP && + HAWK_RTX_GETVALTYPE(rtx, val) != HAWK_VAL_ARR); #endif /* check the value that the assigned variable points to */ @@ -3833,12 +3953,106 @@ static hawk_val_t* do_assignment_idx (hawk_rtx_t* rtx, hawk_nde_var_t* var, hawk case HAWK_VAL_NIL: nil_to_map: vv = assign_newmapval_to_var(rtx, var); - if (HAWK_UNLIKELY(!vv)) goto oops; - break; + if (HAWK_UNLIKELY(!vv)) return HAWK_NULL; + /* fall thru */ case HAWK_VAL_MAP: + { + hawk_ooch_t* str = HAWK_NULL; + hawk_oow_t len; + hawk_ooch_t idxbuf[IDXBUFSIZE]; + hawk_nde_t* remidx; + /* nothing to do */ - break; + len = HAWK_COUNTOF(idxbuf); + str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx); + if (HAWK_UNLIKELY(!str)) goto oops_map; + + map = ((hawk_val_map_t*)vv)->map; + + #if defined(HAWK_ENABLE_GC) + while (remidx) + { + hawk_map_pair_t* pair; + + pair = hawk_map_search(map, str, len); + + vv = pair? (hawk_val_t*)HAWK_HTB_VPTR(pair): hawk_val_nil; + vtype = HAWK_RTX_GETVALTYPE(rtx, vv); + + switch (vtype) + { + case HAWK_VAL_NIL: + remidx_nil_to_map: + vv = assign_newmapval_in_map(rtx, map, str, len); + if (HAWK_UNLIKELY(!vv)) goto oops_map; + map = ((hawk_val_map_t*)vv)->map; + break; + + case HAWK_VAL_MAP: + map = ((hawk_val_map_t*)vv)->map; + break; + + default: + if (rtx->hawk->opt.trait & HAWK_FLEXMAP) + { + /* BEGIN { @local a, b; b="hello"; a[1]=b; a[1][2]=20; print a[1][2];} */ + /* BEGIN { a[1]="hello"; a[1][2]=20; print a[1][2]; } */ + /* BEGIN { b="hello"; a[1]=b; a[1][2]=20; print a[1][2]; } */ + + /* well, this is not the first level index. + * the logic is different from the first level where reset_variable is called. + * here it simply creates a new map. */ + goto remidx_nil_to_map; + } + else + { + hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_ESCALARTOMAP, HAWK_T("not allowed to change a nested scalar under '%.*js' to a map"), var->id.name.len, var->id.name.ptr); + goto oops_map; + } + } + + if (str != idxbuf) hawk_rtx_freemem (rtx, str); + len = HAWK_COUNTOF(idxbuf); + str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx); + if (HAWK_UNLIKELY(!str)) goto oops_map; + } + #endif + + #if defined(DEBUG_RUN) + hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("**** index str=>%s, map->ref=%d, map->type=%d\n"), str, (int)v->ref, (int)v->type); + #endif + + if (HAWK_UNLIKELY(hawk_map_upsert(map, str, len, val, 0) == HAWK_NULL)) goto oops_map; + + if (str != idxbuf) hawk_rtx_freemem (rtx, str); + hawk_rtx_refupval (rtx, val); + return val; + + oops_map: + if (str && str != idxbuf) hawk_rtx_freemem (rtx, str); + ADJERR_LOC (rtx, &var->loc); + return HAWK_NULL; + } + + case HAWK_VAL_ARR: + { + /* multiple indeics in a single bracket is not allowed. e.g. x[1,2] not allowed */ + hawk_ooi_t idx; + hawk_arr_t* arr; + + idx = idxnde_to_int(rtx, var->idx); + if (idx <= -1) return HAWK_NULL; + + arr = ((hawk_val_arr_t*)vv)->arr; + if (HAWK_UNLIKELY(hawk_arr_upsert(arr, idx, val, 0) == HAWK_ARR_NIL)) + { + ADJERR_LOC (rtx, &var->loc); + return HAWK_NULL; + } + hawk_rtx_refupval (rtx, val); + return val; + } default: if (rtx->hawk->opt.trait & HAWK_FLEXMAP) @@ -3851,80 +4065,9 @@ static hawk_val_t* do_assignment_idx (hawk_rtx_t* rtx, hawk_nde_var_t* var, hawk /* you can't manipulate a variable pointing to * a scalar value with an index if FLEXMAP is off. */ hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_ESCALARTOMAP, HAWK_T("not allowed to change a scalar '%.*js' to a map"), var->id.name.len, var->id.name.ptr); - goto oops; + return HAWK_NULL; } - break; } - - len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx); - if (HAWK_UNLIKELY(!str)) goto oops; - - map = ((hawk_val_map_t*)vv)->map; - -#if defined(HAWK_ENABLE_GC) - while (remidx) - { - hawk_map_pair_t* pair; - - pair = hawk_map_search(map, str, len); - - vv = pair? (hawk_val_t*)HAWK_HTB_VPTR(pair): hawk_val_nil; - vtype = HAWK_RTX_GETVALTYPE(rtx, vv); - - switch (vtype) - { - case HAWK_VAL_NIL: - remidx_nil_to_map: - vv = assign_newmapval_in_map(rtx, map, str, len); - if (HAWK_UNLIKELY(!vv)) goto oops; - map = ((hawk_val_map_t*)vv)->map; - break; - - case HAWK_VAL_MAP: - map = ((hawk_val_map_t*)vv)->map; - break; - - default: - if (rtx->hawk->opt.trait & HAWK_FLEXMAP) - { - /* BEGIN { @local a, b; b="hello"; a[1]=b; a[1][2]=20; print a[1][2];} */ - /* BEGIN { a[1]="hello"; a[1][2]=20; print a[1][2]; } */ - /* BEGIN { b="hello"; a[1]=b; a[1][2]=20; print a[1][2]; } */ - - /* well, this is not the first level index. - * the logic is different from the first level where reset_variable is called. - * here it simply creates a new map. */ - goto remidx_nil_to_map; - } - else - { - hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_ESCALARTOMAP, HAWK_T("not allowed to change a nested scalar under '%.*js' to a map"), var->id.name.len, var->id.name.ptr); - goto oops; - } - } - - if (str != idxbuf) hawk_rtx_freemem (rtx, str); - len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx); - if (HAWK_UNLIKELY(!str)) goto oops; - } -#endif - -#if defined(DEBUG_RUN) - hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("**** index str=>%s, map->ref=%d, map->type=%d\n"), str, (int)v->ref, (int)v->type); -#endif - - if (HAWK_UNLIKELY(hawk_map_upsert(map, str, len, val, 0) == HAWK_NULL)) goto oops; - - if (str != idxbuf) hawk_rtx_freemem (rtx, str); - hawk_rtx_refupval (rtx, val); - return val; - -oops: - if (str && str != idxbuf) hawk_rtx_freemem (rtx, str); - ADJERR_LOC (rtx, &var->loc); - return HAWK_NULL; } static hawk_val_t* do_assignment_pos (hawk_rtx_t* rtx, hawk_nde_pos_t* pos, hawk_val_t* val) @@ -6694,14 +6837,8 @@ static hawk_val_t* eval_arg (hawk_rtx_t* rtx, hawk_nde_t* nde) static hawk_val_t* eval_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var) { - hawk_map_t* map; /* containing map */ - hawk_map_pair_t* pair; - hawk_ooch_t* str = HAWK_NULL; - hawk_oow_t len; - hawk_ooch_t idxbuf[IDXBUFSIZE]; hawk_val_t* v; hawk_val_type_t vtype; - hawk_nde_t* remidx; v = fetch_topval_from_var(rtx, var); vtype = HAWK_RTX_GETVALTYPE(rtx, v); @@ -6710,66 +6847,84 @@ static hawk_val_t* eval_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var) { case HAWK_VAL_NIL: v = assign_newmapval_to_var(rtx, var); - if (HAWK_UNLIKELY(!v)) goto oops; - break; + if (HAWK_UNLIKELY(!v)) return HAWK_NULL; + /* fall thru */ case HAWK_VAL_MAP: - /* nothing to do */ - break; + { + hawk_map_t* map; /* containing map */ + hawk_map_pair_t* pair; + hawk_ooch_t* str = HAWK_NULL; + hawk_oow_t len; + hawk_ooch_t idxbuf[IDXBUFSIZE]; + hawk_nde_t* remidx; + + HAWK_ASSERT (var->idx != HAWK_NULL); + + len = HAWK_COUNTOF(idxbuf); + str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx); + if (HAWK_UNLIKELY(!str)) goto oops_map; + + map = ((hawk_val_map_t*)v)->map; + pair = hawk_map_search(map, str, len); + + #if defined(HAWK_ENABLE_GC) + while (remidx) + { + v = pair? (hawk_val_t*)HAWK_HTB_VPTR(pair): hawk_val_nil; + vtype = HAWK_RTX_GETVALTYPE(rtx, v); + + switch (vtype) + { + case HAWK_VAL_NIL: + v = assign_newmapval_in_map(rtx, map, str, len); + if (HAWK_UNLIKELY(!v)) goto oops_map; + map = ((hawk_val_map_t*)v)->map; + break; + + case HAWK_VAL_MAP: + map = ((hawk_val_map_t*)v)->map; + break; + + default: + hawk_rtx_seterrnum (rtx, &var->loc, HAWK_ENOTMAP); + goto oops_map; + } + + if (str != idxbuf) hawk_rtx_freemem (rtx, str); + len = HAWK_COUNTOF(idxbuf); + str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx); + if (HAWK_UNLIKELY(!str)) goto oops_map; + + pair = hawk_map_search(map, str, len); + } + #endif + + if (str != idxbuf) hawk_rtx_freemem (rtx, str); + return pair? (hawk_val_t*)HAWK_HTB_VPTR(pair): hawk_val_nil; + + oops_map: + if (str && str != idxbuf) hawk_rtx_freemem (rtx, str); + ADJERR_LOC (rtx, &var->loc); + return HAWK_NULL; + } + + case HAWK_VAL_ARR: + { + hawk_arr_t* arr; /* containing array */ + hawk_ooi_t idx; + + idx = idxnde_to_int(rtx, var->idx); + if (idx <= -1) return HAWK_NULL; + + arr = ((hawk_val_arr_t*)v)->arr; + return HAWK_ARR_SLOT(arr, idx)? ((hawk_val_t*)HAWK_ARR_DPTR(arr, idx)): ((hawk_val_t*)&hawk_val_nil); + } default: hawk_rtx_seterrnum (rtx, &var->loc, HAWK_ENOTMAP); - goto oops; + return HAWK_NULL; } - - HAWK_ASSERT (var->idx != HAWK_NULL); - - len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx); - if (HAWK_UNLIKELY(!str)) goto oops; - - map = ((hawk_val_map_t*)v)->map; - pair = hawk_map_search(map, str, len); - -#if defined(HAWK_ENABLE_GC) - while (remidx) - { - v = pair? (hawk_val_t*)HAWK_HTB_VPTR(pair): hawk_val_nil; - vtype = HAWK_RTX_GETVALTYPE(rtx, v); - - switch (vtype) - { - case HAWK_VAL_NIL: - v = assign_newmapval_in_map(rtx, map, str, len); - if (HAWK_UNLIKELY(!v)) goto oops; - map = ((hawk_val_map_t*)v)->map; - break; - - case HAWK_VAL_MAP: - map = ((hawk_val_map_t*)v)->map; - break; - - default: - hawk_rtx_seterrnum (rtx, &var->loc, HAWK_ENOTMAP); - goto oops; - } - - if (str != idxbuf) hawk_rtx_freemem (rtx, str); - len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx); - if (HAWK_UNLIKELY(!str)) goto oops; - - pair = hawk_map_search(map, str, len); - } -#endif - - if (str != idxbuf) hawk_rtx_freemem (rtx, str); - return pair? (hawk_val_t*)HAWK_HTB_VPTR(pair): hawk_val_nil; - -oops: - if (str && str != idxbuf) hawk_rtx_freemem (rtx, str); - ADJERR_LOC (rtx, &var->loc); - return HAWK_NULL; } static hawk_val_t* eval_namedidx (hawk_rtx_t* rtx, hawk_nde_t* nde) @@ -7225,6 +7380,41 @@ static hawk_ooch_t* idxnde_to_str (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_ooch_t return str; } +static hawk_ooi_t idxnde_to_int (hawk_rtx_t* rtx, hawk_nde_t* nde) +{ + hawk_int_t v; + hawk_val_t* tmp; + int n; + + if (nde->next) + { + /* multidimensional indices inside a single brakcet is not allowed for an array */ + hawk_rtx_seterrnum (rtx, &nde->loc, HAWK_EARRIDXMULTI); + return -1; + } + + tmp = eval_expression(rtx, nde); + if (HAWK_UNLIKELY(!tmp)) return -1; + + hawk_rtx_refupval (rtx, tmp); + n = hawk_rtx_valtoint(rtx, tmp, &v); + hawk_rtx_refdownval (rtx, tmp); + if (HAWK_UNLIKELY(n <= -1)) + { + ADJERR_LOC (rtx, &nde->loc); + return -1; + } + + if (v < 0 || v > HAWK_QUICKINT_MAX) + { + /* array index out of permitted range */ + hawk_rtx_seterrnum (rtx, &nde->loc, HAWK_EARRIDXRANGE); + return -1; + } + + return (hawk_ooi_t)v; +} + /* ========================================================================= */ hawk_ooch_t* hawk_rtx_format ( diff --git a/hawk/lib/val.c b/hawk/lib/val.c index 13cbed86..fcee6f67 100644 --- a/hawk/lib/val.c +++ b/hawk/lib/val.c @@ -173,18 +173,43 @@ static void gc_trace_refs (hawk_gch_t* list) { v = hawk_gch_to_val(gch); - /* as of now, there is only one type available - HAWK_VAL_MAP */ - HAWK_ASSERT (v->v_type == HAWK_VAL_MAP); - hawk_init_map_itr (&itr, 0); - pair = hawk_map_getfirstpair(((hawk_val_map_t*)v)->map, &itr); - while (pair) + if (v->v_type == HAWK_VAL_MAP) { - iv = (hawk_val_t*)HAWK_MAP_VPTR(pair); - if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc) + hawk_map_t* map; + + map = ((hawk_val_map_t*)v)->map; + hawk_init_map_itr (&itr, 0); + pair = hawk_map_getfirstpair(map, &itr); + while (pair) { - hawk_val_to_gch(iv)->gc_refs--; + iv = (hawk_val_t*)HAWK_MAP_VPTR(pair); + if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc) + { + hawk_val_to_gch(iv)->gc_refs--; + } + pair = hawk_map_getnextpair(map, &itr); + } + } + else /* if (v->v_type == HAWK_VAL_ARR) */ + { + hawk_oow_t size, i; + hawk_arr_t* arr; + + HAWK_ASSERT (v->v_type == HAWK_VAL_ARR); /* only HAWK_VAL_MAP and HAWK_VAL_ARR */ + + arr = ((hawk_val_arr_t*)v)->arr; + size = HAWK_ARR_SIZE(arr); + for (i = 0; i < size; i++) + { + if (HAWK_ARR_SLOT(arr, i)) + { + iv = (hawk_val_t*)HAWK_ARR_DPTR(arr, i); + if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc) + { + hawk_val_to_gch(iv)->gc_refs--; + } + } } - pair = hawk_map_getnextpair(((hawk_val_map_t*)v)->map, &itr); } gch = gch->gc_next; @@ -230,25 +255,57 @@ static void gc_move_reachables (hawk_gch_t* list, hawk_gch_t* reachable_list) { v = hawk_gch_to_val(gch); - /* as of now, there is only one type available - HAWK_VAL_MAP */ -/* the key part is a string. don't care. but if a generic value is allowed as a key, this should change... */ - HAWK_ASSERT (v->v_type == HAWK_VAL_MAP); - hawk_init_map_itr (&itr, 0); - pair = hawk_map_getfirstpair(((hawk_val_map_t*)v)->map, &itr); - while (pair) + if (v->v_type == HAWK_VAL_MAP) { - iv = (hawk_val_t*)HAWK_MAP_VPTR(pair); - if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc) + hawk_map_t* map; + + /* the key part is a string. don't care. but if a generic value is allowed as a key, this should change... */ + map = ((hawk_val_map_t*)v)->map; + + hawk_init_map_itr (&itr, 0); + pair = hawk_map_getfirstpair(map, &itr); + while (pair) { - tmp = hawk_val_to_gch(iv); - if (tmp->gc_refs != GCH_MOVED) + iv = (hawk_val_t*)HAWK_MAP_VPTR(pair); + if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc) { - gc_unchain_gch (tmp); - gc_chain_gch (reachable_list, tmp); - tmp->gc_refs = GCH_MOVED; + tmp = hawk_val_to_gch(iv); + if (tmp->gc_refs != GCH_MOVED) + { + gc_unchain_gch (tmp); + gc_chain_gch (reachable_list, tmp); + tmp->gc_refs = GCH_MOVED; + } + } + pair = hawk_map_getnextpair(map, &itr); + } + } + else /* if (v->v_type == HAWK_VAL_ARR) */ + { + hawk_oow_t size, i; + hawk_arr_t* arr; + + HAWK_ASSERT (v->v_type == HAWK_VAL_ARR); /* only HAWK_VAL_MAP and HAWK_VAL_ARR */ + + arr = ((hawk_val_arr_t*)v)->arr; + size = HAWK_ARR_SIZE(arr); + for (i = 0; i < size; i++) + { + if (HAWK_ARR_SLOT(arr, i)) + { + iv = (hawk_val_t*)HAWK_ARR_DPTR(arr, i); + if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc) + { + tmp = hawk_val_to_gch(iv); + if (tmp->gc_refs != GCH_MOVED) + { + gc_unchain_gch (tmp); + gc_chain_gch (reachable_list, tmp); + tmp->gc_refs = GCH_MOVED; + } + } } } - pair = hawk_map_getnextpair(((hawk_val_map_t*)v)->map, &itr); } gch = gch->gc_next; @@ -915,11 +972,11 @@ static void free_arrayval (hawk_arr_t* arr, void* dptr, hawk_oow_t dlen) static void same_arrayval (hawk_arr_t* map, void* dptr, hawk_oow_t dlen) { - hawk_rtx_t* run = *(hawk_rtx_t**)hawk_arr_getxtn(map); + hawk_rtx_t* rtx = *(hawk_rtx_t**)hawk_arr_getxtn(map); #if defined(DEBUG_VAL) - hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("refdown nofree in map free - [%O]\n"), dptr); + hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("refdown nofree in arr free - [%O]\n"), dptr); #endif - hawk_rtx_refdownval_nofree (run, dptr); + hawk_rtx_refdownval_nofree (rtx, dptr); } @@ -983,7 +1040,7 @@ retry: gc_chain_val (&rtx->gc.g[0], (hawk_val_t*)val); val->v_gc = 1; #if defined(DEBUG_GC) - hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] MADE GCH %p VAL %p\n", hawk_val_to_gch(val), val); + hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] MADE GCH %p VAL(ARR) %p\n", hawk_val_to_gch(val), val); #endif #endif @@ -1016,11 +1073,11 @@ static void free_mapval (hawk_map_t* map, void* dptr, hawk_oow_t dlen) static void same_mapval (hawk_map_t* map, void* dptr, hawk_oow_t dlen) { - hawk_rtx_t* run = *(hawk_rtx_t**)hawk_map_getxtn(map); + hawk_rtx_t* rtx = *(hawk_rtx_t**)hawk_map_getxtn(map); #if defined(DEBUG_VAL) hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("refdown nofree in map free - [%O]\n"), dptr); #endif - hawk_rtx_refdownval_nofree (run, dptr); + hawk_rtx_refdownval_nofree (rtx, dptr); } hawk_val_t* hawk_rtx_makemapval (hawk_rtx_t* rtx) @@ -1090,7 +1147,7 @@ retry: gc_chain_val (&rtx->gc.g[0], (hawk_val_t*)val); val->v_gc = 1; #if defined(DEBUG_GC) - hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] MADE GCH %p VAL %p\n", hawk_val_to_gch(val), val); + hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] MADE GCH %p VAL(MAP) %p\n", hawk_val_to_gch(val), val); #endif #endif @@ -1407,7 +1464,7 @@ void hawk_rtx_freeval (hawk_rtx_t* rtx, hawk_val_t* val, int flags) #if defined(HAWK_ENABLE_GC) #if defined(DEBUG_GC) - hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] FREEING GCH %p VAL %p - flags %d\n", hawk_val_to_gch(val), val, flags); + hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] FREEING GCH %p VAL(MAP) %p - flags %d\n", hawk_val_to_gch(val), val, flags); #endif hawk_map_fini (((hawk_val_map_t*)val)->map); @@ -1422,6 +1479,25 @@ void hawk_rtx_freeval (hawk_rtx_t* rtx, hawk_val_t* val, int flags) #endif break; + case HAWK_VAL_ARR: + #if defined(HAWK_ENABLE_GC) + + #if defined(DEBUG_GC) + hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] FREEING GCH %p VAL(ARR) %p - flags %d\n", hawk_val_to_gch(val), val, flags); + #endif + + hawk_arr_fini (((hawk_val_arr_t*)val)->arr); + if (!(flags & HAWK_RTX_FREEVAL_GC_PRESERVE)) + { + gc_unchain_val (val); + gc_free_val (rtx, val); + } + #else + hawk_arr_fini (((hawk_val_arr_t*)val)->arr); + hawk_rtx_freemem (rtx, val); + #endif + break; + case HAWK_VAL_REF: if ((flags & HAWK_RTX_FREEVAL_CACHE) && rtx->rcache_count < HAWK_COUNTOF(rtx->rcache)) {