awk: fix 'delete array[var--]' decrementing var twice
No binary (build failed)
—
(log yok)
| @@ -2514,6 +2514,32 @@ static var *evaluate(node *op, var *res) | |
| op1 = op->l.n; | |
| debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); | |
| + | /* "delete" is special: |
| + | * "delete array[var--]" must evaluate index expr only once, |
| + | * must not evaluate it in "execute inevitable things" part. |
| + | */ |
| + | if (XC(opinfo & OPCLSMASK) == XC(OC_DELETE)) { |
| + | uint32_t info = op1->info & OPCLSMASK; |
| + | var *v; |
| + | |
| + | debug_printf_eval("DELETE\n"); |
| + | if (info == OC_VAR) { |
| + | v = op1->l.v; |
| + | } else if (info == OC_FNARG) { |
| + | v = &fnargs[op1->l.aidx]; |
| + | } else { |
| + | syntax_error(EMSG_NOT_ARRAY); |
| + | } |
| + | if (op1->r.n) { /* array ref? */ |
| + | const char *s; |
| + | s = getvar_s(evaluate(op1->r.n, v1)); |
| + | hash_remove(iamarray(v), s); |
| + | } else { |
| + | clear_array(iamarray(v)); |
| + | } |
| + | goto next; |
| + | } |
| + | |
| /* execute inevitable things */ | |
| if (opinfo & OF_RES1) | |
| L.v = evaluate(op1, v1); | |
| @@ -2621,28 +2647,7 @@ static var *evaluate(node *op, var *res) | |
| break; | |
| } | |
| - | case XC( OC_DELETE ): { |
| - | uint32_t info = op1->info & OPCLSMASK; |
| - | var *v; |
| - | |
| - | if (info == OC_VAR) { |
| - | v = op1->l.v; |
| - | } else if (info == OC_FNARG) { |
| - | v = &fnargs[op1->l.aidx]; |
| - | } else { |
| - | syntax_error(EMSG_NOT_ARRAY); |
| - | } |
| - | |
| - | if (op1->r.n) { |
| - | const char *s; |
| - | clrvar(L.v); |
| - | s = getvar_s(evaluate(op1->r.n, v1)); |
| - | hash_remove(iamarray(v), s); |
| - | } else { |
| - | clear_array(iamarray(v)); |
| - | } |
| - | break; |
| - | } |
| + | /* case XC( OC_DELETE ): - moved to happen before arg evaluation */ |
| case XC( OC_NEWSOURCE ): | |
| g_progname = op->l.new_progname; | |
| @@ -2666,12 +2671,14 @@ static var *evaluate(node *op, var *res) | |
| /* -- recursive node type -- */ | |
| case XC( OC_VAR ): | |
| + | debug_printf_eval("VAR\n"); |
| L.v = op->l.v; | |
| if (L.v == intvar[NF]) | |
| split_f0(); | |
| goto v_cont; | |
| case XC( OC_FNARG ): | |
| + | debug_printf_eval("FNARG[%d]\n", op->l.aidx); |
| L.v = &fnargs[op->l.aidx]; | |
| v_cont: | |
| res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v; | |
| @@ -3035,7 +3042,8 @@ static var *evaluate(node *op, var *res) | |
| default: | |
| syntax_error(EMSG_POSSIBLE_ERROR); | |
| - | } |
| + | } /* switch */ |
| + | next: |
| if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS) | |
| op = op->a.n; | |
| if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS) | |
| @@ -261,6 +261,25 @@ end d | |
| " \ | |
| "" "" | |
| + | prg=' |
| + | BEGIN{ |
| + | cnt = 0 |
| + | a[cnt] = "zeroth" |
| + | a[++cnt] = "first" |
| + | delete a[cnt--] |
| + | print cnt |
| + | print "[0]:" a[0] |
| + | print "[1]:" a[1] |
| + | }' |
| + | testing "awk 'delete a[v--]' evaluates v-- once" \ |
| + | "awk '$prg'" \ |
| + | "\ |
| + | 0 |
| + | [0]:zeroth |
| + | [1]: |
| + | " \ |
| + | "" "" |
| + | |
| testing "awk handles empty ()" \ | |
| "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" "" | |