plotnik_lib/engine/effect.rs
1//! Runtime effects for VM execution.
2//!
3//! Runtime effects carry actual node references, unlike bytecode EffectOp
4//! which only stores opcode + payload.
5
6use arborium_tree_sitter::Node;
7
8/// Runtime effect produced by VM execution.
9///
10/// Unlike bytecode `EffectOp`, runtime effects carry actual node references
11/// for materialization. Lifetime `'t` denotes the parsed tree-sitter tree.
12#[derive(Debug)]
13pub enum RuntimeEffect<'t> {
14 /// Capture a node reference.
15 Node(Node<'t>),
16 /// Extract source text from a node.
17 Text(Node<'t>),
18 /// Begin array scope.
19 Arr,
20 /// Push current value to array.
21 Push,
22 /// End array scope.
23 EndArr,
24 /// Begin object scope.
25 Obj,
26 /// Set field at member index.
27 Set(u16),
28 /// End object scope.
29 EndObj,
30 /// Begin enum variant at variant index.
31 Enum(u16),
32 /// End enum variant.
33 EndEnum,
34 /// Clear current value.
35 Clear,
36 /// Null placeholder (for optional/alternation).
37 Null,
38}
39
40/// Effect log with truncation support for backtracking.
41#[derive(Debug)]
42pub struct EffectLog<'t>(Vec<RuntimeEffect<'t>>);
43
44impl<'t> EffectLog<'t> {
45 /// Create an empty effect log.
46 pub fn new() -> Self {
47 Self(Vec::new())
48 }
49
50 /// Push an effect to the log.
51 #[inline]
52 pub fn push(&mut self, effect: RuntimeEffect<'t>) {
53 self.0.push(effect);
54 }
55
56 /// Get current length (used as watermark for backtracking).
57 #[inline]
58 pub fn len(&self) -> usize {
59 self.0.len()
60 }
61
62 /// Check if empty.
63 #[inline]
64 #[allow(dead_code)]
65 pub fn is_empty(&self) -> bool {
66 self.0.is_empty()
67 }
68
69 /// Truncate to watermark (for backtracking).
70 #[inline]
71 pub fn truncate(&mut self, watermark: usize) {
72 self.0.truncate(watermark);
73 }
74
75 /// Get effects as slice.
76 pub fn as_slice(&self) -> &[RuntimeEffect<'t>] {
77 &self.0
78 }
79
80 /// Consume into vec.
81 #[allow(dead_code)]
82 pub fn into_vec(self) -> Vec<RuntimeEffect<'t>> {
83 self.0
84 }
85}
86
87impl Default for EffectLog<'_> {
88 fn default() -> Self {
89 Self::new()
90 }
91}