diff --git a/hawk/lib/err.c b/hawk/lib/err.c index 7b59a93f..7ec05144 100644 --- a/hawk/lib/err.c +++ b/hawk/lib/err.c @@ -139,11 +139,10 @@ const hawk_ooch_t* hawk_dfl_errstr (hawk_errnum_t errnum) HAWK_T("non-function value"), HAWK_T("not deletable"), HAWK_T("value not a map"), - HAWK_T("right-hand side of the 'in' operator not a map"), - HAWK_T("right-hand side of the 'in' operator not a map nor nil"), HAWK_T("value not an array"), HAWK_T("value not accessible with index"), HAWK_T("value not referenceable"), + HAWK_T("wrong operand in right-hand side of 'in'"), /* EINROP */ HAWK_T("cannot return a nonscalar value"), /* ENONSCARET */ HAWK_T("cannot assign a nonscalar value to a positional"), /* ENONSCATOPOS */ HAWK_T("cannot assign a nonscalar value to an indexed variable"),/* ENONSCATOIDX */ diff --git a/hawk/lib/hawk-cmn.h b/hawk/lib/hawk-cmn.h index 95dc80a2..110d11e0 100644 --- a/hawk/lib/hawk-cmn.h +++ b/hawk/lib/hawk-cmn.h @@ -974,11 +974,10 @@ enum hawk_errnum_t HAWK_ENOTFUN, /**< non-function value */ HAWK_ENOTDEL, /**< not deletable */ HAWK_ENOTMAP, /**< value not a map */ - HAWK_ENOTMAPIN, /**< right-hand side of 'in' not a map */ - HAWK_ENOTMAPNILIN, /**< right-hand side of 'in' not a map nor nil */ HAWK_ENOTARR, /**< value not an array */ HAWK_ENOTIDXACC, /**< value not accessible with index */ HAWK_ENOTREF, /**< value not referenceable */ + HAWK_EINROP, /**< wrong operand in right-hand side of 'in'*/ HAWK_ENONSCARET, /**< nonscalar value cannot be returned */ HAWK_ENONSCATOPOS, /**< nonscalar value cannot be assigned to a positional */ HAWK_ENONSCATOIDX, /**< nonscalar value cannot be assigned to an indexed variable */ diff --git a/hawk/lib/parse.c b/hawk/lib/parse.c index 61bc0a96..83a09f2a 100644 --- a/hawk/lib/parse.c +++ b/hawk/lib/parse.c @@ -748,7 +748,7 @@ int hawk_parse (hawk_t* hawk, hawk_sio_cbs_t* sio) hawk->sio.inp = &hawk->sio.arg; n = parse(hawk); - if (n == 0 && hawk->sio.outf != HAWK_NULL) n = deparse (hawk); + if (n == 0 && hawk->sio.outf != HAWK_NULL) n = deparse(hawk); HAWK_ASSERT (hawk->parse.depth.loop == 0); HAWK_ASSERT (hawk->parse.depth.expr == 0); diff --git a/hawk/lib/run.c b/hawk/lib/run.c index 526f6afe..2d029aec 100644 --- a/hawk/lib/run.c +++ b/hawk/lib/run.c @@ -193,7 +193,14 @@ 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); +struct idxnde_to_str_idxint_t +{ + int ok; + hawk_int_t v; +}; +typedef struct idxnde_to_str_idxint_t idxnde_to_str_idxint_t; + +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, idxnde_to_str_idxint_t* firstidxint); static hawk_ooi_t idxnde_to_int (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_nde_t** remidx); typedef hawk_val_t* (*binop_func_t) (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right); @@ -2663,7 +2670,7 @@ static int run_forin (hawk_rtx_t* rtx, hawk_nde_forin_t* nde) } default: - hawk_rtx_seterrnum (rtx, &test->right->loc, HAWK_ENOTMAPIN); + hawk_rtx_seterrnum (rtx, &test->right->loc, HAWK_EINROP); ret = -1; goto done1; } @@ -3013,7 +3020,7 @@ static HAWK_INLINE int delete_indexed (hawk_rtx_t* rtx, hawk_val_t* vv, hawk_nde if (vtype == HAWK_VAL_MAP) { len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx); + str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx, HAWK_NULL); if (HAWK_UNLIKELY(!str)) goto oops; map = ((hawk_val_map_t*)vv)->map; } @@ -3049,7 +3056,7 @@ static HAWK_INLINE int delete_indexed (hawk_rtx_t* rtx, hawk_val_t* vv, hawk_nde val_map: if (str && str != idxbuf) hawk_rtx_freemem (rtx, str); len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx); + str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx, HAWK_NULL); if (HAWK_UNLIKELY(!str)) goto oops; map = ((hawk_val_map_t*)vv)->map; break; @@ -4014,7 +4021,7 @@ static hawk_val_t* do_assignment_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var, if (vtype == HAWK_VAL_MAP) { len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx); + str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx, HAWK_NULL); if (HAWK_UNLIKELY(!str)) goto oops; map = ((hawk_val_map_t*)vv)->map; } @@ -4049,7 +4056,7 @@ static hawk_val_t* do_assignment_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var, val_map: if (str != idxbuf) hawk_rtx_freemem (rtx, str); len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx); + str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx, HAWK_NULL); if (HAWK_UNLIKELY(!str)) goto oops; map = ((hawk_val_map_t*)vv)->map; break; @@ -4409,12 +4416,15 @@ static hawk_val_t* eval_binop_land (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_ static hawk_val_t* eval_binop_in (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right) { - hawk_val_t* rv; - hawk_val_type_t rvtype; + hawk_val_t* res; + hawk_val_t* ropv; + hawk_val_type_t ropvtype; hawk_ooch_t* str; hawk_oow_t len; hawk_ooch_t idxbuf[IDXBUFSIZE]; hawk_nde_t* remidx; + idxnde_to_str_idxint_t idxint; + hawk_errnum_t errnum; #if defined(HAWK_ENABLE_GC) if (right->type < HAWK_NDE_NAMED || right->type > HAWK_NDE_ARGIDX) @@ -4430,47 +4440,78 @@ static hawk_val_t* eval_binop_in (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* /* evaluate the left-hand side of the operator */ len = HAWK_COUNTOF(idxbuf); - str = (left->type == HAWK_NDE_GRP)? - idxnde_to_str(rtx, ((hawk_nde_grp_t*)left)->body, idxbuf, &len, &remidx): - idxnde_to_str(rtx, left, idxbuf, &len, &remidx); + str = (left->type == HAWK_NDE_GRP)? /* it is inefficinet to call idxnde_to_str() for an array. but i don't know if the right hand side is a map or an array yet */ + idxnde_to_str(rtx, ((hawk_nde_grp_t*)left)->body, idxbuf, &len, &remidx, &idxint): + idxnde_to_str(rtx, left, idxbuf, &len, &remidx, &idxint); if (HAWK_UNLIKELY(!str)) return HAWK_NULL; + /* There is no way to express a true multi-dimensional indices for the 'in' operator. + * So remidx must be NULL here. + * a[10][20] <--- no way to express the test of 20 under 10 in a. + * You may use multi-level test conjoined with a logical and operator in such a case. + * ((10 in a) && (20 in a[10])) + * + * '(10, 20) in a' is to test for a[10,20] if 'a' is a map. + */ + HAWK_ASSERT (remidx == HAWK_NULL); + /* evaluate the right-hand side of the operator */ HAWK_ASSERT (right->next == HAWK_NULL); - rv = eval_expression(rtx, right); - if (HAWK_UNLIKELY(!rv)) + ropv = eval_expression(rtx, right); + if (HAWK_UNLIKELY(!ropv)) { if (str != idxbuf) hawk_rtx_freemem (rtx, str); return HAWK_NULL; } - hawk_rtx_refupval (rtx, rv); + hawk_rtx_refupval (rtx, ropv); - rvtype = HAWK_RTX_GETVALTYPE(rtx, rv); - if (rvtype == HAWK_VAL_NIL) + ropvtype = HAWK_RTX_GETVALTYPE(rtx, ropv); + switch (ropvtype) { - if (str != idxbuf) hawk_rtx_freemem (rtx, str); - hawk_rtx_refdownval (rtx, rv); - return HAWK_VAL_ZERO; - } - else if (rvtype == HAWK_VAL_MAP) - { - hawk_val_t* res; - hawk_map_t* map; + case HAWK_VAL_NIL: + res = HAWK_VAL_ZERO; + break; - map = ((hawk_val_map_t*)rv)->map; - res = (hawk_map_search(map, str, len) == HAWK_NULL)? HAWK_VAL_ZERO: HAWK_VAL_ONE; + case HAWK_VAL_MAP: + { + + hawk_map_t* map; - if (str != idxbuf) hawk_rtx_freemem (rtx, str); - hawk_rtx_refdownval (rtx, rv); - return res; + map = ((hawk_val_map_t*)ropv)->map; + res = (hawk_map_search(map, str, len) == HAWK_NULL)? HAWK_VAL_ZERO: HAWK_VAL_ONE; + break; + } + + case HAWK_VAL_ARR: + { + hawk_arr_t* arr; + + if (!idxint.ok) + { + hawk_rtx_seterrnum (rtx, &left->loc, HAWK_EARRIDXMULTI); + goto oops; + } + + arr = ((hawk_val_arr_t*)ropv)->arr; + res = (idxint.v < 0 || idxint.v > HAWK_ARR_SIZE(arr) || !HAWK_ARR_SLOT(arr, idxint.v))? HAWK_VAL_ZERO: HAWK_VAL_ONE; + break; + } + + default: + hawk_rtx_seterrnum (rtx, &right->loc, HAWK_EINROP); + goto oops; } - /* need a map */ +done: if (str != idxbuf) hawk_rtx_freemem (rtx, str); - hawk_rtx_refdownval (rtx, rv); + hawk_rtx_refdownval (rtx, ropv); + return res; + +oops: + if (str != idxbuf) hawk_rtx_freemem (rtx, str); + hawk_rtx_refdownval (rtx, ropv); - hawk_rtx_seterrnum (rtx, &right->loc, HAWK_ENOTMAPNILIN); return HAWK_NULL; } @@ -6756,7 +6797,7 @@ static hawk_val_t** get_reference_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var) case HAWK_VAL_MAP: val_map_init: len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx); + str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx, HAWK_NULL); if (HAWK_UNLIKELY(!str)) goto oops; map = ((hawk_val_map_t*)v)->map; break; @@ -6796,7 +6837,7 @@ static hawk_val_t** get_reference_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var) val_map: if (str && str != idxbuf) hawk_rtx_freemem (rtx, str); len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx); + str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx, HAWK_NULL); if (HAWK_UNLIKELY(!str)) goto oops; map = ((hawk_val_map_t*)v)->map; break; @@ -6993,7 +7034,7 @@ static hawk_val_t* eval_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var) case HAWK_VAL_MAP: init_val_map: len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx); + str = idxnde_to_str(rtx, var->idx, idxbuf, &len, &remidx, HAWK_NULL); if (HAWK_UNLIKELY(!str)) goto oops; map = ((hawk_val_map_t*)v)->map; break; @@ -7033,7 +7074,7 @@ static hawk_val_t* eval_indexed (hawk_rtx_t* rtx, hawk_nde_var_t* var) val_map: if (str && str != idxbuf) hawk_rtx_freemem (rtx, str); len = HAWK_COUNTOF(idxbuf); - str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx); + str = idxnde_to_str(rtx, remidx, idxbuf, &len, &remidx, HAWK_NULL); if (HAWK_UNLIKELY(!str)) goto oops; map = ((hawk_val_map_t*)v)->map; break; @@ -7428,10 +7469,11 @@ read_again: return 1; } -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_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, idxnde_to_str_idxint_t* firstidxint) { hawk_ooch_t* str; hawk_val_t* idx; + hawk_int_t idxint; HAWK_ASSERT (nde != HAWK_NULL); @@ -7445,6 +7487,16 @@ static hawk_ooch_t* idxnde_to_str (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_ooch_t hawk_rtx_refupval (rtx, idx); + if (firstidxint) + { + if (hawk_rtx_valtoint(rtx, idx, &idxint) <= -1) + { + hawk_rtx_refdownval (rtx, idx); + ADJERR_LOC (rtx, &nde->loc); + return HAWK_NULL; + } + } + str = HAWK_NULL; if (buf) @@ -7480,10 +7532,15 @@ static hawk_ooch_t* idxnde_to_str (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_ooch_t hawk_rtx_refdownval (rtx, idx); *remidx = HAWK_NULL; + if (firstidxint) + { + firstidxint->ok = 1; + firstidxint->v = idxint; + } } else { - /* multidimensional index */ + /* multidimensional index - e.g. [1,2,3] */ hawk_ooecs_t idxstr; hawk_oocs_t tmp; hawk_rtx_valtostr_out_t out; @@ -7542,6 +7599,8 @@ static hawk_ooch_t* idxnde_to_str (hawk_rtx_t* rtx, hawk_nde_t* nde, hawk_ooch_t /* if nde is not HAWK_NULL, it should be of the HAWK_NDE_NULL type */ *remidx = nde? nde->next: nde; + + if (firstidxint) firstidxint->ok = 0; } return str;