1use intuicio_core::{
2 context::Context,
3 crate_version,
4 function::FunctionQuery,
5 meta::Meta,
6 registry::Registry,
7 script::{
8 ScriptContentProvider, ScriptEnum, ScriptEnumVariant, ScriptExpression, ScriptFunction,
9 ScriptFunctionParameter, ScriptFunctionSignature, ScriptHandle, ScriptModule,
10 ScriptOperation, ScriptPackage, ScriptStruct, ScriptStructField,
11 },
12 types::TypeQuery,
13 IntuicioVersion, Visibility,
14};
15use intuicio_nodes::nodes::{
16 Node, NodeDefinition, NodeGraphVisitor, NodePin, NodeSuggestion, NodeTypeInfo, PropertyValue,
17 ResponseSuggestionNode,
18};
19use serde::{Deserialize, Serialize};
20use std::{collections::HashMap, error::Error};
21
22pub type SerdeScript = Vec<SerdeOperation>;
23
24pub fn frontend_serde_version() -> IntuicioVersion {
25 crate_version!()
26}
27
28#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
29pub enum SerdeLiteral {
30 Unit,
31 Bool(bool),
32 I8(i8),
33 I16(i16),
34 I32(i32),
35 I64(i64),
36 I128(i128),
37 Isize(isize),
38 U8(u8),
39 U16(u16),
40 U32(u32),
41 U64(u64),
42 U128(u128),
43 Usize(usize),
44 F32(f32),
45 F64(f64),
46 Char(char),
47 String(String),
48}
49
50impl SerdeLiteral {
51 fn evaluate(&self, context: &mut Context) {
52 match self {
53 Self::Unit => context.stack().push(()),
54 Self::Bool(value) => context.stack().push(*value),
55 Self::I8(value) => context.stack().push(*value),
56 Self::I16(value) => context.stack().push(*value),
57 Self::I32(value) => context.stack().push(*value),
58 Self::I64(value) => context.stack().push(*value),
59 Self::I128(value) => context.stack().push(*value),
60 Self::Isize(value) => context.stack().push(*value),
61 Self::U8(value) => context.stack().push(*value),
62 Self::U16(value) => context.stack().push(*value),
63 Self::U32(value) => context.stack().push(*value),
64 Self::U64(value) => context.stack().push(*value),
65 Self::U128(value) => context.stack().push(*value),
66 Self::Usize(value) => context.stack().push(*value),
67 Self::F32(value) => context.stack().push(*value),
68 Self::F64(value) => context.stack().push(*value),
69 Self::Char(value) => context.stack().push(*value),
70 Self::String(value) => context.stack().push(value.to_owned()),
71 };
72 }
73}
74
75#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
76pub enum SerdeExpression {
77 Literal(SerdeLiteral),
78 StackDrop,
79}
80
81impl ScriptExpression for SerdeExpression {
82 fn evaluate(&self, context: &mut Context, _: &Registry) {
83 match self {
84 Self::Literal(literal) => {
85 literal.evaluate(context);
86 }
87 Self::StackDrop => {
88 context.stack().drop();
89 }
90 }
91 }
92}
93
94#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
95pub enum SerdeOperation {
96 Expression(SerdeExpression),
97 MakeRegister {
98 name: String,
99 #[serde(default, skip_serializing_if = "Option::is_none")]
100 module_name: Option<String>,
101 },
102 DropRegister {
103 index: usize,
104 },
105 PushFromRegister {
106 index: usize,
107 },
108 PopToRegister {
109 index: usize,
110 },
111 CallFunction {
112 name: String,
113 #[serde(default, skip_serializing_if = "Option::is_none")]
114 module_name: Option<String>,
115 #[serde(default, skip_serializing_if = "Option::is_none")]
116 type_name: Option<String>,
117 #[serde(default, skip_serializing_if = "Option::is_none")]
118 visibility: Option<Visibility>,
119 },
120 BranchScope {
121 script_success: SerdeScript,
122 #[serde(default, skip_serializing_if = "Option::is_none")]
123 script_failure: Option<SerdeScript>,
124 },
125 LoopScope {
126 script: SerdeScript,
127 },
128 PushScope {
129 script: SerdeScript,
130 },
131 PopScope,
132}
133
134fn build_script(script: &SerdeScript) -> ScriptHandle<'static, SerdeExpression> {
135 ScriptHandle::new(
136 script
137 .iter()
138 .map(|operation| match operation {
139 SerdeOperation::Expression(expression) => ScriptOperation::Expression {
140 expression: expression.to_owned(),
141 },
142 SerdeOperation::MakeRegister { name, module_name } => {
143 ScriptOperation::DefineRegister {
144 query: TypeQuery {
145 name: Some(name.to_owned().into()),
146 module_name: module_name.as_ref().map(|name| name.to_owned().into()),
147 ..Default::default()
148 },
149 }
150 }
151 SerdeOperation::DropRegister { index } => {
152 ScriptOperation::DropRegister { index: *index }
153 }
154 SerdeOperation::PushFromRegister { index } => {
155 ScriptOperation::PushFromRegister { index: *index }
156 }
157 SerdeOperation::PopToRegister { index } => {
158 ScriptOperation::PopToRegister { index: *index }
159 }
160 SerdeOperation::CallFunction {
161 name,
162 module_name,
163 type_name,
164 visibility,
165 } => ScriptOperation::CallFunction {
166 query: FunctionQuery {
167 name: Some(name.to_owned().into()),
168 module_name: module_name.as_ref().map(|name| name.to_owned().into()),
169 type_query: type_name.as_ref().map(|name| TypeQuery {
170 name: Some(name.to_owned().into()),
171 module_name: module_name.as_ref().map(|name| name.to_owned().into()),
172 ..Default::default()
173 }),
174 visibility: *visibility,
175 ..Default::default()
176 },
177 },
178 SerdeOperation::BranchScope {
179 script_success: operations_success,
180 script_failure: operations_failure,
181 } => ScriptOperation::BranchScope {
182 scope_success: build_script(operations_success),
183 scope_failure: operations_failure.as_ref().map(build_script),
184 },
185 SerdeOperation::LoopScope { script: operations } => ScriptOperation::LoopScope {
186 scope: build_script(operations),
187 },
188 SerdeOperation::PushScope { script: operations } => ScriptOperation::PushScope {
189 scope: build_script(operations),
190 },
191 SerdeOperation::PopScope => ScriptOperation::PopScope,
192 })
193 .collect(),
194 )
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct SerdeFunctionParameter {
199 pub meta: Option<Meta>,
200 pub name: String,
201 pub module_name: Option<String>,
202 pub type_name: String,
203}
204
205impl SerdeFunctionParameter {
206 pub fn compile(&self) -> ScriptFunctionParameter<'static> {
207 ScriptFunctionParameter {
208 meta: self.meta.to_owned(),
209 name: self.name.to_owned(),
210 type_query: TypeQuery {
211 name: Some(self.type_name.to_owned().into()),
212 module_name: self
213 .module_name
214 .as_ref()
215 .map(|module_name| module_name.to_owned().into()),
216 ..Default::default()
217 },
218 }
219 }
220}
221
222#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct SerdeFunction {
224 #[serde(default, skip_serializing_if = "Option::is_none")]
225 pub meta: Option<Meta>,
226 pub name: String,
227 #[serde(default, skip_serializing_if = "Option::is_none")]
228 pub type_name: Option<String>,
229 #[serde(default)]
230 pub visibility: Visibility,
231 #[serde(default)]
232 pub inputs: Vec<SerdeFunctionParameter>,
233 #[serde(default)]
234 pub outputs: Vec<SerdeFunctionParameter>,
235 pub script: SerdeScript,
236}
237
238impl SerdeFunction {
239 pub fn compile(&self, module_name: &str) -> ScriptFunction<'static, SerdeExpression> {
240 ScriptFunction {
241 signature: ScriptFunctionSignature {
242 meta: self.meta.to_owned(),
243 name: self.name.to_owned(),
244 module_name: Some(module_name.to_owned()),
245 type_query: self.type_name.as_ref().map(|type_name| TypeQuery {
246 name: Some(type_name.to_owned().into()),
247 ..Default::default()
248 }),
249 visibility: self.visibility,
250 inputs: self
251 .inputs
252 .iter()
253 .map(|parameter| parameter.compile())
254 .collect(),
255 outputs: self
256 .outputs
257 .iter()
258 .map(|parameter| parameter.compile())
259 .collect(),
260 },
261 script: build_script(&self.script),
262 }
263 }
264}
265
266#[derive(Debug, Clone, Serialize, Deserialize)]
267pub struct SerdeStructField {
268 #[serde(default, skip_serializing_if = "Option::is_none")]
269 pub meta: Option<Meta>,
270 pub name: String,
271 #[serde(default, skip_serializing_if = "Visibility::is_public")]
272 pub visibility: Visibility,
273 pub module_name: Option<String>,
274 pub type_name: String,
275}
276
277impl SerdeStructField {
278 pub fn compile(&self) -> ScriptStructField<'static> {
279 ScriptStructField {
280 meta: self.meta.to_owned(),
281 name: self.name.to_owned(),
282 visibility: self.visibility,
283 type_query: TypeQuery {
284 name: Some(self.type_name.to_owned().into()),
285 module_name: self
286 .module_name
287 .as_ref()
288 .map(|module_name| module_name.to_owned().into()),
289 ..Default::default()
290 },
291 }
292 }
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct SerdeStruct {
297 #[serde(default, skip_serializing_if = "Option::is_none")]
298 pub meta: Option<Meta>,
299 pub name: String,
300 #[serde(default, skip_serializing_if = "Visibility::is_public")]
301 pub visibility: Visibility,
302 #[serde(default, skip_serializing_if = "Vec::is_empty")]
303 pub fields: Vec<SerdeStructField>,
304}
305
306impl SerdeStruct {
307 pub fn compile(&self, module_name: &str) -> ScriptStruct<'static> {
308 ScriptStruct {
309 meta: self.meta.to_owned(),
310 name: self.name.to_owned(),
311 module_name: Some(module_name.to_owned()),
312 visibility: self.visibility,
313 fields: self.fields.iter().map(|field| field.compile()).collect(),
314 }
315 }
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
319pub struct SerdeEnumVariant {
320 #[serde(default, skip_serializing_if = "Option::is_none")]
321 pub meta: Option<Meta>,
322 pub name: String,
323 pub fields: Vec<SerdeStructField>,
324 pub discriminant: Option<u8>,
325}
326
327impl SerdeEnumVariant {
328 pub fn compile(&self) -> ScriptEnumVariant<'static> {
329 ScriptEnumVariant {
330 meta: self.meta.to_owned(),
331 name: self.name.to_owned(),
332 fields: self.fields.iter().map(|field| field.compile()).collect(),
333 discriminant: self.discriminant,
334 }
335 }
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize)]
339pub struct SerdeEnum {
340 #[serde(default, skip_serializing_if = "Option::is_none")]
341 pub meta: Option<Meta>,
342 pub name: String,
343 #[serde(default, skip_serializing_if = "Visibility::is_public")]
344 pub visibility: Visibility,
345 #[serde(default, skip_serializing_if = "Vec::is_empty")]
346 pub variants: Vec<SerdeEnumVariant>,
347 #[serde(default, skip_serializing_if = "Option::is_none")]
348 pub default_variant: Option<u8>,
349}
350
351impl SerdeEnum {
352 pub fn compile(&self, module_name: &str) -> ScriptEnum<'static> {
353 ScriptEnum {
354 meta: self.meta.to_owned(),
355 name: self.name.to_owned(),
356 module_name: Some(module_name.to_owned()),
357 visibility: self.visibility,
358 variants: self
359 .variants
360 .iter()
361 .map(|variant| variant.compile())
362 .collect(),
363 default_variant: self.default_variant,
364 }
365 }
366}
367
368#[derive(Debug, Clone, Serialize, Deserialize)]
369pub struct SerdeModule {
370 pub name: String,
371 #[serde(default, skip_serializing_if = "Vec::is_empty")]
372 pub structs: Vec<SerdeStruct>,
373 #[serde(default, skip_serializing_if = "Vec::is_empty")]
374 pub enums: Vec<SerdeEnum>,
375 #[serde(default, skip_serializing_if = "Vec::is_empty")]
376 pub functions: Vec<SerdeFunction>,
377}
378
379impl SerdeModule {
380 pub fn compile(&self) -> ScriptModule<'static, SerdeExpression> {
381 ScriptModule {
382 name: self.name.to_owned(),
383 structs: self
384 .structs
385 .iter()
386 .map(|struct_type| struct_type.compile(&self.name))
387 .collect(),
388 enums: self
389 .enums
390 .iter()
391 .map(|enum_type| enum_type.compile(&self.name))
392 .collect(),
393 functions: self
394 .functions
395 .iter()
396 .map(|function| function.compile(&self.name))
397 .collect(),
398 }
399 }
400}
401
402#[derive(Debug, Default, Clone, Serialize, Deserialize)]
403pub struct SerdeFile {
404 #[serde(default, skip_serializing_if = "Vec::is_empty")]
405 pub dependencies: Vec<String>,
406 #[serde(default, skip_serializing_if = "Vec::is_empty")]
407 pub modules: Vec<SerdeModule>,
408}
409
410#[derive(Debug, Default, Clone, Serialize, Deserialize)]
411pub struct SerdePackage {
412 pub files: HashMap<String, SerdeFile>,
413}
414
415impl SerdePackage {
416 pub fn new<CP>(path: &str, content_provider: &mut CP) -> Result<Self, Box<dyn Error>>
417 where
418 CP: ScriptContentProvider<SerdeFile>,
419 {
420 let mut result = Self::default();
421 result.load(path, content_provider)?;
422 Ok(result)
423 }
424
425 pub fn load<CP>(&mut self, path: &str, content_provider: &mut CP) -> Result<(), Box<dyn Error>>
426 where
427 CP: ScriptContentProvider<SerdeFile>,
428 {
429 let path = content_provider.sanitize_path(path)?;
430 if self.files.contains_key(&path) {
431 return Ok(());
432 }
433 for content in content_provider.unpack_load(&path)? {
434 if let Some(file) = content.data? {
435 let dependencies = file.dependencies.to_owned();
436 self.files.insert(content.name, file);
437 for relative in dependencies {
438 let path = content_provider.join_paths(&content.path, &relative)?;
439 self.load(&path, content_provider)?;
440 }
441 }
442 }
443 Ok(())
444 }
445
446 pub fn compile(&self) -> ScriptPackage<'static, SerdeExpression> {
447 ScriptPackage {
448 modules: self
449 .files
450 .values()
451 .flat_map(|file| file.modules.iter())
452 .map(|module| module.compile())
453 .collect(),
454 }
455 }
456}
457
458#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
459pub struct SerdeNodeTypeInfo {
460 pub name: String,
461 pub module_name: Option<String>,
462}
463
464impl SerdeNodeTypeInfo {
465 pub fn new(name: impl ToString, module_name: Option<impl ToString>) -> Self {
466 Self {
467 name: name.to_string(),
468 module_name: module_name.map(|name| name.to_string()),
469 }
470 }
471}
472
473impl NodeTypeInfo for SerdeNodeTypeInfo {
474 fn type_query(&self) -> TypeQuery {
475 TypeQuery {
476 name: Some(self.name.as_str().into()),
477 module_name: self.module_name.as_ref().map(|name| name.into()),
478 ..Default::default()
479 }
480 }
481
482 fn are_compatible(&self, other: &Self) -> bool {
483 self == other
484 }
485}
486
487impl std::fmt::Display for SerdeNodeTypeInfo {
488 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
489 write!(
490 f,
491 "{}::{}",
492 self.name,
493 self.module_name.as_deref().unwrap_or("")
494 )
495 }
496}
497
498#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
499pub enum SerdeNodes {
500 #[default]
501 Start,
502 Operation(SerdeOperation),
503}
504
505impl NodeDefinition for SerdeNodes {
506 type TypeInfo = SerdeNodeTypeInfo;
507
508 fn node_label(&self, _: &Registry) -> String {
509 match self {
510 Self::Start => "Start".to_owned(),
511 Self::Operation(operation) => match operation {
512 SerdeOperation::Expression(expression) => match expression {
513 SerdeExpression::Literal(literal) => match literal {
514 SerdeLiteral::Unit => "Unit literal".to_owned(),
515 SerdeLiteral::Bool(_) => "Boolean literal".to_owned(),
516 SerdeLiteral::I8(_) => "Signed 8-bit literal".to_owned(),
517 SerdeLiteral::I16(_) => "Signed 16-bit literal".to_owned(),
518 SerdeLiteral::I32(_) => "Signed 32-bit literal".to_owned(),
519 SerdeLiteral::I64(_) => "Signed 64-bit literal".to_owned(),
520 SerdeLiteral::I128(_) => "Signed 128-bit literal".to_owned(),
521 SerdeLiteral::Isize(_) => "Signed size literal".to_owned(),
522 SerdeLiteral::U8(_) => "Unsigned 8-bit literal".to_owned(),
523 SerdeLiteral::U16(_) => "Unsigned 16-bit literal".to_owned(),
524 SerdeLiteral::U32(_) => "Unsigned 32-bit literal".to_owned(),
525 SerdeLiteral::U64(_) => "Unsigned 64-bit literal".to_owned(),
526 SerdeLiteral::U128(_) => "Unsigned 128-bit literal".to_owned(),
527 SerdeLiteral::Usize(_) => "Unsigned size literal".to_owned(),
528 SerdeLiteral::F32(_) => "32-bit float literal".to_owned(),
529 SerdeLiteral::F64(_) => "64-bit float literal".to_owned(),
530 SerdeLiteral::Char(_) => "Character literal".to_owned(),
531 SerdeLiteral::String(_) => "String literal".to_owned(),
532 },
533 SerdeExpression::StackDrop => "Stack drop".to_owned(),
534 },
535 SerdeOperation::MakeRegister { .. } => "Make register".to_owned(),
536 SerdeOperation::DropRegister { .. } => "Drop register".to_owned(),
537 SerdeOperation::PushFromRegister { .. } => {
538 "Push data from register to stack".to_owned()
539 }
540 SerdeOperation::PopToRegister { .. } => {
541 "Pop data from stack to register".to_owned()
542 }
543 SerdeOperation::CallFunction {
544 name, module_name, ..
545 } => format!(
546 "Call function: `{}::{}`",
547 module_name.as_deref().unwrap_or(""),
548 name
549 ),
550 SerdeOperation::BranchScope { .. } => "Branch scope".to_owned(),
551 SerdeOperation::LoopScope { .. } => "Loop scope".to_owned(),
552 SerdeOperation::PushScope { .. } => "Push scope".to_owned(),
553 SerdeOperation::PopScope => "Pop scope".to_owned(),
554 },
555 }
556 }
557
558 fn node_pins_in(&self, _: &Registry) -> Vec<NodePin<Self::TypeInfo>> {
559 match self {
560 Self::Start => vec![],
561 Self::Operation(operation) => match operation {
562 SerdeOperation::Expression(expression) => match expression {
563 SerdeExpression::Literal(literal) => match literal {
564 SerdeLiteral::Unit => vec![NodePin::execute("In", false)],
565 _ => vec![NodePin::execute("In", false), NodePin::property("Value")],
566 },
567 SerdeExpression::StackDrop => vec![NodePin::execute("In", false)],
568 },
569 SerdeOperation::MakeRegister { .. } => vec![
570 NodePin::execute("In", false),
571 NodePin::property("Type name"),
572 NodePin::property("Type module name"),
573 ],
574 SerdeOperation::DropRegister { .. }
575 | SerdeOperation::PushFromRegister { .. }
576 | SerdeOperation::PopToRegister { .. } => {
577 vec![NodePin::execute("In", false), NodePin::property("Index")]
578 }
579 SerdeOperation::CallFunction { .. } => vec![
580 NodePin::execute("In", false),
581 NodePin::property("Name"),
582 NodePin::property("Module name"),
583 NodePin::property("Type name"),
584 NodePin::property("Visibility"),
585 ],
586 _ => vec![NodePin::execute("In", false)],
587 },
588 }
589 }
590
591 fn node_pins_out(&self, _: &Registry) -> Vec<NodePin<Self::TypeInfo>> {
592 match self {
593 Self::Start => vec![NodePin::execute("Out", false)],
594 Self::Operation(operation) => match operation {
595 SerdeOperation::BranchScope { .. } => vec![
596 NodePin::execute("Out", false),
597 NodePin::execute("Success body", true),
598 NodePin::execute("Failure body", true),
599 ],
600 SerdeOperation::LoopScope { .. } | SerdeOperation::PushScope { .. } => vec![
601 NodePin::execute("Out", false),
602 NodePin::execute("Body", true),
603 ],
604 SerdeOperation::PopScope => vec![],
605 _ => vec![NodePin::execute("Out", false)],
606 },
607 }
608 }
609
610 fn node_is_start(&self, _: &Registry) -> bool {
611 matches!(self, SerdeNodes::Start)
612 }
613
614 fn node_suggestions(
615 x: i64,
616 y: i64,
617 _: NodeSuggestion<Self>,
618 registry: &Registry,
619 ) -> Vec<ResponseSuggestionNode<Self>> {
620 vec![
621 ResponseSuggestionNode::new(
622 "Literal",
623 Node::new(
624 x,
625 y,
626 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
627 SerdeLiteral::Unit,
628 ))),
629 ),
630 registry,
631 ),
632 ResponseSuggestionNode::new(
633 "Literal",
634 Node::new(
635 x,
636 y,
637 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
638 SerdeLiteral::Bool(true),
639 ))),
640 ),
641 registry,
642 ),
643 ResponseSuggestionNode::new(
644 "Literal",
645 Node::new(
646 x,
647 y,
648 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
649 SerdeLiteral::I8(0),
650 ))),
651 ),
652 registry,
653 ),
654 ResponseSuggestionNode::new(
655 "Literal",
656 Node::new(
657 x,
658 y,
659 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
660 SerdeLiteral::I16(0),
661 ))),
662 ),
663 registry,
664 ),
665 ResponseSuggestionNode::new(
666 "Literal",
667 Node::new(
668 x,
669 y,
670 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
671 SerdeLiteral::I32(0),
672 ))),
673 ),
674 registry,
675 ),
676 ResponseSuggestionNode::new(
677 "Literal",
678 Node::new(
679 x,
680 y,
681 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
682 SerdeLiteral::I64(0),
683 ))),
684 ),
685 registry,
686 ),
687 ResponseSuggestionNode::new(
688 "Literal",
689 Node::new(
690 x,
691 y,
692 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
693 SerdeLiteral::I128(0),
694 ))),
695 ),
696 registry,
697 ),
698 ResponseSuggestionNode::new(
699 "Literal",
700 Node::new(
701 x,
702 y,
703 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
704 SerdeLiteral::Isize(0),
705 ))),
706 ),
707 registry,
708 ),
709 ResponseSuggestionNode::new(
710 "Literal",
711 Node::new(
712 x,
713 y,
714 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
715 SerdeLiteral::U8(0),
716 ))),
717 ),
718 registry,
719 ),
720 ResponseSuggestionNode::new(
721 "Literal",
722 Node::new(
723 x,
724 y,
725 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
726 SerdeLiteral::U16(0),
727 ))),
728 ),
729 registry,
730 ),
731 ResponseSuggestionNode::new(
732 "Literal",
733 Node::new(
734 x,
735 y,
736 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
737 SerdeLiteral::U32(0),
738 ))),
739 ),
740 registry,
741 ),
742 ResponseSuggestionNode::new(
743 "Literal",
744 Node::new(
745 x,
746 y,
747 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
748 SerdeLiteral::U64(0),
749 ))),
750 ),
751 registry,
752 ),
753 ResponseSuggestionNode::new(
754 "Literal",
755 Node::new(
756 x,
757 y,
758 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
759 SerdeLiteral::U128(0),
760 ))),
761 ),
762 registry,
763 ),
764 ResponseSuggestionNode::new(
765 "Literal",
766 Node::new(
767 x,
768 y,
769 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
770 SerdeLiteral::Usize(0),
771 ))),
772 ),
773 registry,
774 ),
775 ResponseSuggestionNode::new(
776 "Literal",
777 Node::new(
778 x,
779 y,
780 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
781 SerdeLiteral::F32(0.0),
782 ))),
783 ),
784 registry,
785 ),
786 ResponseSuggestionNode::new(
787 "Literal",
788 Node::new(
789 x,
790 y,
791 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
792 SerdeLiteral::F64(0.0),
793 ))),
794 ),
795 registry,
796 ),
797 ResponseSuggestionNode::new(
798 "Literal",
799 Node::new(
800 x,
801 y,
802 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
803 SerdeLiteral::Char('@'),
804 ))),
805 ),
806 registry,
807 ),
808 ResponseSuggestionNode::new(
809 "Literal",
810 Node::new(
811 x,
812 y,
813 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
814 SerdeLiteral::String("text".to_owned()),
815 ))),
816 ),
817 registry,
818 ),
819 ResponseSuggestionNode::new(
820 "Expression",
821 Node::new(
822 x,
823 y,
824 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::StackDrop)),
825 ),
826 registry,
827 ),
828 ResponseSuggestionNode::new(
829 "Register",
830 Node::new(
831 x,
832 y,
833 SerdeNodes::Operation(SerdeOperation::MakeRegister {
834 name: "Type".to_owned(),
835 module_name: None,
836 }),
837 ),
838 registry,
839 ),
840 ResponseSuggestionNode::new(
841 "Register",
842 Node::new(
843 x,
844 y,
845 SerdeNodes::Operation(SerdeOperation::DropRegister { index: 0 }),
846 ),
847 registry,
848 ),
849 ResponseSuggestionNode::new(
850 "Register",
851 Node::new(
852 x,
853 y,
854 SerdeNodes::Operation(SerdeOperation::PushFromRegister { index: 0 }),
855 ),
856 registry,
857 ),
858 ResponseSuggestionNode::new(
859 "Register",
860 Node::new(
861 x,
862 y,
863 SerdeNodes::Operation(SerdeOperation::PopToRegister { index: 0 }),
864 ),
865 registry,
866 ),
867 ResponseSuggestionNode::new(
868 "Call",
869 Node::new(
870 x,
871 y,
872 SerdeNodes::Operation(SerdeOperation::CallFunction {
873 name: "Function".to_owned(),
874 module_name: None,
875 type_name: None,
876 visibility: None,
877 }),
878 ),
879 registry,
880 ),
881 ResponseSuggestionNode::new(
882 "Scope",
883 Node::new(
884 x,
885 y,
886 SerdeNodes::Operation(SerdeOperation::BranchScope {
887 script_success: vec![],
888 script_failure: None,
889 }),
890 ),
891 registry,
892 ),
893 ResponseSuggestionNode::new(
894 "Scope",
895 Node::new(
896 x,
897 y,
898 SerdeNodes::Operation(SerdeOperation::LoopScope { script: vec![] }),
899 ),
900 registry,
901 ),
902 ResponseSuggestionNode::new(
903 "Scope",
904 Node::new(
905 x,
906 y,
907 SerdeNodes::Operation(SerdeOperation::PushScope { script: vec![] }),
908 ),
909 registry,
910 ),
911 ResponseSuggestionNode::new(
912 "Scope",
913 Node::new(x, y, SerdeNodes::Operation(SerdeOperation::PopScope)),
914 registry,
915 ),
916 ]
917 }
918
919 fn get_property(&self, property_name: &str) -> Option<PropertyValue> {
920 match self {
921 Self::Operation(operation) => match operation {
922 SerdeOperation::Expression(SerdeExpression::Literal(literal)) => {
923 match property_name {
924 "Value" => match literal {
925 SerdeLiteral::Unit => PropertyValue::new(&()).ok(),
926 SerdeLiteral::Bool(value) => PropertyValue::new(value).ok(),
927 SerdeLiteral::I8(value) => PropertyValue::new(value).ok(),
928 SerdeLiteral::I16(value) => PropertyValue::new(value).ok(),
929 SerdeLiteral::I32(value) => PropertyValue::new(value).ok(),
930 SerdeLiteral::I64(value) => PropertyValue::new(value).ok(),
931 SerdeLiteral::I128(value) => PropertyValue::new(value).ok(),
932 SerdeLiteral::Isize(value) => PropertyValue::new(value).ok(),
933 SerdeLiteral::U8(value) => PropertyValue::new(value).ok(),
934 SerdeLiteral::U16(value) => PropertyValue::new(value).ok(),
935 SerdeLiteral::U32(value) => PropertyValue::new(value).ok(),
936 SerdeLiteral::U64(value) => PropertyValue::new(value).ok(),
937 SerdeLiteral::U128(value) => PropertyValue::new(value).ok(),
938 SerdeLiteral::Usize(value) => PropertyValue::new(value).ok(),
939 SerdeLiteral::F32(value) => PropertyValue::new(value).ok(),
940 SerdeLiteral::F64(value) => PropertyValue::new(value).ok(),
941 SerdeLiteral::Char(value) => PropertyValue::new(value).ok(),
942 SerdeLiteral::String(value) => PropertyValue::new(value).ok(),
943 },
944 _ => None,
945 }
946 }
947 SerdeOperation::MakeRegister { name, module_name } => match property_name {
948 "Type name" => PropertyValue::new(name).ok(),
949 "Type module name" => module_name
950 .as_ref()
951 .and_then(|name| PropertyValue::new(name).ok()),
952 _ => None,
953 },
954 SerdeOperation::DropRegister { index } => match property_name {
955 "Index" => PropertyValue::new(index).ok(),
956 _ => None,
957 },
958 SerdeOperation::PushFromRegister { index } => match property_name {
959 "Index" => PropertyValue::new(index).ok(),
960 _ => None,
961 },
962 SerdeOperation::PopToRegister { index } => match property_name {
963 "Index" => PropertyValue::new(index).ok(),
964 _ => None,
965 },
966 SerdeOperation::CallFunction {
967 name,
968 module_name,
969 type_name,
970 visibility,
971 } => match property_name {
972 "Name" => PropertyValue::new(name).ok(),
973 "Module name" => module_name
974 .as_ref()
975 .and_then(|name| PropertyValue::new(name).ok()),
976 "Type name" => type_name
977 .as_ref()
978 .and_then(|name| PropertyValue::new(name).ok()),
979 "Visibility" => visibility
980 .as_ref()
981 .and_then(|name| PropertyValue::new(name).ok()),
982 _ => None,
983 },
984 _ => None,
985 },
986 _ => None,
987 }
988 }
989
990 fn set_property(&mut self, property_name: &str, property_value: PropertyValue) {
991 if let Self::Operation(operation) = self {
992 match operation {
993 SerdeOperation::Expression(SerdeExpression::Literal(literal)) => {
994 if property_name == "Value" {
995 match literal {
996 SerdeLiteral::Unit => {}
997 SerdeLiteral::Bool(value) => {
998 if let Ok(v) = property_value.get_exact::<bool>() {
999 *value = v;
1000 }
1001 }
1002 SerdeLiteral::I8(value) => {
1003 if let Ok(v) = property_value.get_exact::<i8>() {
1004 *value = v;
1005 }
1006 }
1007 SerdeLiteral::I16(value) => {
1008 if let Ok(v) = property_value.get_exact::<i16>() {
1009 *value = v;
1010 }
1011 }
1012 SerdeLiteral::I32(value) => {
1013 if let Ok(v) = property_value.get_exact::<i32>() {
1014 *value = v;
1015 }
1016 }
1017 SerdeLiteral::I64(value) => {
1018 if let Ok(v) = property_value.get_exact::<i64>() {
1019 *value = v;
1020 }
1021 }
1022 SerdeLiteral::I128(value) => {
1023 if let Ok(v) = property_value.get_exact::<i128>() {
1024 *value = v;
1025 }
1026 }
1027 SerdeLiteral::Isize(value) => {
1028 if let Ok(v) = property_value.get_exact::<isize>() {
1029 *value = v;
1030 }
1031 }
1032 SerdeLiteral::U8(value) => {
1033 if let Ok(v) = property_value.get_exact::<u8>() {
1034 *value = v;
1035 }
1036 }
1037 SerdeLiteral::U16(value) => {
1038 if let Ok(v) = property_value.get_exact::<u16>() {
1039 *value = v;
1040 }
1041 }
1042 SerdeLiteral::U32(value) => {
1043 if let Ok(v) = property_value.get_exact::<u32>() {
1044 *value = v;
1045 }
1046 }
1047 SerdeLiteral::U64(value) => {
1048 if let Ok(v) = property_value.get_exact::<u64>() {
1049 *value = v;
1050 }
1051 }
1052 SerdeLiteral::U128(value) => {
1053 if let Ok(v) = property_value.get_exact::<u128>() {
1054 *value = v;
1055 }
1056 }
1057 SerdeLiteral::Usize(value) => {
1058 if let Ok(v) = property_value.get_exact::<usize>() {
1059 *value = v;
1060 }
1061 }
1062 SerdeLiteral::F32(value) => {
1063 if let Ok(v) = property_value.get_exact::<f32>() {
1064 *value = v;
1065 }
1066 }
1067 SerdeLiteral::F64(value) => {
1068 if let Ok(v) = property_value.get_exact::<f64>() {
1069 *value = v;
1070 }
1071 }
1072 SerdeLiteral::Char(value) => {
1073 if let Ok(v) = property_value.get_exact::<char>() {
1074 *value = v;
1075 }
1076 }
1077 SerdeLiteral::String(value) => {
1078 if let Ok(v) = property_value.get_exact::<String>() {
1079 *value = v;
1080 }
1081 }
1082 }
1083 }
1084 }
1085 SerdeOperation::MakeRegister { name, module_name } => match property_name {
1086 "Type name" => {
1087 if let Ok(v) = property_value.get_exact::<String>() {
1088 *name = v;
1089 }
1090 }
1091 "Type module name" => {
1092 *module_name = if let Ok(v) = property_value.get_exact::<String>() {
1093 Some(v)
1094 } else {
1095 None
1096 };
1097 }
1098 _ => {}
1099 },
1100 SerdeOperation::DropRegister { index } => {
1101 if property_name == "Index" {
1102 if let Ok(v) = property_value.get_exact::<usize>() {
1103 *index = v;
1104 }
1105 }
1106 }
1107 SerdeOperation::PushFromRegister { index } => {
1108 if property_name == "Index" {
1109 if let Ok(v) = property_value.get_exact::<usize>() {
1110 *index = v;
1111 }
1112 }
1113 }
1114 SerdeOperation::PopToRegister { index } => {
1115 if property_name == "Index" {
1116 if let Ok(v) = property_value.get_exact::<usize>() {
1117 *index = v;
1118 }
1119 }
1120 }
1121 SerdeOperation::CallFunction {
1122 name,
1123 module_name,
1124 type_name,
1125 visibility,
1126 } => match property_name {
1127 "Name" => {
1128 if let Ok(v) = property_value.get_exact::<String>() {
1129 *name = v;
1130 }
1131 }
1132 "Module name" => {
1133 *module_name = if let Ok(v) = property_value.get_exact::<String>() {
1134 Some(v)
1135 } else {
1136 None
1137 };
1138 }
1139 "Type name" => {
1140 *type_name = if let Ok(v) = property_value.get_exact::<String>() {
1141 Some(v)
1142 } else {
1143 None
1144 };
1145 }
1146 "Visibility" => {
1147 *visibility = if let Ok(v) = property_value.get_exact::<Visibility>() {
1148 Some(v)
1149 } else {
1150 None
1151 };
1152 }
1153 _ => {}
1154 },
1155 _ => {}
1156 }
1157 }
1158 }
1159}
1160
1161pub struct CompileSerdeNodeGraphVisitor;
1162
1163impl NodeGraphVisitor<SerdeNodes> for CompileSerdeNodeGraphVisitor {
1164 type Input = ();
1165 type Output = SerdeOperation;
1166
1167 fn visit_statement(
1168 &mut self,
1169 node: &Node<SerdeNodes>,
1170 _: HashMap<String, Self::Input>,
1171 mut scopes: HashMap<String, Vec<Self::Output>>,
1172 result: &mut Vec<Self::Output>,
1173 ) -> bool {
1174 if let SerdeNodes::Operation(operation) = &node.data {
1175 match operation {
1176 SerdeOperation::BranchScope { .. } => {
1177 if let Some(script_success) = scopes.remove("Success body") {
1178 result.push(SerdeOperation::BranchScope {
1179 script_success,
1180 script_failure: scopes.remove("Failure body"),
1181 });
1182 }
1183 }
1184 SerdeOperation::LoopScope { .. } => {
1185 if let Some(script) = scopes.remove("Body") {
1186 result.push(SerdeOperation::LoopScope { script });
1187 }
1188 }
1189 SerdeOperation::PushScope { .. } => {
1190 if let Some(script) = scopes.remove("Body") {
1191 result.push(SerdeOperation::PushScope { script });
1192 }
1193 }
1194 _ => result.push(operation.to_owned()),
1195 }
1196 }
1197 true
1198 }
1199
1200 fn visit_expression(
1201 &mut self,
1202 _: &Node<SerdeNodes>,
1203 _: HashMap<String, Self::Input>,
1204 ) -> Option<Self::Input> {
1205 None
1206 }
1207}
1208
1209#[cfg(test)]
1210mod tests {
1211 use crate::*;
1212 use intuicio_backend_vm::prelude::*;
1213 use intuicio_core::prelude::*;
1214 use intuicio_nodes::nodes::*;
1215
1216 pub struct LexprContentParser;
1217
1218 impl BytesContentParser<SerdeFile> for LexprContentParser {
1219 fn parse(&self, bytes: Vec<u8>) -> Result<SerdeFile, Box<dyn Error>> {
1220 let content = String::from_utf8(bytes)?;
1221 Ok(serde_lexpr::from_str::<SerdeFile>(&content)?)
1222 }
1223 }
1224
1225 #[test]
1226 fn test_frontend_lexpr() {
1227 let mut registry = Registry::default().with_basic_types();
1228 registry.add_function(define_function! {
1229 registry => mod intrinsics fn add(a: usize, b: usize) -> (result: usize) {
1230 (a + b,)
1231 }
1232 });
1233 let mut content_provider = FileContentProvider::new("lexpr", LexprContentParser);
1234 SerdePackage::new("../../resources/package.lexpr", &mut content_provider)
1235 .unwrap()
1236 .compile()
1237 .install::<VmScope<SerdeExpression>>(
1238 &mut registry,
1239 None,
1240 );
1248 assert!(registry
1249 .find_function(FunctionQuery {
1250 name: Some("main".into()),
1251 module_name: Some("test".into()),
1252 ..Default::default()
1253 })
1254 .is_some());
1255 let mut host = Host::new(Context::new(10240, 10240), RegistryHandle::new(registry));
1256 let (result,) = host
1257 .call_function::<(usize,), _>("main", "test", None)
1258 .unwrap()
1259 .run(());
1260 assert_eq!(result, 42);
1261 }
1262
1263 #[test]
1264 fn test_nodes() {
1265 let mut registry = Registry::default().with_basic_types();
1266 registry.add_function(define_function! {
1267 registry => mod intrinsics fn add(a: usize, b: usize) -> (result: usize) {
1268 (a + b,)
1269 }
1270 });
1271 let mut graph = NodeGraph::default();
1272 let start = graph
1273 .add_node(Node::new(0, 0, SerdeNodes::Start), ®istry)
1274 .unwrap();
1275 let literal_a = graph
1276 .add_node(
1277 Node::new(
1278 0,
1279 0,
1280 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
1281 SerdeLiteral::I32(2),
1282 ))),
1283 ),
1284 ®istry,
1285 )
1286 .unwrap();
1287 let literal_b = graph
1288 .add_node(
1289 Node::new(
1290 0,
1291 0,
1292 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
1293 SerdeLiteral::I32(40),
1294 ))),
1295 ),
1296 ®istry,
1297 )
1298 .unwrap();
1299 let call_add = graph
1300 .add_node(
1301 Node::new(
1302 0,
1303 0,
1304 SerdeNodes::Operation(SerdeOperation::CallFunction {
1305 name: "add".to_owned(),
1306 module_name: Some("intrinsics".to_owned()),
1307 type_name: None,
1308 visibility: None,
1309 }),
1310 ),
1311 ®istry,
1312 )
1313 .unwrap();
1314 graph.connect_nodes(NodeConnection::new(start, literal_a, "Out", "In"));
1315 graph.connect_nodes(NodeConnection::new(literal_a, literal_b, "Out", "In"));
1316 graph.connect_nodes(NodeConnection::new(literal_b, call_add, "Out", "In"));
1317 graph.validate(®istry).unwrap();
1318 assert_eq!(
1319 graph.visit(&mut CompileSerdeNodeGraphVisitor, ®istry),
1320 vec![
1321 SerdeOperation::Expression(SerdeExpression::Literal(SerdeLiteral::I32(2))),
1322 SerdeOperation::Expression(SerdeExpression::Literal(SerdeLiteral::I32(40))),
1323 SerdeOperation::CallFunction {
1324 name: "add".to_owned(),
1325 module_name: Some("intrinsics".to_owned()),
1326 type_name: None,
1327 visibility: None,
1328 }
1329 ]
1330 );
1331
1332 {
1333 let mut graph = graph.clone();
1334 graph.connect_nodes(NodeConnection {
1335 from_node: call_add,
1336 to_node: call_add,
1337 from_pin: "Out".to_owned(),
1338 to_pin: "In".to_owned(),
1339 });
1340 assert!(matches!(
1341 graph.validate(®istry).unwrap_err()[0],
1342 NodeGraphError::Connection(ConnectionError::InternalConnection(_))
1343 ));
1344 }
1345
1346 {
1347 let mut graph = graph.clone();
1348 graph.connect_nodes(NodeConnection {
1349 from_node: literal_a,
1350 to_node: literal_b,
1351 from_pin: "Out".to_owned(),
1352 to_pin: "Body".to_owned(),
1353 });
1354 assert!(matches!(
1355 graph.validate(®istry).unwrap_err()[0],
1356 NodeGraphError::Connection(ConnectionError::TargetPinNotFound { .. })
1357 ));
1358 }
1359
1360 {
1361 let mut graph = graph.clone();
1362 graph.connect_nodes(NodeConnection {
1363 from_node: literal_a,
1364 to_node: literal_b,
1365 from_pin: "Out".to_owned(),
1366 to_pin: "Value".to_owned(),
1367 });
1368 assert!(matches!(
1369 graph.validate(®istry).unwrap_err()[0],
1370 NodeGraphError::Connection(ConnectionError::MismatchPins { .. })
1371 ));
1372 }
1373
1374 {
1375 let mut graph = graph.clone();
1376 graph.connect_nodes(NodeConnection {
1377 from_node: call_add,
1378 to_node: literal_a,
1379 from_pin: "Out".to_owned(),
1380 to_pin: "In".to_owned(),
1381 });
1382 assert!(matches!(
1383 graph.validate(®istry).unwrap_err()[0],
1384 NodeGraphError::Connection(ConnectionError::CycleNodeFound { .. })
1385 ));
1386 }
1387 }
1388}