rigz_vm/
builder.rs

1use crate::process::ModulesMap;
2use crate::vm::VMOptions;
3use crate::{
4    BinaryOperation, BroadcastArgs, Instruction, Lifecycle, LoadValue, Module, RigzType, Scope,
5    UnaryOperation, Value, VM,
6};
7use log::Level;
8use std::fmt::Debug;
9
10#[derive(Clone, Debug)]
11pub struct VMBuilder<'vm> {
12    pub sp: usize,
13    pub scopes: Vec<Scope<'vm>>,
14    pub modules: ModulesMap<'vm>,
15    pub options: VMOptions,
16    pub lifecycles: Vec<Lifecycle>,
17    pub constants: Vec<Value>,
18}
19
20impl Default for VMBuilder<'_> {
21    #[inline]
22    fn default() -> Self {
23        Self {
24            sp: 0,
25            scopes: vec![Default::default()],
26            modules: Default::default(),
27            options: Default::default(),
28            lifecycles: Default::default(),
29            constants: Default::default(),
30        }
31    }
32}
33
34#[macro_export]
35macro_rules! generate_unary_op_methods {
36    ($($name:ident => $variant:ident),*) => {
37        $(
38            #[inline]
39            fn $name(&mut self) -> &mut Self {
40                self.add_instruction(Instruction::Unary(UnaryOperation::$variant))
41            }
42        )*
43    };
44}
45
46#[macro_export]
47macro_rules! generate_bin_op_methods {
48    ($($name:ident => $variant:ident),*) => {
49        $(
50            #[inline]
51            fn $name(&mut self) -> &mut Self {
52                self.add_instruction(Instruction::Binary(BinaryOperation::$variant))
53            }
54        )*
55    };
56}
57
58pub trait RigzBuilder<'vm>: Debug + Default {
59    fn add_constant(&mut self, value: Value) -> usize;
60
61    fn add_instruction(&mut self, instruction: Instruction<'vm>) -> &mut Self;
62
63    fn build(self) -> VM<'vm>;
64
65    fn current_scope(&self) -> usize;
66
67    fn enter_scope(
68        &mut self,
69        named: &'vm str,
70        args: Vec<(&'vm str, bool)>,
71        set_self: Option<bool>,
72    ) -> usize;
73
74    fn enter_lifecycle_scope(
75        &mut self,
76        named: &'vm str,
77        lifecycle: Lifecycle,
78        args: Vec<(&'vm str, bool)>,
79        set_self: Option<bool>,
80    ) -> usize;
81
82    fn exit_scope(&mut self, current: usize) -> &mut Self;
83
84    fn convert_to_lazy_scope(&mut self, scope_id: usize, var: &'vm str) -> &mut Self;
85
86    fn module_exists(&mut self, module: &'vm str) -> bool;
87
88    #[cfg(feature = "threaded")]
89    fn register_module(&mut self, module: impl Module<'vm> + 'static + Send + Sync) -> &mut Self;
90
91    #[cfg(not(feature = "threaded"))]
92    fn register_module(&mut self, module: impl Module<'vm> + 'static) -> &mut Self;
93
94    fn with_options(&mut self, options: VMOptions) -> &mut Self;
95
96    generate_bin_op_methods! {
97        add_add_instruction => Add,
98        add_bitand_instruction => BitAnd,
99        add_bitor_instruction => BitOr,
100        add_bitxor_instruction => BitXor,
101        add_and_instruction => And,
102        add_or_instruction => Or,
103        add_xor_instruction => Xor,
104        add_div_instruction => Div,
105        add_mul_instruction => Mul,
106        add_rem_instruction => Rem,
107        add_shl_instruction => Shl,
108        add_shr_instruction => Shr,
109        add_sub_instruction => Sub,
110        add_gt_instruction => Gt,
111        add_gte_instruction => Gte,
112        add_lt_instruction => Lt,
113        add_lte_instruction => Lte,
114        add_elvis_instruction => Elvis
115    }
116
117    generate_unary_op_methods! {
118        add_neg_instruction => Neg,
119        add_not_instruction => Not,
120        add_print_instruction => Print,
121        add_eprint_instruction => EPrint,
122        add_println_instruction => PrintLn,
123        add_eprintln_instruction => EPrintLn,
124        add_reverse_instruction => Reverse
125    }
126
127    #[inline]
128    fn add_for_list_instruction(&mut self, scope: usize) -> &mut Self {
129        self.add_instruction(Instruction::ForList { scope })
130    }
131
132    #[inline]
133    fn add_for_map_instruction(&mut self, scope: usize) -> &mut Self {
134        self.add_instruction(Instruction::ForMap { scope })
135    }
136
137    #[inline]
138    fn add_unary_instruction(&mut self, op: UnaryOperation) -> &mut Self {
139        self.add_instruction(Instruction::Unary(op))
140    }
141
142    #[inline]
143    fn add_binary_instruction(&mut self, op: BinaryOperation) -> &mut Self {
144        self.add_instruction(Instruction::Binary(op))
145    }
146
147    #[inline]
148    fn add_binary_assign_instruction(&mut self, op: BinaryOperation) -> &mut Self {
149        self.add_instruction(Instruction::BinaryAssign(op))
150    }
151
152    #[inline]
153    fn add_call_module_instruction(
154        &mut self,
155        module: &'vm str,
156        func: &'vm str,
157        args: usize,
158    ) -> &mut Self {
159        self.add_instruction(Instruction::CallModule { module, func, args });
160        self
161    }
162
163    #[inline]
164    fn add_call_extension_module_instruction(
165        &mut self,
166        module: &'vm str,
167        func: &'vm str,
168        args: usize,
169    ) -> &mut Self {
170        self.add_instruction(Instruction::CallExtension { module, func, args });
171        self
172    }
173
174    #[inline]
175    fn add_call_mutable_extension_module_instruction(
176        &mut self,
177        module: &'vm str,
178        func: &'vm str,
179        args: usize,
180    ) -> &mut Self {
181        self.add_instruction(Instruction::CallMutableExtension { module, func, args });
182        self
183    }
184
185    #[inline]
186    fn add_call_vm_extension_module_instruction(
187        &mut self,
188        name: &'vm str,
189        func: &'vm str,
190        args: usize,
191    ) -> &mut Self {
192        self.add_instruction(Instruction::CallVMExtension {
193            module: name,
194            func,
195            args,
196        });
197        self
198    }
199
200    #[inline]
201    fn add_halt_instruction(&mut self) -> &mut Self {
202        self.add_instruction(Instruction::Halt)
203    }
204
205    #[inline]
206    fn add_ret_instruction(&mut self) -> &mut Self {
207        self.add_instruction(Instruction::Ret)
208    }
209
210    #[inline]
211    fn add_call_instruction(&mut self, scope: usize) -> &mut Self {
212        self.add_instruction(Instruction::Call(scope))
213    }
214
215    #[inline]
216    fn add_call_memo_instruction(&mut self, scope: usize) -> &mut Self {
217        self.add_instruction(Instruction::CallMemo(scope))
218    }
219
220    #[inline]
221    fn add_call_eq_instruction(&mut self, scope_id: usize) -> &mut Self {
222        self.add_instruction(Instruction::CallEq(scope_id))
223    }
224
225    #[inline]
226    fn add_call_neq_instruction(&mut self, scope_id: usize) -> &mut Self {
227        self.add_instruction(Instruction::CallNeq(scope_id))
228    }
229
230    #[inline]
231    fn add_if_else_instruction(&mut self, if_scope: usize, else_scope: usize) -> &mut Self {
232        self.add_instruction(Instruction::IfElse {
233            if_scope,
234            else_scope,
235        })
236    }
237
238    #[inline]
239    fn add_if_instruction(&mut self, if_scope: usize) -> &mut Self {
240        self.add_instruction(Instruction::If(if_scope))
241    }
242
243    #[inline]
244    fn add_unless_instruction(&mut self, unless_scope: usize) -> &mut Self {
245        self.add_instruction(Instruction::Unless(unless_scope))
246    }
247
248    #[inline]
249    fn add_cast_instruction(&mut self, rigz_type: RigzType) -> &mut Self {
250        self.add_instruction(Instruction::Cast { rigz_type })
251    }
252
253    #[inline]
254    fn add_pop_instruction(&mut self, amount: usize) -> &mut Self {
255        self.add_instruction(Instruction::Pop(amount))
256    }
257
258    #[inline]
259    fn add_load_instruction(&mut self, value: LoadValue) -> &mut Self {
260        self.add_instruction(Instruction::Load(value))
261    }
262
263    #[inline]
264    fn add_get_variable_reference_instruction(&mut self, name: &'vm str) -> &mut Self {
265        self.add_instruction(Instruction::GetVariableReference(name))
266    }
267
268    #[inline]
269    fn add_get_variable_instruction(&mut self, name: &'vm str) -> &mut Self {
270        self.add_instruction(Instruction::GetVariable(name))
271    }
272
273    #[inline]
274    fn add_get_mutable_variable_instruction(&mut self, name: &'vm str) -> &mut Self {
275        self.add_instruction(Instruction::GetMutableVariable(name))
276    }
277
278    #[inline]
279    fn add_get_self_instruction(&mut self) -> &mut Self {
280        self.add_instruction(Instruction::GetVariable("self"))
281    }
282
283    #[inline]
284    fn add_get_self_mut_instruction(&mut self) -> &mut Self {
285        self.add_instruction(Instruction::GetMutableVariable("self"))
286    }
287
288    #[inline]
289    fn add_load_let_instruction(&mut self, name: &'vm str) -> &mut Self {
290        self.add_instruction(Instruction::LoadLet(name))
291    }
292
293    #[inline]
294    fn add_load_mut_instruction(&mut self, name: &'vm str) -> &mut Self {
295        self.add_instruction(Instruction::LoadMut(name))
296    }
297
298    #[inline]
299    fn add_puts_instruction(&mut self, values: usize) -> &mut Self {
300        self.add_instruction(Instruction::Puts(values))
301    }
302
303    #[inline]
304    fn add_log_instruction(
305        &mut self,
306        level: Level,
307        template: &'vm str,
308        values: usize,
309    ) -> &mut Self {
310        self.add_instruction(Instruction::Log(level, template, values))
311    }
312
313    #[inline]
314    fn add_instance_get_instruction(&mut self, multiple: bool) -> &mut Self {
315        self.add_instruction(Instruction::InstanceGet(multiple))
316    }
317
318    #[inline]
319    fn add_instance_set_instruction(&mut self) -> &mut Self {
320        self.add_instruction(Instruction::InstanceSet)
321    }
322
323    #[inline]
324    fn add_send_instruction(&mut self, args: usize) -> &mut Self {
325        self.add_instruction(Instruction::Send(args))
326    }
327
328    #[inline]
329    fn add_receive_instruction(&mut self, args: usize) -> &mut Self {
330        self.add_instruction(Instruction::Receive(args))
331    }
332
333    #[inline]
334    fn add_spawn_instruction(&mut self, scope_id: usize, timeout: bool) -> &mut Self {
335        self.add_instruction(Instruction::Spawn(scope_id, timeout))
336    }
337
338    #[inline]
339    fn add_broadcast_instruction(&mut self, args: BroadcastArgs) -> &mut Self {
340        self.add_instruction(Instruction::Broadcast(args))
341    }
342
343    #[inline]
344    fn add_sleep_instruction(&mut self) -> &mut Self {
345        self.add_instruction(Instruction::Sleep)
346    }
347}
348
349#[macro_export]
350macro_rules! generate_builder {
351    () => {
352        /// call this before calling `enter_scope` or `enter_lifecycle_scope`, result should be used for `exit_scope`
353        fn current_scope(&self) -> usize {
354            self.sp
355        }
356
357        #[inline]
358        fn enter_scope(
359            &mut self,
360            named: &'vm str,
361            args: Vec<(&'vm str, bool)>,
362            set_self: Option<bool>,
363        ) -> usize {
364            let next = self.scopes.len();
365            self.scopes.push(Scope::new(named, args, set_self));
366            self.sp = self.scopes.len() - 1;
367            next
368        }
369
370        #[inline]
371        fn convert_to_lazy_scope(&mut self, scope_id: usize, variable: &'vm str) -> &mut Self {
372            let scope = &mut self.scopes[scope_id];
373            let last = scope.instructions.len() - 1;
374            scope
375                .instructions
376                .insert(last, Instruction::PersistScope(variable));
377            self
378        }
379
380        #[inline]
381        fn enter_lifecycle_scope(
382            &mut self,
383            named: &'vm str,
384            lifecycle: Lifecycle,
385            args: Vec<(&'vm str, bool)>,
386            set_self: Option<bool>,
387        ) -> usize {
388            let next = self.scopes.len();
389            self.scopes
390                .push(Scope::lifecycle(named, args, lifecycle, set_self));
391            self.sp = next;
392            next
393        }
394
395        #[inline]
396        fn exit_scope(&mut self, current: usize) -> &mut Self {
397            let s = self.add_instruction(Instruction::Ret);
398            s.sp = current;
399            s
400        }
401
402        #[inline]
403        #[cfg(feature = "threaded")]
404        fn register_module(
405            &mut self,
406            module: impl Module<'vm> + 'static + Send + Sync,
407        ) -> &mut Self {
408            self.modules
409                .insert(module.name(), std::sync::Arc::new(module));
410            self
411        }
412
413        #[inline]
414        #[cfg(not(feature = "threaded"))]
415        fn register_module(&mut self, module: impl Module<'vm> + 'static) -> &mut Self {
416            self.modules.insert(module.name(), Box::new(module));
417            self
418        }
419
420        #[inline]
421        fn with_options(&mut self, options: VMOptions) -> &mut Self {
422            self.options = options;
423            self
424        }
425
426        #[inline]
427        fn add_instruction(&mut self, instruction: Instruction<'vm>) -> &mut Self {
428            self.scopes[self.sp].instructions.push(instruction);
429            self
430        }
431
432        #[inline]
433        fn module_exists(&mut self, module: &'vm str) -> bool {
434            self.modules.contains_key(module)
435        }
436
437        #[inline]
438        fn add_constant(&mut self, value: Value) -> usize {
439            let index = self.constants.len();
440            self.constants.push(value);
441            index
442        }
443    };
444}
445
446impl<'vm> RigzBuilder<'vm> for VMBuilder<'vm> {
447    generate_builder!();
448
449    #[inline]
450    fn build(self) -> VM<'vm> {
451        VM {
452            scopes: self.scopes,
453            modules: self.modules,
454            options: self.options,
455            lifecycles: self.lifecycles,
456            constants: self.constants,
457            ..Default::default()
458        }
459    }
460}
461
462impl VMBuilder<'_> {
463    #[inline]
464    pub fn new() -> Self {
465        Self::default()
466    }
467}