1use intuicio_core::{
2 IntuicioVersion, Visibility,
3 context::Context,
4 crate_version,
5 function::FunctionQuery,
6 meta::Meta,
7 registry::Registry,
8 script::{
9 ScriptContentProvider, ScriptEnum, ScriptEnumVariant, ScriptExpression, ScriptFunction,
10 ScriptFunctionParameter, ScriptFunctionSignature, ScriptHandle, ScriptModule,
11 ScriptOperation, ScriptPackage, ScriptStruct, ScriptStructField,
12 },
13 types::TypeQuery,
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 = property_value.get_exact::<String>().ok();
1093 }
1094 _ => {}
1095 },
1096 SerdeOperation::DropRegister { index } => {
1097 if property_name == "Index"
1098 && let Ok(v) = property_value.get_exact::<usize>()
1099 {
1100 *index = v;
1101 }
1102 }
1103 SerdeOperation::PushFromRegister { index } => {
1104 if property_name == "Index"
1105 && let Ok(v) = property_value.get_exact::<usize>()
1106 {
1107 *index = v;
1108 }
1109 }
1110 SerdeOperation::PopToRegister { index } => {
1111 if property_name == "Index"
1112 && let Ok(v) = property_value.get_exact::<usize>()
1113 {
1114 *index = v;
1115 }
1116 }
1117 SerdeOperation::CallFunction {
1118 name,
1119 module_name,
1120 type_name,
1121 visibility,
1122 } => match property_name {
1123 "Name" => {
1124 if let Ok(v) = property_value.get_exact::<String>() {
1125 *name = v;
1126 }
1127 }
1128 "Module name" => {
1129 *module_name = property_value.get_exact::<String>().ok();
1130 }
1131 "Type name" => {
1132 *type_name = property_value.get_exact::<String>().ok();
1133 }
1134 "Visibility" => {
1135 *visibility = property_value.get_exact::<Visibility>().ok();
1136 }
1137 _ => {}
1138 },
1139 _ => {}
1140 }
1141 }
1142 }
1143}
1144
1145pub struct CompileSerdeNodeGraphVisitor;
1146
1147impl NodeGraphVisitor<SerdeNodes> for CompileSerdeNodeGraphVisitor {
1148 type Input = ();
1149 type Output = SerdeOperation;
1150
1151 fn visit_statement(
1152 &mut self,
1153 node: &Node<SerdeNodes>,
1154 _: HashMap<String, Self::Input>,
1155 mut scopes: HashMap<String, Vec<Self::Output>>,
1156 result: &mut Vec<Self::Output>,
1157 ) -> bool {
1158 if let SerdeNodes::Operation(operation) = &node.data {
1159 match operation {
1160 SerdeOperation::BranchScope { .. } => {
1161 if let Some(script_success) = scopes.remove("Success body") {
1162 result.push(SerdeOperation::BranchScope {
1163 script_success,
1164 script_failure: scopes.remove("Failure body"),
1165 });
1166 }
1167 }
1168 SerdeOperation::LoopScope { .. } => {
1169 if let Some(script) = scopes.remove("Body") {
1170 result.push(SerdeOperation::LoopScope { script });
1171 }
1172 }
1173 SerdeOperation::PushScope { .. } => {
1174 if let Some(script) = scopes.remove("Body") {
1175 result.push(SerdeOperation::PushScope { script });
1176 }
1177 }
1178 _ => result.push(operation.to_owned()),
1179 }
1180 }
1181 true
1182 }
1183
1184 fn visit_expression(
1185 &mut self,
1186 _: &Node<SerdeNodes>,
1187 _: HashMap<String, Self::Input>,
1188 ) -> Option<Self::Input> {
1189 None
1190 }
1191}
1192
1193#[cfg(test)]
1194mod tests {
1195 use crate::*;
1196 use intuicio_backend_vm::scope::VmScope;
1197 use intuicio_core::{
1198 define_function,
1199 host::Host,
1200 registry::RegistryHandle,
1201 script::{BytesContentParser, FileContentProvider},
1202 };
1203 use intuicio_nodes::nodes::*;
1204
1205 pub struct LexprContentParser;
1206
1207 impl BytesContentParser<SerdeFile> for LexprContentParser {
1208 fn parse(&self, bytes: Vec<u8>) -> Result<SerdeFile, Box<dyn Error>> {
1209 let content = String::from_utf8(bytes)?;
1210 Ok(serde_lexpr::from_str::<SerdeFile>(&content)?)
1211 }
1212 }
1213
1214 #[test]
1215 fn test_frontend_lexpr() {
1216 let mut registry = Registry::default().with_basic_types();
1217 registry.add_function(define_function! {
1218 registry => mod intrinsics fn add(a: usize, b: usize) -> (result: usize) {
1219 (a + b,)
1220 }
1221 });
1222 let mut content_provider = FileContentProvider::new("lexpr", LexprContentParser);
1223 SerdePackage::new("../../resources/package.lexpr", &mut content_provider)
1224 .unwrap()
1225 .compile()
1226 .install::<VmScope<SerdeExpression>>(
1227 &mut registry,
1228 None,
1229 );
1237 assert!(
1238 registry
1239 .find_function(FunctionQuery {
1240 name: Some("main".into()),
1241 module_name: Some("test".into()),
1242 ..Default::default()
1243 })
1244 .is_some()
1245 );
1246 let mut host = Host::new(Context::new(10240, 10240), RegistryHandle::new(registry));
1247 let (result,) = host
1248 .call_function::<(usize,), _>("main", "test", None)
1249 .unwrap()
1250 .run(());
1251 assert_eq!(result, 42);
1252 }
1253
1254 #[test]
1255 fn test_nodes() {
1256 let mut registry = Registry::default().with_basic_types();
1257 registry.add_function(define_function! {
1258 registry => mod intrinsics fn add(a: usize, b: usize) -> (result: usize) {
1259 (a + b,)
1260 }
1261 });
1262 let mut graph = NodeGraph::default();
1263 let start = graph
1264 .add_node(Node::new(0, 0, SerdeNodes::Start), ®istry)
1265 .unwrap();
1266 let literal_a = graph
1267 .add_node(
1268 Node::new(
1269 0,
1270 0,
1271 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
1272 SerdeLiteral::I32(2),
1273 ))),
1274 ),
1275 ®istry,
1276 )
1277 .unwrap();
1278 let literal_b = graph
1279 .add_node(
1280 Node::new(
1281 0,
1282 0,
1283 SerdeNodes::Operation(SerdeOperation::Expression(SerdeExpression::Literal(
1284 SerdeLiteral::I32(40),
1285 ))),
1286 ),
1287 ®istry,
1288 )
1289 .unwrap();
1290 let call_add = graph
1291 .add_node(
1292 Node::new(
1293 0,
1294 0,
1295 SerdeNodes::Operation(SerdeOperation::CallFunction {
1296 name: "add".to_owned(),
1297 module_name: Some("intrinsics".to_owned()),
1298 type_name: None,
1299 visibility: None,
1300 }),
1301 ),
1302 ®istry,
1303 )
1304 .unwrap();
1305 graph.connect_nodes(NodeConnection::new(start, literal_a, "Out", "In"));
1306 graph.connect_nodes(NodeConnection::new(literal_a, literal_b, "Out", "In"));
1307 graph.connect_nodes(NodeConnection::new(literal_b, call_add, "Out", "In"));
1308 graph.validate(®istry).unwrap();
1309 assert_eq!(
1310 graph.visit(&mut CompileSerdeNodeGraphVisitor, ®istry),
1311 vec![
1312 SerdeOperation::Expression(SerdeExpression::Literal(SerdeLiteral::I32(2))),
1313 SerdeOperation::Expression(SerdeExpression::Literal(SerdeLiteral::I32(40))),
1314 SerdeOperation::CallFunction {
1315 name: "add".to_owned(),
1316 module_name: Some("intrinsics".to_owned()),
1317 type_name: None,
1318 visibility: None,
1319 }
1320 ]
1321 );
1322
1323 {
1324 let mut graph = graph.clone();
1325 graph.connect_nodes(NodeConnection {
1326 from_node: call_add,
1327 to_node: call_add,
1328 from_pin: "Out".to_owned(),
1329 to_pin: "In".to_owned(),
1330 });
1331 assert!(matches!(
1332 graph.validate(®istry).unwrap_err()[0],
1333 NodeGraphError::Connection(ConnectionError::InternalConnection(_))
1334 ));
1335 }
1336
1337 {
1338 let mut graph = graph.clone();
1339 graph.connect_nodes(NodeConnection {
1340 from_node: literal_a,
1341 to_node: literal_b,
1342 from_pin: "Out".to_owned(),
1343 to_pin: "Body".to_owned(),
1344 });
1345 assert!(matches!(
1346 graph.validate(®istry).unwrap_err()[0],
1347 NodeGraphError::Connection(ConnectionError::TargetPinNotFound { .. })
1348 ));
1349 }
1350
1351 {
1352 let mut graph = graph.clone();
1353 graph.connect_nodes(NodeConnection {
1354 from_node: literal_a,
1355 to_node: literal_b,
1356 from_pin: "Out".to_owned(),
1357 to_pin: "Value".to_owned(),
1358 });
1359 assert!(matches!(
1360 graph.validate(®istry).unwrap_err()[0],
1361 NodeGraphError::Connection(ConnectionError::MismatchPins { .. })
1362 ));
1363 }
1364
1365 {
1366 let mut graph = graph.clone();
1367 graph.connect_nodes(NodeConnection {
1368 from_node: call_add,
1369 to_node: literal_a,
1370 from_pin: "Out".to_owned(),
1371 to_pin: "In".to_owned(),
1372 });
1373 assert!(matches!(
1374 graph.validate(®istry).unwrap_err()[0],
1375 NodeGraphError::Connection(ConnectionError::CycleNodeFound { .. })
1376 ));
1377 }
1378 }
1379}