intuicio_frontend_serde/
lib.rs

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                // Some(
1230                //     PrintDebugger::full()
1231                //         .basic_printables()
1232                //         .stack_bytes(false)
1233                //         .registers_bytes(false)
1234                //         .into_handle(),
1235                // ),
1236            );
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), &registry)
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                &registry,
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                &registry,
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                &registry,
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(&registry).unwrap();
1309        assert_eq!(
1310            graph.visit(&mut CompileSerdeNodeGraphVisitor, &registry),
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(&registry).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(&registry).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(&registry).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(&registry).unwrap_err()[0],
1375                NodeGraphError::Connection(ConnectionError::CycleNodeFound { .. })
1376            ));
1377        }
1378    }
1379}