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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/// # An event triggered by scripts, to signal a specific condition
///
/// Effects moderate the communication between script and host. The effect
/// itself only relays _which_ effect has triggered, but that may signal to
/// the host that a different communication channel (like operand stack or
/// memory) is ready to be accessed.
///
/// ## Handling Effects
///
/// The host may handle effects however it wishes. But since most effects
/// signal error conditions that the script would not expect to recover
/// from, a well-behaving host must be careful not to handle effects in
/// a way that make reasoning about the script's behavior difficult.
///
/// Abandoning the evaluation and reporting an error in the appropriate
/// manner, is the only reasonable way to handle most effects. The
/// exception to that is [`Effect::Yield`], which does not signal an error
/// condition. A script would expect to continue afterwards.
///
/// To make that possible, the host must clear the effect by calling
/// [`Eval::clear_effect`].
///
/// ### Example
///
/// ```
/// use stack_assembly::{Effect, Eval, Script};
///
/// // This script increments a number in a loop, yielding control to the
/// // host every time it did so.
/// let script = Script::compile("
/// 0
///
/// increment:
/// 1 +
/// yield
/// @increment jump
/// ");
///
/// let mut eval = Eval::new();
///
/// // When running the script for the first time, we expect that it has
/// // incremented the number once, before yielding.
/// let (effect, _) = eval.run(&script);
/// assert_eq!(effect, Effect::Yield);
/// assert_eq!(eval.operand_stack.to_u32_slice(), &[1]);
///
/// // To allow the script to continue, we must clear the effect.
/// eval.clear_effect();
///
/// // Since we handled the effect correctly, we can now assume that the
/// // script has incremented the number a second time, before yielding
/// // again.
/// let (effect, _) = eval.run(&script);
/// assert_eq!(effect, Effect::Yield);
/// assert_eq!(eval.operand_stack.to_u32_slice(), &[2]);
/// ```
///
/// [`Eval::clear_effect`]: crate::Eval::clear_effect