summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--op.c11
-rw-r--r--pp_hot.c17
-rw-r--r--t/op/state.t44
3 files changed, 60 insertions, 12 deletions
diff --git a/op.c b/op.c
index 23b4b81863..f05be0b95e 100644
--- a/op.c
+++ b/op.c
@@ -3925,6 +3925,17 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
lop = lop->op_sibling;
}
}
+ else if (((left->op_private & (OPpLVAL_INTRO | OPpPAD_STATE))
+ == (OPpLVAL_INTRO | OPpPAD_STATE))
+ && ( left->op_type == OP_PADSV
+ || left->op_type == OP_PADAV
+ || left->op_type == OP_PADHV
+ || left->op_type == OP_PADANY))
+ {
+ o->op_private |= OPpASSIGN_STATE;
+ /* hijacking PADSTALE for uninitialized state variables */
+ SvPADSTALE_on(PAD_SVl(left->op_targ));
+ }
if (right && right->op_type == OP_SPLIT) {
OP* tmpop = ((LISTOP*)right)->op_first;
diff --git a/pp_hot.c b/pp_hot.c
index f01a3e06df..83ed6135cc 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -130,8 +130,11 @@ PP(pp_sassign)
else if (PL_op->op_private & OPpASSIGN_STATE) {
if (SvPADSTALE(right))
SvPADSTALE_off(right);
- else
+ else {
+ (void)POPs;
+ PUSHs(right);
RETURN; /* ignore assignment */
+ }
}
if (PL_tainting && PL_tainted && !SvTAINTED(left))
TAINT_NOT;
@@ -969,6 +972,12 @@ PP(pp_aassign)
int duplicates = 0;
SV **firsthashrelem = NULL; /* "= 0" keeps gcc 2.95 quiet */
+ if (PL_op->op_private & OPpASSIGN_STATE) {
+ if (SvPADSTALE(*firstlelem))
+ SvPADSTALE_off(*firstlelem);
+ else
+ RETURN; /* ignore assignment */
+ }
PL_delaymagic = DM_DELAY; /* catch simultaneous items */
gimme = GIMME_V;
@@ -986,12 +995,6 @@ PP(pp_aassign)
}
}
}
- if (PL_op->op_private & OPpASSIGN_STATE) {
- if (SvPADSTALE(*firstlelem))
- SvPADSTALE_off(*firstlelem);
- else
- RETURN; /* ignore assignment */
- }
relem = firstrelem;
lelem = firstlelem;
diff --git a/t/op/state.t b/t/op/state.t
index 9f618b0486..57b46ab32a 100644
--- a/t/op/state.t
+++ b/t/op/state.t
@@ -10,7 +10,7 @@ BEGIN {
use strict;
use feature "state";
-plan tests => 37;
+plan tests => 46;
ok( ! defined state $uninit, q(state vars are undef by default) );
@@ -20,23 +20,27 @@ sub stateful {
state $x;
state $y = 1;
my $z = 2;
- return ($x++, $y++, $z++);
+ state ($t) = 3;
+ return ($x++, $y++, $z++, $t++);
}
-my ($x, $y, $z) = stateful();
+my ($x, $y, $z, $t) = stateful();
is( $x, 0, 'uninitialized state var' );
is( $y, 1, 'initialized state var' );
is( $z, 2, 'lexical' );
+is( $t, 3, 'initialized state var, list syntax' );
-($x, $y, $z) = stateful();
+($x, $y, $z, $t) = stateful();
is( $x, 1, 'incremented state var' );
is( $y, 2, 'incremented state var' );
is( $z, 2, 'reinitialized lexical' );
+is( $t, 4, 'incremented state var, list syntax' );
-($x, $y, $z) = stateful();
+($x, $y, $z, $t) = stateful();
is( $x, 2, 'incremented state var' );
is( $y, 3, 'incremented state var' );
is( $z, 2, 'reinitialized lexical' );
+is( $t, 5, 'incremented state var, list syntax' );
# in a nested block
@@ -126,6 +130,18 @@ is( $xsize, 0, 'uninitialized state array' );
$xsize = stateful_array();
is( $xsize, 1, 'uninitialized state array after one iteration' );
+sub stateful_array_init {
+ state @x = (1, 2);
+ push @x, 'x';
+ return $#x;
+}
+
+$xsize = stateful_array_init();
+is( $xsize, 2, 'initialized state array' );
+
+$xsize = stateful_array_init();
+is( $xsize, 3, 'initialized state array after one iteration' );
+
# hash state vars
sub stateful_hash {
@@ -139,6 +155,17 @@ is( $xhval, 0, 'uninitialized state hash' );
$xhval = stateful_hash();
is( $xhval, 1, 'uninitialized state hash after one iteration' );
+sub stateful_hash_init {
+ state %hx = (foo => 10);
+ return $hx{foo}++;
+}
+
+$xhval = stateful_hash_init();
+is( $xhval, 10, 'initialized state hash' );
+
+$xhval = stateful_hash_init();
+is( $xhval, 11, 'initialized state hash after one iteration' );
+
# state declaration with a list
sub statelist {
@@ -175,3 +202,10 @@ sub noseworth {
noseworth($level - 1) if $level;
}
noseworth(2);
+
+# Assignment return value
+
+sub pugnax { my $x = state $y = 42; $y++; $x; }
+
+is( pugnax(), 42, 'scalar state assignment return value' );
+is( pugnax(), 43, 'scalar state assignment return value' );