aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--awkgram.y25
-rw-r--r--interpret.h21
-rw-r--r--test/let1.awk9
3 files changed, 44 insertions, 11 deletions
diff --git a/awkgram.y b/awkgram.y
index 285c233a..423cf66b 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -1644,17 +1644,26 @@ let_var_list
}
| NAME ASSIGN exp
{
- add_let(in_function, $1);
+ bool is_reused_location = add_let(in_function, $1);
$1->opcode = Op_push;
$1->memory = variable($1->source_line, $1->lextok, Node_var_new);
$$ = list_append(mk_assignment(list_create($1), $3, $2),
instruction(Op_pop));
-
+ /* Even for initialized variables, we must emit the Op_clear_var
+ instruction. This is because the variable may previously have
+ been an array and is now being assigned as a scalar value.
+ the Op_clear_var will reset the type to allow that. */
+ if (in_loop || is_reused_location) {
+ INSTRUCTION *clr = instruction(Op_clear_var);
+ UPREF($1->memory);
+ clr->memory = $1->memory;
+ $$ = list_prepend($$, clr);
+ }
}
| let_var_list comma NAME ASSIGN exp
{
INSTRUCTION *assn;
- add_let(in_function, $3);
+ bool is_reused_location = add_let(in_function, $3);
$3->opcode = Op_push;
$3->memory = variable($3->source_line, $3->lextok, Node_var_new);
assn = list_append(mk_assignment(list_create($3), $5, $4),
@@ -1663,6 +1672,16 @@ let_var_list
$$ = assn;
else
$$ = list_merge($1, assn);
+ /* Even for initialized variables, we must emit the Op_clear_var
+ instruction. This is because the variable may previously have
+ been an array and is now being assigned as a scalar value.
+ the Op_clear_var will reset the type to allow that. */
+ if (in_loop || is_reused_location) {
+ INSTRUCTION *clr = instruction(Op_clear_var);
+ UPREF($3->memory);
+ clr->memory = $3->memory;
+ $$ = list_prepend($$, clr);
+ }
}
| error
{ $$ = NULL; }
diff --git a/interpret.h b/interpret.h
index 0dc261d6..f239406f 100644
--- a/interpret.h
+++ b/interpret.h
@@ -753,16 +753,21 @@ mod:
* initialized frame locations.
*/
NODE *var = pc->memory;
- lhs = get_lhs(var, false);
- /*
- * If it's already clear, nothing to do
- */
- if (*lhs != Nnull_string) {
- unref(*lhs);
- *lhs = dupnode(Nnull_string);
+ if (var->type != Node_var_new) {
+ NODETYPE prevtype = var->type;
+ var->type = Node_var_new;
+ var->flags &= MALLOC;
+
+ /*
+ * If it's already clear, nothing to do
+ */
+ if (var->var_value != Nnull_string) {
+ if (prevtype == Node_var)
+ unref(var->var_value);
+ var->var_value = dupnode(Nnull_string);
+ }
}
- var->type = Node_var_new;
}
break;
diff --git a/test/let1.awk b/test/let1.awk
index 431fb8b8..90b1248b 100644
--- a/test/let1.awk
+++ b/test/let1.awk
@@ -43,6 +43,15 @@ BEGIN {
BEGIN {
@let (i = 3) { }
@let (a) { a[0] = 42 }
+ @let (i = 3) { }
+}
+
+# Yacc rules are duplicated for first versus rest, so we need additional coverage.
+
+BEGIN {
+ @let (x, i = 3) { }
+ @let (x, a) { a[0] = 42 }
+ @let (x, i = 3) { }
}
# test clearing uninitialized variables