summaryrefslogtreecommitdiff
path: root/ext/B/ramblings/flip-flop
blob: e08333d172dbc88798410b58826f11c8654cbffb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
PP(pp_range)
{
    if (GIMME == G_ARRAY)
        return NORMAL;
    if (SvTRUEx(PAD_SV(PL_op->op_targ)))
	return cLOGOP->op_other;
    else
	return NORMAL;
}

pp_range is a LOGOP.
In list context, it just returns op_next.
In scalar context it checks the truth of targ and returns
op_other if true, op_next if false.

flip is an UNOP.
It "looks after" its child which is always a pp_range LOGOP.
In list context, it just returns the child's op_other.
In scalar context, there are three possible outcomes:
  (1) set child's targ to 1, our targ to 1 and return op_next.
  (2) set child's targ to 1, our targ to 0, sp-- and return child's op_other.
  (3) Blank targ and  TOPs and return op_next.
Case 1 happens for a "..." with a matching lineno... or true TOPs.
Case 2 happens for a ".." with a matching lineno... or true TOPs.
Case 3 happens for a non-matching lineno or false TOPs.

               $a = lhs..rhs;

        ,------->  range
        ^         /     \
        |    true/       \false
        |       /         \
   first|     lhs        rhs
        |      \   first   /
        ^--- flip <----- flop
                 \       /
                  \     /
                  sassign


/* range */
if (SvTRUE(curpad[op->op_targ]))
    goto label(op_other);
/* op_next */
...
/* flip */
/* For "..." returns op_next. For ".." returns op_next or op_first->op_other */
/* end of basic block */
goto out;
label(range op_other):
...
/* flop */
out:
...