1use intuicio_core::{
2 context::Context,
3 function::{
4 Function, FunctionBody, FunctionParameter, FunctionQuery, FunctionQueryParameter,
5 FunctionSignature,
6 },
7 host::Host,
8 nativizer::ScriptNativizer,
9 registry::Registry,
10 script::{
11 ScriptExpression, ScriptFunction, ScriptFunctionSignature, ScriptOperation, ScriptStruct,
12 ScriptStructField,
13 },
14 struct_type::{StructFieldQuery, StructQuery},
15 Visibility,
16};
17use std::fmt::{Error, Write};
18
19#[derive(Debug, Copy, Clone, PartialEq, Eq)]
20enum ScopeKind {
21 Normal,
22 Branch,
23 Loop,
24}
25
26pub trait RustHostExpressionNativizer<SE: ScriptExpression> {
27 fn nativize_expression(&mut self, output: &mut dyn Write, input: &SE) -> Result<(), Error>;
28}
29
30impl<SE: ScriptExpression> RustHostExpressionNativizer<SE> for () {
31 fn nativize_expression(&mut self, _: &mut dyn Write, _: &SE) -> Result<(), Error> {
32 Ok(())
33 }
34}
35
36pub struct RustHostNativizer<'a, SE: ScriptExpression> {
37 pub tab_size: usize,
38 indent: usize,
39 scope_kind: Vec<ScopeKind>,
40 registry: &'a Registry,
41 expression_nativizer: Box<dyn RustHostExpressionNativizer<SE>>,
42}
43
44impl<'a, SE: ScriptExpression> RustHostNativizer<'a, SE> {
45 pub fn new(
46 registry: &'a Registry,
47 expression_nativizer: impl RustHostExpressionNativizer<SE> + 'static,
48 ) -> Self {
49 Self {
50 tab_size: 4,
51 indent: 0,
52 scope_kind: vec![],
53 registry,
54 expression_nativizer: Box::new(expression_nativizer),
55 }
56 }
57
58 pub fn with_tab_size(mut self, size: usize) -> Self {
59 self.tab_size = size;
60 self
61 }
62
63 pub fn push_indent(&mut self) {
64 self.indent += 1;
65 }
66
67 pub fn pop_indent(&mut self) {
68 if self.indent > 0 {
69 self.indent -= 1;
70 }
71 }
72
73 pub fn pad(&mut self, output: &mut dyn Write) -> Result<(), Error> {
74 for _ in 0..(self.indent * self.tab_size) {
75 output.write_char(' ')?;
76 }
77 Ok(())
78 }
79
80 pub fn write_visibility(
81 &mut self,
82 output: &mut dyn Write,
83 input: Visibility,
84 ) -> Result<(), Error> {
85 match input {
86 Visibility::Private => {}
87 Visibility::Module => {
88 write!(output, "pub(crate) ")?;
89 }
90 Visibility::Public => {
91 write!(output, "pub ")?;
92 }
93 }
94 Ok(())
95 }
96
97 pub fn write_struct_field_query(
98 &mut self,
99 output: &mut dyn Write,
100 input: &StructFieldQuery,
101 ) -> Result<(), Error> {
102 writeln!(output, "{} {{", std::any::type_name::<StructFieldQuery>())?;
103 self.push_indent();
104 self.pad(output)?;
105 if let Some(name) = input.name.as_ref() {
106 writeln!(output, r#"name: Some("{}".into()),"#, name.as_ref())?;
107 } else {
108 writeln!(output, "name: None,")?;
109 }
110 self.pad(output)?;
111 if let Some(struct_query) = input.struct_query.as_ref() {
112 write!(output, "struct_query: Some(")?;
113 self.write_struct_query(output, struct_query)?;
114 writeln!(output, "),")?;
115 } else {
116 writeln!(output, "struct_query: None,")?;
117 }
118 self.pad(output)?;
119 writeln!(
120 output,
121 "visibility: {}::{:?},",
122 std::any::type_name::<Visibility>(),
123 input.visibility
124 )?;
125 self.pop_indent();
126 self.pad(output)?;
127 write!(output, "}}")
128 }
129
130 pub fn write_struct_query(
131 &mut self,
132 output: &mut dyn Write,
133 input: &StructQuery,
134 ) -> Result<(), Error> {
135 writeln!(output, "{} {{", std::any::type_name::<StructQuery>())?;
136 self.push_indent();
137 self.pad(output)?;
138 if let Some(name) = input.name.as_ref() {
139 writeln!(output, r#"name: Some("{}".into()),"#, name.as_ref())?;
140 } else {
141 writeln!(output, "name: None,")?;
142 }
143 self.pad(output)?;
144 writeln!(output, "type_hash: None,")?;
145 self.pad(output)?;
146 if let Some(module_name) = input.module_name.as_ref() {
147 writeln!(
148 output,
149 r#"module_name: Some("{}".into()),"#,
150 module_name.as_ref()
151 )?;
152 } else {
153 writeln!(output, "module_name: None,")?;
154 }
155 self.pad(output)?;
156 if let Some(visibility) = input.visibility {
157 writeln!(
158 output,
159 "visibility: Some({}::{:?}),",
160 std::any::type_name::<Visibility>(),
161 visibility
162 )?;
163 } else {
164 writeln!(output, "visibility: None,")?;
165 }
166 self.pad(output)?;
167 writeln!(output, "fields: [")?;
168 self.push_indent();
169 for field in input.fields.as_ref() {
170 self.pad(output)?;
171 self.write_struct_field_query(output, field)?;
172 writeln!(output, ",")?;
173 }
174 self.pop_indent();
175 self.pad(output)?;
176 writeln!(output, "].as_slice().into(),")?;
177 self.pop_indent();
178 self.pad(output)?;
179 write!(output, "}}")
180 }
181
182 pub fn write_function_parameter_query(
183 &mut self,
184 output: &mut dyn Write,
185 input: &FunctionQueryParameter,
186 ) -> Result<(), Error> {
187 writeln!(
188 output,
189 "{} {{",
190 std::any::type_name::<FunctionQueryParameter>()
191 )?;
192 self.push_indent();
193 self.pad(output)?;
194 if let Some(name) = input.name.as_ref() {
195 writeln!(output, r#"name: Some("{}".into()),"#, name.as_ref())?;
196 } else {
197 writeln!(output, "name: None,")?;
198 }
199 self.pad(output)?;
200 if let Some(struct_query) = input.struct_query.as_ref() {
201 write!(output, "struct_query: Some(")?;
202 self.write_struct_query(output, struct_query)?;
203 writeln!(output, "),")?;
204 } else {
205 writeln!(output, "struct_query: None,")?;
206 }
207 self.pop_indent();
208 self.pad(output)?;
209 write!(output, "}}")
210 }
211
212 pub fn write_function_query(
213 &mut self,
214 output: &mut dyn Write,
215 input: &FunctionQuery,
216 ) -> Result<(), Error> {
217 writeln!(output, "{} {{", std::any::type_name::<FunctionQuery>())?;
218 self.push_indent();
219 self.pad(output)?;
220 if let Some(name) = input.name.as_ref() {
221 writeln!(output, r#"name: Some("{}".into()),"#, name.as_ref())?;
222 } else {
223 writeln!(output, "name: None,")?;
224 }
225 self.pad(output)?;
226 if let Some(struct_query) = input.struct_query.as_ref() {
227 write!(output, "Some(")?;
228 self.write_struct_query(output, struct_query)?;
229 writeln!(output, "),")?;
230 } else {
231 writeln!(output, "struct_query: None,")?;
232 }
233 self.pad(output)?;
234 if let Some(module_name) = input.module_name.as_ref() {
235 writeln!(
236 output,
237 r#"module_name: Some("{}".into()),"#,
238 module_name.as_ref()
239 )?;
240 } else {
241 writeln!(output, "module_name: None,")?;
242 }
243 self.pad(output)?;
244 if let Some(visibility) = input.visibility {
245 writeln!(
246 output,
247 "visibility: Some({}::{:?}),",
248 std::any::type_name::<Visibility>(),
249 visibility
250 )?;
251 } else {
252 writeln!(output, "visibility: None,")?;
253 }
254 self.pad(output)?;
255 writeln!(output, "inputs: [")?;
256 self.push_indent();
257 for parameter in input.inputs.as_ref() {
258 self.pad(output)?;
259 self.write_function_parameter_query(output, parameter)?;
260 writeln!(output, ",")?;
261 }
262 self.pop_indent();
263 self.pad(output)?;
264 writeln!(output, "].as_slice().into(),")?;
265 self.pad(output)?;
266 writeln!(output, "outputs: [")?;
267 self.push_indent();
268 for parameter in input.outputs.as_ref() {
269 self.pad(output)?;
270 self.write_function_parameter_query(output, parameter)?;
271 writeln!(output, ",")?;
272 }
273 self.pop_indent();
274 self.pad(output)?;
275 writeln!(output, "].as_slice().into(),")?;
276 self.pop_indent();
277 self.pad(output)?;
278 write!(output, "}}")
279 }
280
281 fn write_function(
282 &mut self,
283 output: &mut dyn Write,
284 input: &ScriptFunction<SE>,
285 ) -> Result<(), Error> {
286 self.pad(output)?;
287 self.write_visibility(output, input.signature.visibility)?;
288 write!(output, "fn {}(", input.signature.name,)?;
289 for parameter in &input.signature.inputs {
290 write!(
291 output,
292 "{}: {},",
293 parameter.name,
294 self.registry
295 .structs()
296 .find(|struct_type| parameter.struct_query.is_valid(struct_type))
297 .unwrap()
298 .type_name()
299 )?;
300 }
301 write!(output, ") -> (")?;
302 for parameter in &input.signature.outputs {
303 write!(
304 output,
305 "{},",
306 self.registry
307 .structs()
308 .find(|struct_type| parameter.struct_query.is_valid(struct_type))
309 .unwrap()
310 .type_name()
311 )?;
312 }
313 writeln!(output, ") {{")?;
314 self.push_indent();
315 self.pad(output)?;
316 writeln!(
317 output,
318 "{}::with_global(move |mut host| {{",
319 std::any::type_name::<Host>()
320 )?;
321 self.push_indent();
322 self.pad(output)?;
323 writeln!(
324 output,
325 "let (mut __context__, __registry__) = host.context_and_registry();"
326 )?;
327 for parameter in input.signature.inputs.iter().rev() {
328 self.pad(output)?;
329 writeln!(output, "__context__.stack().push({});", parameter.name)?;
330 }
331 self.pad(output)?;
332 writeln!(
333 output,
334 "{}::intuicio_function(__context__, __registry__);",
335 input.signature.name
336 )?;
337 self.pad(output)?;
338 write!(output, "(")?;
339 for parameter in &input.signature.outputs {
340 write!(
341 output,
342 "__context__.stack().pop::<{}>().unwrap(),",
343 self.registry
344 .structs()
345 .find(|struct_type| parameter.struct_query.is_valid(struct_type))
346 .unwrap()
347 .type_name()
348 )?;
349 }
350 writeln!(output, ")")?;
351 self.pop_indent();
352 self.pad(output)?;
353 writeln!(
354 output,
355 r#"}}).expect("There is no global host for current thread to run function: `{:?}`")"#,
356 input.signature
357 )?;
358 self.pop_indent();
359 self.pad(output)?;
360 writeln!(output, "}}")?;
361 writeln!(output)?;
362 self.pad(output)?;
363 writeln!(output, "pub mod {} {{", input.signature.name)?;
364 self.push_indent();
365 self.pad(output)?;
366 writeln!(
367 output,
368 "pub fn define_signature(registry: &{}) -> {} {{",
369 std::any::type_name::<Registry>(),
370 std::any::type_name::<FunctionSignature>()
371 )?;
372 self.push_indent();
373 self.pad(output)?;
374 writeln!(
375 output,
376 r#"let mut result = {}::new("{}");"#,
377 std::any::type_name::<FunctionSignature>(),
378 input.signature.name
379 )?;
380 if let Some(module_name) = input.signature.module_name.as_ref() {
381 self.pad(output)?;
382 writeln!(
383 output,
384 r#"result.module_name = Some("{}".to_owned());"#,
385 module_name
386 )?;
387 }
388 self.pad(output)?;
389 writeln!(
390 output,
391 "result.visibility = {}::{:?};",
392 std::any::type_name::<Visibility>(),
393 input.signature.visibility
394 )?;
395 for parameter in &input.signature.inputs {
396 self.pad(output)?;
397 writeln!(
398 output,
399 r#"result.inputs.push({}::new("{}", registry.find_struct({}::of::<{}>()).unwrap()));"#,
400 std::any::type_name::<FunctionParameter>(),
401 parameter.name,
402 std::any::type_name::<StructQuery>(),
403 self.registry
404 .structs()
405 .find(|struct_type| parameter.struct_query.is_valid(struct_type))
406 .unwrap()
407 .type_name()
408 )?;
409 }
410 for parameter in &input.signature.outputs {
411 self.pad(output)?;
412 writeln!(
413 output,
414 r#"result.outputs.push({}::new("{}", registry.find_struct({}::of::<{}>()).unwrap()));"#,
415 std::any::type_name::<FunctionParameter>(),
416 parameter.name,
417 std::any::type_name::<StructQuery>(),
418 self.registry
419 .structs()
420 .find(|struct_type| parameter.struct_query.is_valid(struct_type))
421 .unwrap()
422 .type_name()
423 )?;
424 }
425 self.pad(output)?;
426 writeln!(output, "result")?;
427 self.pop_indent();
428 self.pad(output)?;
429 writeln!(output, "}}")?;
430 writeln!(output)?;
431 self.pad(output)?;
432 writeln!(
433 output,
434 "pub fn define_function(registry: &{}) -> {} {{",
435 std::any::type_name::<Registry>(),
436 std::any::type_name::<Function>()
437 )?;
438 self.push_indent();
439 self.pad(output)?;
440 writeln!(
441 output,
442 "{}::new(define_signature(registry), {}::pointer(intuicio_function))",
443 std::any::type_name::<Function>(),
444 std::any::type_name::<FunctionBody>()
445 )?;
446 self.pop_indent();
447 self.pad(output)?;
448 writeln!(output, "}}")?;
449 writeln!(output)
450 }
451}
452
453impl<'a, SE: ScriptExpression> ScriptNativizer<SE> for RustHostNativizer<'a, SE> {
454 fn nativize_struct_begin(
455 &mut self,
456 output: &mut dyn Write,
457 input: &ScriptStruct,
458 ) -> Result<(), Error> {
459 self.pad(output)?;
460 writeln!(output, "#[derive(IntuicioScript)]")?;
461 if let Some(module_name) = input.module_name.as_ref() {
462 self.pad(output)?;
463 writeln!(output, r#"#[intuicio(module_name = "{}")]"#, module_name)?;
464 }
465 self.pad(output)?;
466 self.write_visibility(output, input.visibility)?;
467 writeln!(output, "struct {} {{", input.name)?;
468 self.push_indent();
469 Ok(())
470 }
471
472 fn nativize_struct_end(
473 &mut self,
474 output: &mut dyn Write,
475 _: &ScriptStruct,
476 ) -> Result<(), Error> {
477 self.pop_indent();
478 self.pad(output)?;
479 writeln!(output, "}}")
480 }
481
482 fn nativize_struct_field(
483 &mut self,
484 output: &mut dyn Write,
485 input: &ScriptStructField,
486 ) -> Result<(), Error> {
487 self.pad(output)?;
488 self.write_visibility(output, input.visibility)?;
489 writeln!(
490 output,
491 "{}: {},",
492 input.name,
493 self.registry
494 .structs()
495 .find(|struct_type| input.struct_query.is_valid(struct_type))
496 .unwrap()
497 .type_name()
498 )
499 }
500
501 fn nativize_function_begin(
502 &mut self,
503 output: &mut dyn Write,
504 input: &ScriptFunction<SE>,
505 ) -> Result<(), Error> {
506 self.write_function(output, input)
507 }
516
517 fn nativize_function_end(
518 &mut self,
519 output: &mut dyn Write,
520 _: &ScriptFunction<SE>,
521 ) -> Result<(), Error> {
522 writeln!(output)?;
523 self.pop_indent();
524 self.pad(output)?;
525 writeln!(output, "}}")?;
526 Ok(())
527 }
528
529 fn nativize_function_signature(
530 &mut self,
531 output: &mut dyn Write,
532 input: &ScriptFunctionSignature,
533 ) -> Result<(), Error> {
534 self.pad(output)?;
535 self.write_visibility(output, input.visibility)?;
536 write!(
537 output,
538 "fn intuicio_function(context: &mut {}, registry: &{})",
539 std::any::type_name::<Context>(),
540 std::any::type_name::<Registry>()
541 )
542 }
543
544 fn nativize_function_body_begin(
545 &mut self,
546 output: &mut dyn Write,
547 _: &ScriptFunction<SE>,
548 ) -> Result<(), Error> {
549 write!(output, " ")
550 }
551
552 fn nativize_script_begin(
553 &mut self,
554 output: &mut dyn Write,
555 _: &[ScriptOperation<SE>],
556 ) -> Result<(), Error> {
557 if let Some(kind) = self.scope_kind.last() {
558 if *kind != ScopeKind::Loop {
559 write!(output, "'scope{}: ", self.scope_kind.len())?;
560 }
561 }
562 writeln!(output, "{{")?;
563 self.push_indent();
564 Ok(())
565 }
566
567 fn nativize_script_end(
568 &mut self,
569 output: &mut dyn Write,
570 _: &[ScriptOperation<SE>],
571 ) -> Result<(), Error> {
572 self.pop_indent();
573 self.pad(output)?;
574 write!(output, "}}")
575 }
576
577 fn nativize_operation_expression(
578 &mut self,
579 output: &mut dyn Write,
580 input: &SE,
581 ) -> Result<(), Error> {
582 self.expression_nativizer.nativize_expression(output, input)
583 }
584
585 fn nativize_operation_define_register(
586 &mut self,
587 output: &mut dyn Write,
588 query: &StructQuery,
589 ) -> Result<(), Error> {
590 self.pad(output)?;
591 writeln!(output, "{{")?;
592 self.push_indent();
593 self.pad(output)?;
594 write!(output, "let query = ")?;
595 self.write_struct_query(output, query)?;
596 writeln!(output, ";")?;
597 self.pad(output)?;
598 writeln!(
599 output,
600 "let handle = registry.structs().find(|handle| query.is_valid(handle)).unwrap();"
601 )?;
602 self.pad(output)?;
603 writeln!(
604 output,
605 "unsafe {{ context.registers().push_register_raw(handle.type_hash(), *handle.layout()) }};"
606 )?;
607 self.pop_indent();
608 self.pad(output)?;
609 writeln!(output, "}}")
610 }
611
612 fn nativize_operation_drop_register(
613 &mut self,
614 output: &mut dyn Write,
615 index: usize,
616 ) -> Result<(), Error> {
617 self.pad(output)?;
618 writeln!(output, "{{")?;
619 self.push_indent();
620 self.pad(output)?;
621 writeln!(
622 output,
623 "let index = context.absolute_register_index({});",
624 index
625 )?;
626 self.pad(output)?;
627 writeln!(
628 output,
629 "context.registers().access_register(index).unwrap().free();"
630 )?;
631 self.pop_indent();
632 self.pad(output)?;
633 writeln!(output, "}}")
634 }
635
636 fn nativize_operation_push_from_register(
637 &mut self,
638 output: &mut dyn Write,
639 index: usize,
640 ) -> Result<(), Error> {
641 self.pad(output)?;
642 writeln!(output, "{{")?;
643 self.push_indent();
644 self.pad(output)?;
645 writeln!(
646 output,
647 "let index = context.absolute_register_index({});",
648 index
649 )?;
650 self.pad(output)?;
651 writeln!(
652 output,
653 "let (stack, registers) = context.stack_and_registers();"
654 )?;
655 self.pad(output)?;
656 writeln!(
657 output,
658 "let mut register = registers.access_register(index).unwrap();"
659 )?;
660 self.pad(output)?;
661 writeln!(
662 output,
663 r#"if !stack.push_from_register(&mut register) {{ panic!("Could not push data from register: {}"); }}"#,
664 index
665 )?;
666 self.pop_indent();
667 self.pad(output)?;
668 writeln!(output, "}}")
669 }
670
671 fn nativize_operation_pop_to_register(
672 &mut self,
673 output: &mut dyn Write,
674 index: usize,
675 ) -> Result<(), Error> {
676 self.pad(output)?;
677 writeln!(output, "{{")?;
678 self.push_indent();
679 self.pad(output)?;
680 writeln!(
681 output,
682 "let index = context.absolute_register_index({});",
683 index
684 )?;
685 self.pad(output)?;
686 writeln!(
687 output,
688 "let (stack, registers) = context.stack_and_registers();"
689 )?;
690 self.pad(output)?;
691 writeln!(
692 output,
693 "let mut register = registers.access_register(index).unwrap();"
694 )?;
695 self.pad(output)?;
696 writeln!(
697 output,
698 r#"if !stack.pop_to_register(&mut register) {{ panic!("Could not pop data to register: {}"); }}"#,
699 index
700 )?;
701 self.pop_indent();
702 self.pad(output)?;
703 writeln!(output, "}}")
704 }
705
706 fn nativize_operation_move_register(
707 &mut self,
708 output: &mut dyn Write,
709 from: usize,
710 to: usize,
711 ) -> Result<(), Error> {
712 self.pad(output)?;
713 writeln!(output, "{{")?;
714 self.push_indent();
715 self.pad(output)?;
716 writeln!(
717 output,
718 "let from = context.absolute_register_index({});",
719 from
720 )?;
721 self.pad(output)?;
722 writeln!(output, "let to = context.absolute_register_index({});", to)?;
723 self.pad(output)?;
724 writeln!(
725 output,
726 "let (mut source, mut target) = context.registers().access_registers_pair(from, to).unwrap();"
727 )?;
728 self.pad(output)?;
729 writeln!(output, "source.move_to(&mut target);")?;
730 self.pop_indent();
731 self.pad(output)?;
732 writeln!(output, "}}")
733 }
734
735 fn nativize_operation_call_function(
736 &mut self,
737 output: &mut dyn Write,
738 query: &FunctionQuery,
739 ) -> Result<(), Error> {
740 self.pad(output)?;
741 writeln!(output, "{{")?;
742 self.push_indent();
743 self.pad(output)?;
744 write!(output, "let query = ")?;
745 self.write_function_query(output, query)?;
746 writeln!(output, ";")?;
747 self.pad(output)?;
748 writeln!(output, "registry.functions().find(|handle| query.is_valid(handle.signature())).unwrap().invoke(context, registry);")?;
749 self.pop_indent();
750 self.pad(output)?;
751 writeln!(output, "}}")
752 }
753
754 fn nativize_operation_branch_scope(
755 &mut self,
756 output: &mut dyn Write,
757 scope_success: &[ScriptOperation<SE>],
758 scope_failure: Option<&[ScriptOperation<SE>]>,
759 ) -> Result<(), Error> {
760 self.pad(output)?;
761 writeln!(output, "if context.stack().pop::<bool>().unwrap() {{")?;
762 self.push_indent();
763 self.pad(output)?;
764 self.scope_kind.push(ScopeKind::Branch);
765 self.nativize_script(output, scope_success)?;
766 self.scope_kind.pop();
767 self.pop_indent();
768 writeln!(output)?;
769 self.pad(output)?;
770 write!(output, "}}")?;
771 if let Some(scope_failure) = scope_failure.as_ref() {
772 writeln!(output, " else {{")?;
773 self.push_indent();
774 self.pad(output)?;
775 self.scope_kind.push(ScopeKind::Branch);
776 self.nativize_script(output, scope_failure)?;
777 self.scope_kind.pop();
778 self.pop_indent();
779 writeln!(output)?;
780 self.pad(output)?;
781 write!(output, "}}")?;
782 }
783 writeln!(output)
784 }
785
786 fn nativize_operation_loop_scope(
787 &mut self,
788 output: &mut dyn Write,
789 scope: &[ScriptOperation<SE>],
790 ) -> Result<(), Error> {
791 self.pad(output)?;
792 write!(output, "loop ")?;
793 self.scope_kind.push(ScopeKind::Loop);
794 self.nativize_script(output, scope)?;
795 self.scope_kind.pop();
796 writeln!(output)?;
797 Ok(())
798 }
799
800 fn nativize_operation_push_scope(
801 &mut self,
802 output: &mut dyn Write,
803 scope: &[ScriptOperation<SE>],
804 ) -> Result<(), Error> {
805 self.pad(output)?;
806 self.scope_kind.push(ScopeKind::Normal);
807 self.nativize_script(output, scope)?;
808 self.scope_kind.pop();
809 writeln!(output)?;
810 Ok(())
811 }
812
813 fn nativize_operation_pop_scope(&mut self, output: &mut dyn Write) -> Result<(), Error> {
814 self.pad(output)?;
815 match self.scope_kind.last() {
816 Some(ScopeKind::Normal) | Some(ScopeKind::Branch) => {
817 writeln!(output, "break 'scope{};", self.scope_kind.len())
818 }
819 Some(ScopeKind::Loop) => {
820 writeln!(output, "break;")
821 }
822 None => {
823 writeln!(output, "return;")
824 }
825 }
826 }
827
828 fn nativize_operation_continue_scope_conditionally(
829 &mut self,
830 output: &mut dyn Write,
831 ) -> Result<(), Error> {
832 self.pad(output)?;
833 write!(output, "if !context.stack().pop::<bool>().unwrap() {{ ")?;
834 match self.scope_kind.last() {
835 Some(ScopeKind::Normal) | Some(ScopeKind::Branch) => {
836 write!(output, "break 'scope{};", self.scope_kind.len())?;
837 }
838 Some(ScopeKind::Loop) => {
839 write!(output, "break;")?;
840 }
841 None => {
842 write!(output, "return;")?;
843 }
844 }
845 writeln!(output, " }}")
846 }
847}
848
849#[cfg(test)]
850mod tests {
851 use super::RustHostNativizer;
852 use intuicio_core::{
853 function::FunctionQuery,
854 nativizer::ScriptNativizer,
855 registry::Registry,
856 script::{
857 ScriptBuilder, ScriptFunction, ScriptFunctionParameter, ScriptFunctionSignature,
858 ScriptStruct, ScriptStructField,
859 },
860 struct_type::StructQuery,
861 Visibility,
862 };
863 use intuicio_data::type_hash::TypeHash;
864
865 #[test]
866 fn test_rust_host_nativization() {
867 let mut registry = Registry::default().with_basic_types();
868
869 let struct_type = ScriptStruct {
870 meta: None,
871 name: "Foo".to_owned(),
872 module_name: Some("test".to_owned()),
873 visibility: Visibility::Public,
874 fields: vec![
875 ScriptStructField {
876 meta: None,
877 name: "a".to_owned(),
878 visibility: Visibility::Public,
879 struct_query: StructQuery {
880 type_hash: Some(TypeHash::of::<bool>()),
881 ..Default::default()
882 },
883 },
884 ScriptStructField {
885 meta: None,
886 name: "b".to_owned(),
887 visibility: Visibility::Public,
888 struct_query: StructQuery {
889 type_hash: Some(TypeHash::of::<usize>()),
890 ..Default::default()
891 },
892 },
893 ScriptStructField {
894 meta: None,
895 name: "c".to_owned(),
896 visibility: Visibility::Public,
897 struct_query: StructQuery {
898 type_hash: Some(TypeHash::of::<f32>()),
899 ..Default::default()
900 },
901 },
902 ],
903 };
904 struct_type.install(&mut registry);
905 let mut buffer = String::new();
906 RustHostNativizer::<()>::new(®istry, ())
907 .nativize_struct(&mut buffer, &struct_type)
908 .unwrap();
909 println!("{}", buffer);
910
911 let function = ScriptFunction::<()> {
912 signature: ScriptFunctionSignature {
913 meta: None,
914 name: "foo".to_owned(),
915 module_name: Some("test".to_owned()),
916 struct_query: None,
917 visibility: Visibility::Public,
918 inputs: vec![
919 ScriptFunctionParameter {
920 meta: None,
921 name: "a".to_owned(),
922 struct_query: StructQuery {
923 type_hash: Some(TypeHash::of::<bool>()),
924 ..Default::default()
925 },
926 },
927 ScriptFunctionParameter {
928 meta: None,
929 name: "b".to_owned(),
930 struct_query: StructQuery {
931 type_hash: Some(TypeHash::of::<usize>()),
932 ..Default::default()
933 },
934 },
935 ],
936 outputs: vec![ScriptFunctionParameter {
937 meta: None,
938 name: "c".to_owned(),
939 struct_query: StructQuery {
940 type_hash: Some(TypeHash::of::<f32>()),
941 ..Default::default()
942 },
943 }],
944 },
945 script: ScriptBuilder::default()
946 .define_register(StructQuery {
947 name: Some("i32".into()),
948 ..Default::default()
949 })
950 .drop_register(0)
951 .push_from_register(0)
952 .pop_to_register(0)
953 .move_register(0, 1)
954 .call_function(FunctionQuery {
955 name: Some("foo".into()),
956 ..Default::default()
957 })
958 .branch_scope(
959 ScriptBuilder::default()
960 .pop_to_register(0)
961 .move_register(0, 1)
962 .continue_scope_conditionally()
963 .pop_scope()
964 .build(),
965 Some(
966 ScriptBuilder::default()
967 .pop_to_register(0)
968 .move_register(0, 1)
969 .continue_scope_conditionally()
970 .pop_scope()
971 .build(),
972 ),
973 )
974 .loop_scope(
975 ScriptBuilder::default()
976 .pop_to_register(0)
977 .move_register(0, 1)
978 .continue_scope_conditionally()
979 .pop_scope()
980 .build(),
981 )
982 .push_scope(
983 ScriptBuilder::default()
984 .pop_to_register(0)
985 .move_register(0, 1)
986 .continue_scope_conditionally()
987 .pop_scope()
988 .build(),
989 )
990 .continue_scope_conditionally()
991 .pop_scope()
992 .build(),
993 };
994 let mut buffer = String::new();
995 RustHostNativizer::new(®istry, ())
996 .nativize_function(&mut buffer, &function)
997 .unwrap();
998 println!("{}", buffer);
999 }
1000}