intuicio_frontend_serde/
lib.rs

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