hydro_lang/builder/
compiled.rs
1use std::collections::BTreeMap;
2use std::marker::PhantomData;
3
4use dfir_lang::graph::DfirGraph;
5use dfir_rs::scheduled::graph::Dfir;
6use proc_macro2::TokenStream;
7use quote::quote;
8use stageleft::QuotedWithContext;
9use stageleft::runtime_support::FreeVariableWithContext;
10
11use crate::Location;
12use crate::staging_util::Invariant;
13
14pub struct CompiledFlow<'a, ID> {
15 pub(super) dfir: BTreeMap<usize, DfirGraph>,
16 pub(super) extra_stmts: BTreeMap<usize, Vec<syn::Stmt>>,
17 pub(super) _phantom: Invariant<'a, ID>,
18}
19
20impl<'a, ID> CompiledFlow<'a, ID> {
21 pub fn dfir_for(&self, location: &impl Location<'a>) -> &DfirGraph {
22 self.dfir.get(&location.id().raw_id()).unwrap()
23 }
24
25 pub fn all_dfir(&self) -> &BTreeMap<usize, DfirGraph> {
26 &self.dfir
27 }
28}
29
30impl<'a> CompiledFlow<'a, usize> {
31 pub fn with_dynamic_id(
32 self,
33 id: impl QuotedWithContext<'a, usize, ()>,
34 ) -> CompiledFlowWithId<'a> {
35 let hydro_lang_crate = proc_macro_crate::crate_name("hydro_lang")
36 .expect("hydro_lang should be present in `Cargo.toml`");
37 let root = match hydro_lang_crate {
38 proc_macro_crate::FoundCrate::Itself => quote! { hydro_lang::dfir_rs },
39 proc_macro_crate::FoundCrate::Name(name) => {
40 let ident = syn::Ident::new(&name, proc_macro2::Span::call_site());
41 quote! { #ident::dfir_rs }
42 }
43 };
44
45 let mut conditioned_tokens = None;
46 for (subgraph_id, partitioned_graph) in self.dfir {
47 let mut diagnostics = Vec::new();
48 let tokens = partitioned_graph.as_code(&root, true, quote::quote!(), &mut diagnostics);
49 let my_extra_stmts = self
50 .extra_stmts
51 .get(&subgraph_id)
52 .cloned()
53 .unwrap_or_default();
54
55 if let Some(conditioned_tokens) = conditioned_tokens.as_mut() {
56 *conditioned_tokens = syn::parse_quote! {
57 #conditioned_tokens else if __given_id == #subgraph_id {
58 #(#my_extra_stmts)*
59 #tokens
60 }
61 };
62 } else {
63 conditioned_tokens = Some(syn::parse_quote! {
64 if __given_id == #subgraph_id {
65 #(#my_extra_stmts)*
66 #tokens
67 }
68 });
69 }
70 }
71
72 let conditioned_tokens: TokenStream = conditioned_tokens.unwrap();
73 let id = id.splice_untyped();
74 CompiledFlowWithId {
75 tokens: syn::parse_quote!({
76 let __given_id = #id;
77 #conditioned_tokens else {
78 panic!("Invalid node id: {}", __given_id);
79 }
80 }),
81 _phantom: PhantomData,
82 }
83 }
84}
85
86impl<'a, Ctx> QuotedWithContext<'a, Dfir<'a>, Ctx> for CompiledFlow<'a, ()> {}
87
88impl<'a, Ctx> FreeVariableWithContext<Ctx> for CompiledFlow<'a, ()> {
89 type O = Dfir<'a>;
90
91 fn to_tokens(mut self, _ctx: &Ctx) -> (Option<TokenStream>, Option<TokenStream>) {
92 let hydro_lang_crate = proc_macro_crate::crate_name("hydro_lang")
93 .expect("hydro_lang should be present in `Cargo.toml`");
94 let root = match hydro_lang_crate {
95 proc_macro_crate::FoundCrate::Itself => quote! { hydro_lang::dfir_rs },
96 proc_macro_crate::FoundCrate::Name(name) => {
97 let ident = syn::Ident::new(&name, proc_macro2::Span::call_site());
98 quote! { #ident::dfir_rs }
99 }
100 };
101
102 if self.dfir.len() != 1 {
103 panic!("Expected exactly one subgraph in the DFIR.");
104 }
105
106 let partitioned_graph = self.dfir.remove(&0).unwrap();
107
108 let mut diagnostics = Vec::new();
109 let tokens = partitioned_graph.as_code(&root, true, quote::quote!(), &mut diagnostics);
110
111 (None, Some(tokens))
112 }
113}
114
115pub struct CompiledFlowWithId<'a> {
116 tokens: TokenStream,
117 _phantom: Invariant<'a>,
118}
119
120impl<'a, Ctx> QuotedWithContext<'a, Dfir<'a>, Ctx> for CompiledFlowWithId<'a> {}
121
122impl<'a, Ctx> FreeVariableWithContext<Ctx> for CompiledFlowWithId<'a> {
123 type O = Dfir<'a>;
124
125 fn to_tokens(self, _ctx: &Ctx) -> (Option<TokenStream>, Option<TokenStream>) {
126 (None, Some(self.tokens))
127 }
128}