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 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}