protoflow_syntax/
codegen.rs1extern crate std;
4
5use crate::{
6 prelude::{fmt, String, Vec},
7 AnalysisError,
8};
9use error_stack::Report;
10use quote::{format_ident, quote, ToTokens};
11use sysml_parser::{ParsedBlock, ParsedImport, ParsedMember, ParsedModel};
12
13#[derive(Debug, Default)]
14pub struct Code(proc_macro2::TokenStream);
15
16impl Code {
17 pub fn unparse(&self) -> String {
18 let file = syn::parse2::<syn::File>(self.0.clone()).unwrap();
19 prettyplease::unparse(&file)
20 }
21}
22
23impl fmt::Display for Code {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 self.0.fmt(f)
26 }
27}
28
29impl ToTokens for Code {
30 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
31 self.0.to_tokens(tokens);
32 }
33}
34
35impl TryFrom<&ParsedModel> for Code {
36 type Error = Report<AnalysisError>;
37
38 fn try_from(model: &ParsedModel) -> Result<Self, Self::Error> {
39 let members = model
40 .members()
41 .into_iter()
42 .map(|member| Code::try_from(member))
43 .collect::<Result<Vec<_>, _>>()?;
44 Ok(Code(quote! {
45 fn main() {
46 #(#members)*
47 }
48 }))
49 }
50}
51
52impl TryFrom<&ParsedMember> for Code {
53 type Error = Report<AnalysisError>;
54
55 fn try_from(member: &ParsedMember) -> Result<Self, Self::Error> {
56 use ParsedMember::*;
57 match member {
58 Import(import) => Code::try_from(import),
59 Package(package) => {
60 let members = package
61 .members()
62 .into_iter()
63 .map(|member| Code::try_from(member))
64 .collect::<Result<Vec<_>, _>>()?;
65 Ok(Code(quote! {
66 #(#members)*
67 }))
68 }
69 BlockUsage(usage) => Code::try_from(usage),
70 AttributeUsage(_usage) => Ok(Code::default()), PortUsage(_usage) => Ok(Code::default()), }
73 }
74}
75
76impl TryFrom<&ParsedImport> for Code {
77 type Error = Report<AnalysisError>;
78
79 fn try_from(import: &ParsedImport) -> Result<Self, Self::Error> {
80 Ok(Self(match import.imported_name.to_tuple3() {
81 (Some("Protoflow"), Some("*") | Some("**"), None) => {
82 quote! {
83 use protoflow::*;
84 }
85 }
86 (Some("Protoflow"), Some(unqualified_name), None) => {
87 let block_name = format_ident!("{}", unqualified_name);
88 quote! {
89 use protoflow::blocks::#block_name;
90 }
91 }
92 _ => {
93 return Err(Report::new(AnalysisError::InvalidImport(
94 import.imported_name.clone(),
95 )));
96 }
97 }))
98 }
99}
100
101impl TryFrom<&ParsedBlock> for Code {
102 type Error = Report<AnalysisError>;
103
104 fn try_from(usage: &ParsedBlock) -> Result<Self, Self::Error> {
105 let name = format_ident!(
106 "{}",
107 usage
108 .name
109 .as_ref()
110 .map(|s| s.as_str())
111 .unwrap_or_else(|| "block")
112 );
113 Ok(Self(quote! {
114 let #name = s.block();
115 }))
116 }
117}