Skip to main content

regorus/rvm/instructions/
params.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3use alloc::vec::Vec;
4use serde::{Deserialize, Serialize};
5
6use super::types::{ComprehensionMode, LiteralOrRegister, LoopMode};
7
8/// Loop parameters stored in program's instruction data table
9#[repr(C)]
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct LoopStartParams {
12    /// Loop mode (Existential/Universal/Comprehension types)
13    pub mode: LoopMode,
14    /// Register containing the collection to iterate over
15    pub collection: u8,
16    /// Register to store current key (same as value_reg if key not needed)
17    pub key_reg: u8,
18    /// Register to store current value
19    pub value_reg: u8,
20    /// Register to store final result
21    pub result_reg: u8,
22    /// Jump target for loop body start
23    pub body_start: u16,
24    /// Jump target for loop end
25    pub loop_end: u16,
26}
27
28/// Builtin function call parameters stored in program's instruction data table
29#[repr(C)]
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct BuiltinCallParams {
32    /// Destination register to store the result
33    pub dest: u8,
34    /// Index into program's builtin_info_table
35    pub builtin_index: u16,
36    /// Number of arguments actually used
37    pub num_args: u8,
38    /// Argument register numbers (unused slots contain undefined values)
39    pub args: [u8; 8],
40}
41
42impl BuiltinCallParams {
43    /// Get the number of arguments actually used
44    pub fn arg_count(&self) -> usize {
45        usize::from(self.num_args)
46    }
47
48    /// Get argument register numbers as a slice
49    pub fn arg_registers(&self) -> &[u8] {
50        let count = usize::from(self.num_args).min(self.args.len());
51        self.args.get(..count).unwrap_or(&[])
52    }
53}
54
55/// Function rule call parameters stored in program's instruction data table
56#[repr(C)]
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct FunctionCallParams {
59    /// Destination register to store the result
60    pub dest: u8,
61    /// Rule index of the function to call
62    pub func_rule_index: u16,
63    /// Number of arguments actually used
64    pub num_args: u8,
65    /// Argument register numbers (unused slots contain undefined values)
66    pub args: [u8; 8],
67}
68
69impl FunctionCallParams {
70    /// Get the number of arguments actually used
71    pub fn arg_count(&self) -> usize {
72        usize::from(self.num_args)
73    }
74
75    /// Get argument register numbers as a slice
76    pub fn arg_registers(&self) -> &[u8] {
77        let count = usize::from(self.num_args).min(self.args.len());
78        self.args.get(..count).unwrap_or(&[])
79    }
80}
81
82/// Object creation parameters stored in program's instruction data table
83#[repr(C)]
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct ObjectCreateParams {
86    /// Destination register to store the result object
87    pub dest: u8,
88    /// Literal index of template object with all keys (undefined values)
89    /// Always present - empty object if no literal keys
90    pub template_literal_idx: u16,
91    /// Fields with literal keys: (literal_key_index, value_register) in sorted order
92    pub literal_key_fields: Vec<(u16, u8)>,
93    /// Fields with non-literal keys: (key_register, value_register)
94    pub fields: Vec<(u8, u8)>,
95}
96
97impl ObjectCreateParams {
98    /// Get the total number of fields
99    pub const fn field_count(&self) -> usize {
100        self.literal_key_fields
101            .len()
102            .saturating_add(self.fields.len())
103    }
104
105    /// Get literal key field pairs as a slice
106    pub fn literal_key_field_pairs(&self) -> &[(u16, u8)] {
107        &self.literal_key_fields
108    }
109
110    /// Get non-literal key field pairs as a slice
111    pub fn field_pairs(&self) -> &[(u8, u8)] {
112        &self.fields
113    }
114}
115
116/// Array creation parameters stored in program's instruction data table
117#[repr(C)]
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct ArrayCreateParams {
120    /// Destination register to store the result array
121    pub dest: u8,
122    /// Register numbers containing the element values
123    pub elements: Vec<u8>,
124}
125
126impl ArrayCreateParams {
127    /// Get the number of elements
128    pub const fn element_count(&self) -> usize {
129        self.elements.len()
130    }
131
132    /// Get element register numbers as a slice
133    pub fn element_registers(&self) -> &[u8] {
134        &self.elements
135    }
136}
137
138/// Set creation parameters stored in program's instruction data table
139#[repr(C)]
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct SetCreateParams {
142    /// Destination register to store the result set
143    pub dest: u8,
144    /// Register numbers containing the element values
145    pub elements: Vec<u8>,
146}
147
148impl SetCreateParams {
149    /// Get the number of elements
150    pub const fn element_count(&self) -> usize {
151        self.elements.len()
152    }
153
154    /// Get element register numbers as a slice
155    pub fn element_registers(&self) -> &[u8] {
156        &self.elements
157    }
158}
159
160/// Virtual data document lookup parameters for data namespace access with rule evaluation
161#[repr(C)]
162#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct VirtualDataDocumentLookupParams {
164    /// Destination register to store the result
165    pub dest: u8,
166    /// Path components in order (e.g., for data.users[input.name].config)
167    /// This would be [Literal("users"), Register(5), Literal("config")]
168    /// where register 5 contains the value from input.name
169    pub path_components: Vec<LiteralOrRegister>,
170}
171
172impl VirtualDataDocumentLookupParams {
173    /// Get the number of path components
174    pub const fn component_count(&self) -> usize {
175        self.path_components.len()
176    }
177
178    /// Check if all components are literals (can be optimized at compile time)
179    pub fn all_literals(&self) -> bool {
180        self.path_components
181            .iter()
182            .all(|c| matches!(c, LiteralOrRegister::Literal(_)))
183    }
184
185    /// Get just the literal indices (for debugging/display)
186    pub fn literal_indices(&self) -> Vec<u16> {
187        self.path_components
188            .iter()
189            .filter_map(|c| match *c {
190                LiteralOrRegister::Literal(idx) => Some(idx),
191                _ => None,
192            })
193            .collect()
194    }
195
196    /// Get just the register numbers (for debugging/display)
197    pub fn register_numbers(&self) -> Vec<u8> {
198        self.path_components
199            .iter()
200            .filter_map(|c| match *c {
201                LiteralOrRegister::Register(reg) => Some(reg),
202                _ => None,
203            })
204            .collect()
205    }
206}
207
208/// Chained index parameters for multi-level object access (input, locals, non-rule data paths)
209#[repr(C)]
210#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct ChainedIndexParams {
212    /// Destination register to store the result
213    pub dest: u8,
214    /// Root register containing the base object (input, local var, data subset)
215    pub root: u8,
216    /// Path components to traverse from the root
217    pub path_components: Vec<LiteralOrRegister>,
218}
219
220impl ChainedIndexParams {
221    /// Get the number of path components
222    pub const fn component_count(&self) -> usize {
223        self.path_components.len()
224    }
225
226    /// Check if all components are literals (can be optimized)
227    pub fn all_literals(&self) -> bool {
228        self.path_components
229            .iter()
230            .all(|c| matches!(c, LiteralOrRegister::Literal(_)))
231    }
232
233    /// Get just the literal indices (for debugging/display)
234    pub fn literal_indices(&self) -> Vec<u16> {
235        self.path_components
236            .iter()
237            .filter_map(|c| match *c {
238                LiteralOrRegister::Literal(idx) => Some(idx),
239                _ => None,
240            })
241            .collect()
242    }
243
244    /// Get just the register numbers (for debugging/display)
245    pub fn register_numbers(&self) -> Vec<u8> {
246        self.path_components
247            .iter()
248            .filter_map(|c| match *c {
249                LiteralOrRegister::Register(reg) => Some(reg),
250                _ => None,
251            })
252            .collect()
253    }
254}
255
256/// Comprehension parameters stored in program's instruction data table
257#[repr(C)]
258#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct ComprehensionBeginParams {
260    /// Type of comprehension being created
261    pub mode: ComprehensionMode,
262    /// Register containing the source collection to iterate over
263    pub collection_reg: u8,
264    /// Register to store the comprehension result collection
265    /// If not specified separately, this will match collection_reg
266    pub result_reg: u8,
267    /// Register to store current iteration key
268    pub key_reg: u8,
269    /// Register to store current iteration value
270    pub value_reg: u8,
271    /// Jump target for comprehension body start
272    pub body_start: u16,
273    /// Jump target for comprehension end
274    pub comprehension_end: u16,
275}
276
277/// Instruction data container for complex instruction parameters
278#[derive(Debug, Clone, Serialize, Deserialize)]
279pub struct InstructionData {
280    /// Loop parameter table for LoopStart instructions
281    pub loop_params: Vec<LoopStartParams>,
282    /// Builtin function call parameter table for BuiltinCall instructions
283    pub builtin_call_params: Vec<BuiltinCallParams>,
284    /// Function rule call parameter table for FunctionCall instructions
285    pub function_call_params: Vec<FunctionCallParams>,
286    /// Object creation parameter table for ObjectCreate instructions
287    pub object_create_params: Vec<ObjectCreateParams>,
288    /// Array creation parameter table for ArrayCreate instructions
289    pub array_create_params: Vec<ArrayCreateParams>,
290    /// Set creation parameter table for SetCreate instructions
291    pub set_create_params: Vec<SetCreateParams>,
292    /// Virtual data document lookup parameter table for VirtualDataDocumentLookup instructions
293    pub virtual_data_document_lookup_params: Vec<VirtualDataDocumentLookupParams>,
294    /// Chained index parameter table for ChainedIndex instructions
295    pub chained_index_params: Vec<ChainedIndexParams>,
296    /// Comprehension parameter table for ComprehensionBegin instructions
297    pub comprehension_begin_params: Vec<ComprehensionBeginParams>,
298}
299
300impl InstructionData {
301    fn ensure_u16_index(len: usize) -> u16 {
302        debug_assert!(len <= usize::from(u16::MAX));
303        u16::try_from(len).unwrap_or(u16::MAX)
304    }
305
306    /// Create a new empty instruction data container
307    pub const fn new() -> Self {
308        Self {
309            loop_params: Vec::new(),
310            builtin_call_params: Vec::new(),
311            function_call_params: Vec::new(),
312            object_create_params: Vec::new(),
313            array_create_params: Vec::new(),
314            set_create_params: Vec::new(),
315            virtual_data_document_lookup_params: Vec::new(),
316            chained_index_params: Vec::new(),
317            comprehension_begin_params: Vec::new(),
318        }
319    }
320
321    /// Add loop parameters and return the index
322    pub fn add_loop_params(&mut self, params: LoopStartParams) -> u16 {
323        let index = Self::ensure_u16_index(self.loop_params.len());
324        self.loop_params.push(params);
325        index
326    }
327
328    /// Add builtin call parameters and return the index
329    pub fn add_builtin_call_params(&mut self, params: BuiltinCallParams) -> u16 {
330        let index = Self::ensure_u16_index(self.builtin_call_params.len());
331        self.builtin_call_params.push(params);
332        index
333    }
334
335    /// Add function call parameters and return the index
336    pub fn add_function_call_params(&mut self, params: FunctionCallParams) -> u16 {
337        let index = Self::ensure_u16_index(self.function_call_params.len());
338        self.function_call_params.push(params);
339        index
340    }
341
342    /// Add object create parameters and return the index
343    pub fn add_object_create_params(&mut self, params: ObjectCreateParams) -> u16 {
344        let index = Self::ensure_u16_index(self.object_create_params.len());
345        self.object_create_params.push(params);
346        index
347    }
348
349    /// Add array create parameters and return the index
350    pub fn add_array_create_params(&mut self, params: ArrayCreateParams) -> u16 {
351        let index = Self::ensure_u16_index(self.array_create_params.len());
352        self.array_create_params.push(params);
353        index
354    }
355
356    /// Add set create parameters and return the index
357    pub fn add_set_create_params(&mut self, params: SetCreateParams) -> u16 {
358        let index = Self::ensure_u16_index(self.set_create_params.len());
359        self.set_create_params.push(params);
360        index
361    }
362
363    /// Get loop parameters by index
364    pub fn get_loop_params(&self, index: u16) -> Option<&LoopStartParams> {
365        self.loop_params.get(usize::from(index))
366    }
367
368    /// Get builtin call parameters by index
369    pub fn get_builtin_call_params(&self, index: u16) -> Option<&BuiltinCallParams> {
370        self.builtin_call_params.get(usize::from(index))
371    }
372
373    /// Get function call parameters by index
374    pub fn get_function_call_params(&self, index: u16) -> Option<&FunctionCallParams> {
375        self.function_call_params.get(usize::from(index))
376    }
377
378    /// Get object create parameters by index
379    pub fn get_object_create_params(&self, index: u16) -> Option<&ObjectCreateParams> {
380        self.object_create_params.get(usize::from(index))
381    }
382
383    /// Get array create parameters by index
384    pub fn get_array_create_params(&self, index: u16) -> Option<&ArrayCreateParams> {
385        self.array_create_params.get(usize::from(index))
386    }
387
388    /// Get set create parameters by index
389    pub fn get_set_create_params(&self, index: u16) -> Option<&SetCreateParams> {
390        self.set_create_params.get(usize::from(index))
391    }
392
393    /// Add virtual data document lookup parameters and return the index
394    pub fn add_virtual_data_document_lookup_params(
395        &mut self,
396        params: VirtualDataDocumentLookupParams,
397    ) -> u16 {
398        let index = Self::ensure_u16_index(self.virtual_data_document_lookup_params.len());
399        self.virtual_data_document_lookup_params.push(params);
400        index
401    }
402
403    /// Get virtual data document lookup parameters by index
404    pub fn get_virtual_data_document_lookup_params(
405        &self,
406        index: u16,
407    ) -> Option<&VirtualDataDocumentLookupParams> {
408        self.virtual_data_document_lookup_params
409            .get(usize::from(index))
410    }
411
412    /// Add chained index parameters and return the index
413    pub fn add_chained_index_params(&mut self, params: ChainedIndexParams) -> u16 {
414        let index = Self::ensure_u16_index(self.chained_index_params.len());
415        self.chained_index_params.push(params);
416        index
417    }
418
419    /// Get chained index parameters by index
420    pub fn get_chained_index_params(&self, index: u16) -> Option<&ChainedIndexParams> {
421        self.chained_index_params.get(usize::from(index))
422    }
423
424    /// Get mutable reference to loop parameters by index
425    pub fn get_loop_params_mut(&mut self, index: u16) -> Option<&mut LoopStartParams> {
426        self.loop_params.get_mut(usize::from(index))
427    }
428
429    /// Add comprehension begin parameters and return the index
430    pub fn add_comprehension_begin_params(&mut self, params: ComprehensionBeginParams) -> u16 {
431        let index = Self::ensure_u16_index(self.comprehension_begin_params.len());
432        self.comprehension_begin_params.push(params);
433        index
434    }
435
436    /// Get comprehension begin parameters by index
437    pub fn get_comprehension_begin_params(&self, index: u16) -> Option<&ComprehensionBeginParams> {
438        self.comprehension_begin_params.get(usize::from(index))
439    }
440
441    /// Get mutable reference to comprehension begin parameters by index
442    pub fn get_comprehension_begin_params_mut(
443        &mut self,
444        index: u16,
445    ) -> Option<&mut ComprehensionBeginParams> {
446        self.comprehension_begin_params.get_mut(usize::from(index))
447    }
448}
449
450impl Default for InstructionData {
451    fn default() -> Self {
452        Self::new()
453    }
454}