diff --git a/lib/hawk.h b/lib/hawk.h index 8e458f9d..e99c933a 100644 --- a/lib/hawk.h +++ b/lib/hawk.h @@ -433,7 +433,9 @@ enum hawk_nde_type_t HAWK_NDE_MBS, HAWK_NDE_REX, HAWK_NDE_XNIL, - HAWK_NDE_XARG, + HAWK_NDE_XARGC, + HAWK_NDE_XARGV, + HAWK_NDE_XARGVIDX, HAWK_NDE_FUN, /* keep this order for the following items otherwise, you may have diff --git a/lib/parse.c b/lib/parse.c index 386c074b..c8db72ee 100644 --- a/lib/parse.c +++ b/lib/parse.c @@ -1309,7 +1309,7 @@ static hawk_nde_t* parse_function (hawk_t* hawk) hawk_fun_t* fun = HAWK_NULL; hawk_ooch_t* argspec = HAWK_NULL; hawk_oow_t argspeccapa = 0; - hawk_oow_t argspeclen; + hawk_oow_t argspeclen = 0; hawk_oow_t nargs, g; int variadic = 0; hawk_htb_pair_t* pair; @@ -4086,9 +4086,9 @@ static hawk_nde_t* parse_in (hawk_t* hawk, const hawk_loc_t* xloc) if (HAWK_UNLIKELY(!right)) goto oops; #if defined(HAWK_ENABLE_GC) - if (!is_var(right)) + if (!is_var(right) && right->type != HAWK_NDE_XARGV) #else - if (!is_plain_var(right)) + if (!is_plain_var(right) && right->type != HAWK_NDE_XARGV) #endif { hawk_seterrnum (hawk, &rloc, HAWK_ENOTVAR); @@ -5118,55 +5118,84 @@ oops: static hawk_nde_t* parse_primary_xarg (hawk_t* hawk, const hawk_loc_t* xloc) { - hawk_nde_xarg_t* nde = HAWK_NULL; + hawk_nde_t* nde = HAWK_NULL; hawk_nde_t* pos = HAWK_NULL; - int opcode; + int nde_type; + + /* @argc, @argv, @argv[] look like the standard ARGC and ARGV but form special constructs + * for function arguments. this is useful when combined with the variadic function arguments. + * it can't be used in assignment, delete, reset, in many other context, however. + * when used in the main entry point function, @argc is the number of arguments to the + * function but ARGC is the number of arguments including the program name so ARGC is greater + * than @argc by 1. */ HAWK_ASSERT (hawk->tok.type == TOK_XARGV || hawk->tok.type == TOK_XARGC); - opcode = (hawk->tok.type == TOK_XARGC); /* @argv: 1 @argv: 2 */ - - if (get_token(hawk) <= -1) goto oops; - if (!MATCH(hawk,TOK_LPAREN)) - { - hawk_seterrfmt (hawk, &hawk->tok.loc, HAWK_ELPAREN, FMT_ELPAREN, HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOECS_PTR(hawk->tok.name)); - goto oops; - } - if (get_token(hawk) <= -1) goto oops; - - if (opcode == 0) + if (hawk->tok.type == TOK_XARGV) { /* @argv */ - hawk_loc_t eloc; - eloc = hawk->tok.loc; - pos = parse_expr_withdc(hawk, &eloc); - if (HAWK_UNLIKELY(!pos)) goto oops; - } + nde_type = HAWK_NDE_XARGV; + if (get_token(hawk) <= -1) goto oops; - if (!MATCH(hawk,TOK_RPAREN)) + if (MATCH(hawk,TOK_LBRACK)) /* @argv[, expecting to see @argv[expr] */ + { + hawk_loc_t eloc; + + if (get_token(hawk) <= -1) goto oops; + + eloc = hawk->tok.loc; + pos = parse_expr_withdc(hawk, &eloc); + if (HAWK_UNLIKELY(!pos)) goto oops; + + if (!MATCH(hawk,TOK_RBRACK)) + { + hawk_seterrfmt (hawk, &hawk->tok.loc, HAWK_ERBRACK, FMT_ERBRACK, HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOECS_PTR(hawk->tok.name)); + goto oops; + } + + if (get_token(hawk) <= -1) goto oops; + } + } + else { - hawk_seterrfmt (hawk, &hawk->tok.loc, HAWK_ERPAREN, FMT_ERPAREN, HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOECS_PTR(hawk->tok.name)); - goto oops; + nde_type = HAWK_NDE_XARGC; + if (get_token(hawk) <= -1) goto oops; } - if (get_token(hawk) <= -1) goto oops; - - nde = (hawk_nde_xarg_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*nde)); - if (HAWK_UNLIKELY(!nde)) + if (pos) { - ADJERR_LOC (hawk, xloc); - return HAWK_NULL; - } + hawk_nde_xargvidx_t* xargvidx; - nde->type = HAWK_NDE_XARG; - nde->loc = *xloc; - nde->opcode = opcode; - nde->pos = pos; + xargvidx = (hawk_nde_xargvidx_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*xargvidx)); + if (HAWK_UNLIKELY(!xargvidx)) + { + ADJERR_LOC (hawk, xloc); + return HAWK_NULL; + } + + xargvidx->type = HAWK_NDE_XARGVIDX; + xargvidx->loc = *xloc; + xargvidx->pos = pos; + + nde = (hawk_nde_t*)xargvidx; + } + else + { + nde = hawk_callocmem(hawk, HAWK_SIZEOF(*nde)); + if (HAWK_UNLIKELY(!nde)) + { + ADJERR_LOC (hawk, xloc); + return HAWK_NULL; + } + + nde->type = nde_type; + nde->loc = *xloc; + } return (hawk_nde_t*)nde; oops: - if (nde) hawk_freemem (hawk, nde); /* tricky to call hawk_clrpt() on nde due to var and pos */ + if (nde) hawk_freemem (hawk, nde); /* tricky to call hawk_clrpt() on nde due to pos */ if (pos) hawk_clrpt (hawk, pos); return HAWK_NULL; } @@ -7343,7 +7372,11 @@ static hawk_htb_walk_t deparse_func (hawk_htb_t* map, hawk_htb_pair_t* pair, voi PUT_S (df, HAWK_T(", ")); } - if (fun->variadic) PUT_S(df, HAWK_T(" ...")); + if (fun->variadic) + { + if (fun->nargs > 0) PUT_S (df, HAWK_T(", ")); + PUT_S(df, HAWK_T("...")); + } PUT_S (df, HAWK_T(")")); if (df->hawk->opt.trait & HAWK_CRLF) PUT_C (df, HAWK_T('\r')); diff --git a/lib/run.c b/lib/run.c index 8572e722..97f62ba6 100644 --- a/lib/run.c +++ b/lib/run.c @@ -163,7 +163,9 @@ static hawk_val_t* eval_str (hawk_rtx_t* rtx, hawk_nde_t* nde); static hawk_val_t* eval_mbs (hawk_rtx_t* rtx, hawk_nde_t* nde); static hawk_val_t* eval_rex (hawk_rtx_t* rtx, hawk_nde_t* nde); static hawk_val_t* eval_xnil (hawk_rtx_t* rtx, hawk_nde_t* nde); -static hawk_val_t* eval_xarg (hawk_rtx_t* rtx, hawk_nde_t* nde); +static hawk_val_t* eval_xargc (hawk_rtx_t* rtx, hawk_nde_t* nde); +static hawk_val_t* eval_xargv (hawk_rtx_t* rtx, hawk_nde_t* nde); +static hawk_val_t* eval_xargvidx (hawk_rtx_t* rtx, hawk_nde_t* nde); static hawk_val_t* eval_fun (hawk_rtx_t* rtx, hawk_nde_t* nde); static hawk_val_t* eval_named (hawk_rtx_t* rtx, hawk_nde_t* nde); static hawk_val_t* eval_gbl (hawk_rtx_t* rtx, hawk_nde_t* nde); @@ -3708,7 +3710,9 @@ static hawk_val_t* eval_expression0 (hawk_rtx_t* rtx, hawk_nde_t* nde) eval_mbs, eval_rex, eval_xnil, - eval_xarg, + eval_xargc, + eval_xargv, + eval_xargvidx, eval_fun, eval_named, eval_gbl, @@ -4496,6 +4500,8 @@ static hawk_val_t* eval_binop_in (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* hawk_nde_t* remidx; hawk_int_t idxint; + if (right->type == HAWK_NDE_XARGV) goto rvalue_ok; + #if defined(HAWK_ENABLE_GC) if (right->type < HAWK_NDE_NAMED || right->type > HAWK_NDE_ARGIDX) #else @@ -4508,6 +4514,7 @@ static hawk_val_t* eval_binop_in (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* return HAWK_NULL; } +rvalue_ok: /* evaluate the left-hand side of the operator */ len = HAWK_COUNTOF(idxbuf); 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 */ @@ -7473,38 +7480,59 @@ static hawk_val_t* eval_xnil (hawk_rtx_t* rtx, hawk_nde_t* nde) return hawk_rtx_makenilval(rtx); /* this never fails */ } -static hawk_val_t* eval_xarg (hawk_rtx_t* rtx, hawk_nde_t* nde) +static hawk_val_t* eval_xargc (hawk_rtx_t* rtx, hawk_nde_t* nde) { - hawk_nde_xarg_t* xarg; + hawk_int_t nargs = (hawk_int_t)hawk_rtx_getnargs(rtx); + return hawk_rtx_makeintval(rtx, nargs); +} - xarg = (hawk_nde_xarg_t*)nde; - if (xarg->opcode == 0) +static hawk_val_t* eval_xargv (hawk_rtx_t* rtx, hawk_nde_t* nde) +{ + /* this create a new array. referencing @argv without a subscript + * slows hawk. TODO: fix this issue */ + hawk_oow_t nargs, i; + hawk_val_t* v; + + nargs = hawk_rtx_getnargs(rtx); + v = hawk_rtx_makearrval(rtx, nargs); + if (HAWK_UNLIKELY(!v)) return HAWK_NULL; + + hawk_rtx_refupval (rtx,v); + for (i = 0; i < nargs; i++) { - /* @argv */ - hawk_val_t* v; - hawk_int_t pos; - int n; - - v = eval_expression(rtx, xarg->pos); - if (HAWK_UNLIKELY(!v)) return HAWK_NULL; - - hawk_rtx_refupval (rtx, v); - n = hawk_rtx_valtoint(rtx, v, &pos); - hawk_rtx_refdownval (rtx, v); - if (n <= -1) + if (HAWK_UNLIKELY(!hawk_rtx_setarrvalfld(rtx, v, i, hawk_rtx_getarg(rtx, i)))) { - hawk_rtx_seterrnum (rtx, &xarg->pos->loc, HAWK_EPOSIDX); + hawk_rtx_refdownval (rtx, v); return HAWK_NULL; } + } - return (pos < 0 || pos >= hawk_rtx_getnargs(rtx))? hawk_rtx_makenilval(rtx): hawk_rtx_getarg(rtx, pos); - } - else + hawk_rtx_refdownval_nofree (rtx,v); + return v; +} + +static hawk_val_t* eval_xargvidx (hawk_rtx_t* rtx, hawk_nde_t* nde) +{ + hawk_nde_xargvidx_t* xarg; + hawk_val_t* v; + hawk_int_t pos; + int n; + + xarg = (hawk_nde_xargvidx_t*)nde; + + v = eval_expression(rtx, xarg->pos); + if (HAWK_UNLIKELY(!v)) return HAWK_NULL; + + hawk_rtx_refupval (rtx, v); + n = hawk_rtx_valtoint(rtx, v, &pos); + hawk_rtx_refdownval (rtx, v); + if (n <= -1) { - /* @argc */ - hawk_int_t nargs = (hawk_int_t)hawk_rtx_getnargs(rtx); - return hawk_rtx_makeintval(rtx, nargs); + hawk_rtx_seterrnum (rtx, &xarg->pos->loc, HAWK_EPOSIDX); + return HAWK_NULL; } + + return (pos < 0 || pos >= hawk_rtx_getnargs(rtx))? hawk_rtx_makenilval(rtx): hawk_rtx_getarg(rtx, pos); } static hawk_val_t* eval_fun (hawk_rtx_t* rtx, hawk_nde_t* nde) diff --git a/lib/tree-prv.h b/lib/tree-prv.h index fbacedf0..1086f9ec 100644 --- a/lib/tree-prv.h +++ b/lib/tree-prv.h @@ -68,7 +68,7 @@ typedef struct hawk_nde_mbs_t hawk_nde_mbs_t; typedef struct hawk_nde_rex_t hawk_nde_rex_t; typedef struct hawk_nde_fun_t hawk_nde_fun_t; typedef struct hawk_nde_xnil_t hawk_nde_xnil_t; -typedef struct hawk_nde_xarg_t hawk_nde_xarg_t; +typedef struct hawk_nde_xargvidx_t hawk_nde_xargvidx_t; typedef struct hawk_nde_var_t hawk_nde_var_t; typedef struct hawk_nde_fncall_t hawk_nde_fncall_t; @@ -178,7 +178,7 @@ struct hawk_nde_str_t { HAWK_NDE_HDR; hawk_ooch_t* ptr; - hawk_oow_t len; + hawk_oow_t len; }; /* HAWK_NDE_MBS */ @@ -186,15 +186,15 @@ struct hawk_nde_mbs_t { HAWK_NDE_HDR; hawk_bch_t* ptr; - hawk_oow_t len; + hawk_oow_t len; }; /* HAWK_NDE_REX */ struct hawk_nde_rex_t { HAWK_NDE_HDR; - hawk_oocs_t str; - hawk_tre_t* code[2]; /* [0]: case sensitive, [1]: case insensitive */ + hawk_oocs_t str; + hawk_tre_t* code[2]; /* [0]: case sensitive, [1]: case insensitive */ }; struct hawk_nde_xnil_t @@ -202,10 +202,9 @@ struct hawk_nde_xnil_t HAWK_NDE_HDR; }; -struct hawk_nde_xarg_t +struct hawk_nde_xargvidx_t { HAWK_NDE_HDR; - int opcode; /* 0: @argc, 1: @argv */ hawk_nde_t* pos; }; diff --git a/lib/tree.c b/lib/tree.c index eaeaf2ed..63bf6a87 100644 --- a/lib/tree.c +++ b/lib/tree.c @@ -554,16 +554,23 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde) break; } - case HAWK_NDE_XARG: + case HAWK_NDE_XARGC: { - static hawk_ooch_t* xarg_str[] = - { - HAWK_T("@argv("), - HAWK_T("@argc("), - }; - PUT_SRCSTR (hawk, xarg_str[((hawk_nde_xarg_t*)nde)->opcode % 2]); - if (((hawk_nde_xarg_t*)nde)->pos) PRINT_EXPR (hawk, ((hawk_nde_xarg_t*)nde)->pos); - PUT_SRCSTR (hawk, HAWK_T(")")); + PUT_SRCSTR (hawk, HAWK_T("@argc")); + break; + } + + case HAWK_NDE_XARGV: + { + PUT_SRCSTR (hawk, HAWK_T("@argv")); + break; + } + + case HAWK_NDE_XARGVIDX: + { + PUT_SRCSTR (hawk, HAWK_T("@argv[")); + PRINT_EXPR (hawk, ((hawk_nde_xargvidx_t*)nde)->pos); + PUT_SRCSTR (hawk, HAWK_T("]")); break; } @@ -1467,10 +1474,16 @@ void hawk_clrpt (hawk_t* hawk, hawk_nde_t* tree) break; } - case HAWK_NDE_XARG: + case HAWK_NDE_XARGC: + case HAWK_NDE_XARGV: { - if (((hawk_nde_xarg_t*)p)->pos) /* pos is null for @argc */ - hawk_clrpt (hawk, ((hawk_nde_xarg_t*)p)->pos); + hawk_freemem (hawk, p); + break; + } + + case HAWK_NDE_XARGVIDX: + { + hawk_clrpt (hawk, ((hawk_nde_xargvidx_t*)p)->pos); hawk_freemem (hawk, p); break; } diff --git a/lib/val.c b/lib/val.c index 490fc74a..e9539e8b 100644 --- a/lib/val.c +++ b/lib/val.c @@ -1069,7 +1069,7 @@ hawk_val_t* hawk_rtx_makerexval (hawk_rtx_t* rtx, const hawk_oocs_t* str, hawk_t /* --------------------------------------------------------------------- */ -static void free_arrayval (hawk_arr_t* arr, void* dptr, hawk_oow_t dlen) +static void free_arrval (hawk_arr_t* arr, void* dptr, hawk_oow_t dlen) { hawk_rtx_t* rtx = *(hawk_rtx_t**)hawk_arr_getxtn(arr); hawk_val_t* v = (hawk_val_t*)dptr; @@ -1091,7 +1091,7 @@ static void free_arrayval (hawk_arr_t* arr, void* dptr, hawk_oow_t dlen) hawk_rtx_refdownval (rtx, v); } -static void same_arrayval (hawk_arr_t* map, void* dptr, hawk_oow_t dlen) +static void same_arrval (hawk_arr_t* map, void* dptr, hawk_oow_t dlen) { hawk_rtx_t* rtx = *(hawk_rtx_t**)hawk_arr_getxtn(map); #if defined(DEBUG_VAL) @@ -1111,9 +1111,9 @@ hawk_val_t* hawk_rtx_makearrval (hawk_rtx_t* rtx, hawk_ooi_t init_capa) * freeing the actual value is handled by free_arrval and same_arrval */ HAWK_ARR_COPIER_DEFAULT, - free_arrayval, + free_arrval, HAWK_ARR_COMPER_DEFAULT, - same_arrayval, + same_arrval, HAWK_ARR_SIZER_DEFAULT }; #if defined(HAWK_ENABLE_GC) diff --git a/mod/mod-uci.c b/mod/mod-uci.c index 919d9e72..0f1df270 100644 --- a/mod/mod-uci.c +++ b/mod/mod-uci.c @@ -530,7 +530,7 @@ static int getoption_byid (hawk_rtx_t* rtx, uctx_list_t* list, hawk_int_t id, ha { int n; hawk_rtx_refupval (rtx, map); - n = hawk_rtx_setrefval (rtx, ref, map); + n = hawk_rtx_setrefval(rtx, ref, map); hawk_rtx_refdownval (rtx, map); if (n <= -1) { diff --git a/t/h-002.hawk b/t/h-002.hawk index 47879d82..8011f79b 100644 --- a/t/h-002.hawk +++ b/t/h-002.hawk @@ -643,8 +643,15 @@ function main() tap_ensure (RLENGTH, 2, @SCRIPTNAME, @SCRIPTLINE); tap_ensure (test5(10, 20, 30), 10, @SCRIPTNAME, @SCRIPTLINE); - tap_ensure (test6(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 54, @SCRIPTNAME, @SCRIPTLINE); - tap_ensure (test7(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 55, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure (test6(), 2, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure (test6(11, 11, 11), 3, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure (test7(), 0, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure (test7(11, 11, 11), 3, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure (test8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 54, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure (test9(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 55, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure (test10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 55, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure (test11("aa", "bb", "cc"), 0, @SCRIPTNAME, @SCRIPTLINE); + tap_ensure (test11("aa", "bb", "cc", "dd"), 1, @SCRIPTNAME, @SCRIPTLINE); } tap_end (); } @@ -658,16 +665,35 @@ function test5(a, b, ...) { return a; } -function test6(a, ...) { - @local i, x - x = 0 - for (i = 0; i < @argc(); i++) x += @argv(i); - return x - a; +function test6(a, b, ...) { + return @argc; } function test7(...) { + return @argc; +} + +function test8(a, ...) { @local i, x x = 0 - for (i = 0; i < @argc(); i++) x += @argv(i); + for (i = 0; i < @argc; i++) x += @argv[i]; + return x - a; +} + +function test9(...) { + @local i, x + x = 0 + for (i = 0; i < @argc; i++) x += @argv[i]; return x; } + +function test10(...) { + @local i, x + x = 0 + for (i in @argv) x += @argv[i]; + return x; +} + +function test11(...) { + return (3 in @argv); +}