Skip to main content

ruso_runtime/runtime/
bytecode.rs

1//! Executable bytecode produced from the script AST.
2
3use crate::contract::{EvidenceKind, ExtractSource, QualifiedMatch};
4use crate::runtime::spec::ProgramSpec;
5
6/// Compiled script ready for the executor (probes, metadata, and instruction stream).
7#[derive(Debug, Clone)]
8pub struct BytecodeProgram {
9    /// Probe table and finding metadata (the non-executable part).
10    pub spec: ProgramSpec,
11    /// The instruction stream the executor walks.
12    pub code: Vec<Instr>,
13    /// String pool. Instruction operands index into this.
14    pub strings: Vec<String>,
15    /// Binary payloads referenced by `Send.payload` (override bytes).
16    pub payloads: Vec<Vec<u8>>,
17    /// Matcher pool, indexed by `Match`/`Assert`/`IfMatch` operands.
18    pub matchers: Vec<QualifiedMatch>,
19    /// Extract-rule pool, indexed by `Extract` operands.
20    pub extracts: Vec<ExtractSource>,
21    /// Evidence-rule pool, indexed by `Evidence` operands.
22    pub evidence: Vec<EvidenceKind>,
23}
24
25/// Instruction pointer index into `BytecodeProgram::code`.
26pub type Pc = u32;
27
28/// A single VM instruction. Operands are `u32`/`u16` indices into the
29/// program's pools (`strings`, `matchers`, `extracts`, `evidence`) or program
30/// counters ([`Pc`]) into `code` — never inline data.
31#[derive(Debug, Clone, PartialEq)]
32pub enum Instr {
33    /// Set a string variable: `name` and `value` index the string pool.
34    Set {
35        /// String-pool index of the variable name.
36        name: u32,
37        /// String-pool index of the value.
38        value: u32,
39    },
40    /// Set a list variable from `len` consecutive strings starting at `start`.
41    SetList {
42        /// String-pool index of the variable name.
43        name: u32,
44        /// String-pool index of the first element.
45        start: u32,
46        /// Number of elements.
47        len: u16,
48    },
49    /// Perform a probe's request. `payload`, if set, overrides the probe's
50    /// payload (string-pool or payload-pool index, per probe kind).
51    Send {
52        /// String-pool index of the probe name.
53        probe: u32,
54        /// Optional payload-override index.
55        payload: Option<u32>,
56    },
57    /// Evaluate one matcher (matcher-pool index); on failure, latch the match
58    /// chain false.
59    Match(u32),
60    /// Evaluate `len` matchers starting at `start`; all must pass.
61    MatchAll {
62        /// Matcher-pool index of the first matcher.
63        start: u32,
64        /// Number of matchers.
65        len: u16,
66    },
67    /// Evaluate `len` matchers starting at `start`; any one passing succeeds.
68    MatchAny {
69        /// Matcher-pool index of the first matcher.
70        start: u32,
71        /// Number of matchers.
72        len: u16,
73    },
74    /// Like `Match`, but a failure aborts the run with an error.
75    Assert(u32),
76    /// Extract a value into a variable. `name` is a string-pool index; `source`
77    /// indexes the extract pool.
78    Extract {
79        /// String-pool index of the destination variable name.
80        name: u32,
81        /// Extract-pool index of the source rule.
82        source: u32,
83    },
84    /// If the matcher holds, fall through; otherwise jump to `else_pc`.
85    IfMatch {
86        /// Matcher-pool index of the condition.
87        matcher: u32,
88        /// Program counter to jump to when the condition is false.
89        else_pc: Pc,
90    },
91    /// Begin a `for` over a literal list (`len` strings from `start`), binding
92    /// each to `item`. `end_pc` is the instruction after the loop.
93    ForList {
94        /// String-pool index of the loop variable name.
95        item: u32,
96        /// String-pool index of the first value.
97        start: u32,
98        /// Number of values.
99        len: u16,
100        /// Program counter just past the loop.
101        end_pc: Pc,
102    },
103    /// Begin a `for` over a list variable (`list`), binding each to `item`.
104    ForVar {
105        /// String-pool index of the loop variable name.
106        item: u32,
107        /// String-pool index of the list variable name.
108        list: u32,
109        /// Program counter just past the loop.
110        end_pc: Pc,
111    },
112    /// End-of-loop-body marker: advance the loop or exit it.
113    LoopBack,
114    /// Exit the innermost loop.
115    Break,
116    /// Snapshot a probe's response under another name (`from`/`to` index the
117    /// string pool).
118    Save {
119        /// String-pool index of the source probe name.
120        from: u32,
121        /// String-pool index of the destination name.
122        to: u32,
123    },
124    /// Attach evidence (evidence-pool index) when the match chain is true.
125    Evidence(u32),
126    /// Re-send a probe up to `count` times, stopping on first success.
127    Retry {
128        /// String-pool index of the probe name.
129        probe: u32,
130        /// Maximum attempts.
131        count: u32,
132    },
133    /// Set the delay between `Retry` attempts (string-pool index of a duration).
134    RetryDelay(u32),
135    /// Sleep for a duration (string-pool index of a duration literal).
136    Sleep(u32),
137    /// Stop the run, emitting no finding.
138    Stop,
139    /// Abort the run with an error.
140    Fail,
141    /// Skip to the next iteration of the innermost loop.
142    Continue,
143    /// Stop the run, emitting the finding if the match chain held.
144    Exit,
145}
146
147impl BytecodeProgram {
148    /// Number of instructions in the program's `code` stream.
149    pub fn instr_count(&self) -> usize {
150        self.code.len()
151    }
152}