Skip to content
← Back

src/syntax/process/receiver_shield.ghul

1
namespace Syntax.Process is
2
use Symbol = Semantic.Symbols.Symbol;
3
4
// One in-flight assignment-receiver shield: the field held exempt
5
// from the call transfer, and whether a call occurred while it was
6
// held (so the assignment drops the field once the receiver is read).
7
class SHIELD_FRAME is
8
symbol: Symbol public;
9
hit: bool public;
10
11
init(symbol: Symbol) is
12
self.symbol = symbol;
13
hit = false;
14
si
15
si
16
17
// The set of assignment-target receivers currently exempt from the
18
// call transfer. A member/index assignment's receiver is read before
19
// its right-hand side runs, so a call there must not drop the
20
// receiver's presence; it is shielded for the duration of the
21
// assignment and dropped afterwards only if a call actually occurred.
22
//
23
// A stack, so an assignment nested in a lambda or block inside an
24
// outer assignment's right-hand side shields its own receiver without
25
// disturbing the outer one. Each frame records whether a shielded
26
// call occurred. Owned by NARROWING_FLOW, which consults it in the
27
// call transfer (`on_call`).
28
class RECEIVER_SHIELD is
29
_frames: Collections.LIST[SHIELD_FRAME];
30
31
init() is
32
_frames = Collections.LIST[SHIELD_FRAME]();
33
si
34
35
// Shield `v` until its frame is released, returning the frame to
36
// release with — null (a no-op frame) when `v` is null. Frames
37
// stack for nested assignments.
38
push(v: Symbol?) -> SHIELD_FRAME? is
39
if !v? then
40
return null;
41
fi
42
43
let frame = SHIELD_FRAME(v);
44
45
_frames.add(frame);
46
47
return frame;
48
si
49
50
// Release a frame from `push`. Returns true iff a call occurred
51
// while it was shielding — the caller then drops the field, since
52
// the receiver read that justified the shield is done and later
53
// reads must observe the post-call state.
54
release(frame: SHIELD_FRAME?) -> bool is
55
if !frame? then
56
return false;
57
fi
58
59
_frames.remove(frame);
60
61
return frame.hit;
62
si
63
64
// True iff `v` is shielded by an in-flight assignment receiver.
65
// Marks every frame shielding it as hit so its assignment drops
66
// it once the receiver has been read.
67
mark_if_shielded(v: Symbol) -> bool is
68
let shielded mut = false;
69
70
for frame in _frames do
71
if frame.symbol == v then
72
frame.hit = true;
73
shielded = true;
74
fi
75
od
76
77
return shielded;
78
si
79
si
80
si