1use std::collections::{BTreeMap, BTreeSet, VecDeque};
19use std::vec::Vec;
20
21use proc_macro2::TokenStream;
22use quote::{format_ident, quote};
23use syn::Ident;
24
25use crate::etypes::{BoundedTyvar, Defined, Handleable, ImportExport, TypeBound, Tyvar};
26
27#[derive(Debug, Default)]
31pub struct Trait {
32 pub supertraits: BTreeMap<Vec<Ident>, TokenStream>,
35 pub tvs: BTreeMap<Ident, (Option<u32>, TokenStream)>,
42 pub items: TokenStream,
44}
45impl Trait {
46 pub fn new() -> Self {
47 Self {
48 supertraits: BTreeMap::new(),
49 tvs: BTreeMap::new(),
50 items: TokenStream::new(),
51 }
52 }
53 pub fn tv_idxs(&self) -> Vec<u32> {
59 self.tvs.iter().map(|(_, (n, _))| n.unwrap()).collect()
60 }
61 pub fn adjust_vars(&mut self, n: u32) {
63 for (_, (v, _)) in self.tvs.iter_mut() {
64 if let Some(v) = v.as_mut() {
65 *v += n;
66 }
67 }
68 }
69 pub fn tv_toks_inner(&mut self) -> TokenStream {
72 let tvs = self
73 .tvs
74 .iter()
75 .map(|(k, (_, v))| {
76 let colon = if v.is_empty() {
77 quote! {}
78 } else {
79 quote! { : }
80 };
81 quote! { #k #colon #v }
82 })
83 .collect::<Vec<_>>();
84 quote! { #(#tvs),* }
85 }
86 pub fn tv_toks(&mut self) -> TokenStream {
89 if !self.tvs.is_empty() {
90 let toks = self.tv_toks_inner();
91 quote! { <#toks> }
92 } else {
93 quote! {}
94 }
95 }
96 pub fn into_tokens(&mut self, n: Ident) -> TokenStream {
98 let trait_colon = if !self.supertraits.is_empty() {
99 quote! { : }
100 } else {
101 quote! {}
102 };
103 let supertraits = self
104 .supertraits
105 .iter()
106 .map(|(is, ts)| {
107 quote! { #(#is)::*#ts }
108 })
109 .collect::<Vec<_>>();
110 let tvs = self.tv_toks();
111 let items = &self.items;
112 quote! {
113 pub trait #n #tvs #trait_colon #(#supertraits)+* { #items }
114 }
115 }
116}
117
118#[derive(Debug, Default)]
122pub struct Mod {
123 pub submods: BTreeMap<Ident, Mod>,
124 pub items: TokenStream,
125 pub traits: BTreeMap<Ident, Trait>,
126 pub impls: BTreeMap<(Vec<Ident>, Ident), TokenStream>,
127}
128impl Mod {
129 pub fn empty() -> Self {
130 Self {
131 submods: BTreeMap::new(),
132 items: TokenStream::new(),
133 traits: BTreeMap::new(),
134 impls: BTreeMap::new(),
135 }
136 }
137 pub fn submod<'a>(&'a mut self, i: Ident) -> &'a mut Self {
139 self.submods.entry(i).or_insert(Self::empty())
140 }
141 pub fn submod_immut<'a>(&'a self, i: Ident) -> &'a Self {
145 &self.submods[&i]
146 }
147 pub fn r#trait<'a>(&'a mut self, i: Ident) -> &'a mut Trait {
150 self.traits.entry(i).or_default()
151 }
152 pub fn trait_immut<'a>(&'a self, i: Ident) -> &'a Trait {
156 &self.traits[&i]
157 }
158 pub fn r#impl<'a>(&'a mut self, t: Vec<Ident>, i: Ident) -> &'a mut TokenStream {
164 self.impls.entry((t, i)).or_default()
165 }
166 pub fn adjust_vars(&mut self, n: u32) {
168 self.submods
169 .iter_mut()
170 .map(|(_, m)| m.adjust_vars(n))
171 .for_each(drop);
172 self.traits
173 .iter_mut()
174 .map(|(_, t)| t.adjust_vars(n))
175 .for_each(drop);
176 }
177 pub fn into_tokens(self) -> TokenStream {
179 let mut tt = TokenStream::new();
180 for (k, v) in self.submods {
181 let vt = v.into_tokens();
182 tt.extend(quote! {
183 pub mod #k { #vt }
184 });
185 }
186 for (n, mut t) in self.traits {
187 tt.extend(t.into_tokens(n));
188 }
189 tt.extend(self.items);
190 for ((ns, i), t) in self.impls {
191 tt.extend(quote! {
192 impl #(#ns)::* for #i { #t }
193 })
194 }
195 tt
196 }
197}
198
199#[derive(Debug)]
201pub struct State<'a, 'b> {
202 pub root_mod: &'a mut Mod,
204 pub mod_cursor: Vec<Ident>,
207 pub cur_trait: Option<Ident>,
211 pub cur_helper_mod: Option<Ident>,
217 pub is_helper: bool,
222 pub bound_vars: &'a mut VecDeque<BoundedTyvar<'b>>,
225 pub var_offset: usize,
231 pub origin: Vec<ImportExport<'b>>,
237 pub cur_needs_vars: Option<&'a mut BTreeSet<u32>>,
240 pub vars_needs_vars: &'a mut VecDeque<BTreeSet<u32>>,
244 pub import_param_var: Option<Ident>,
247 pub self_param_var: Option<Ident>,
250 pub is_impl: bool,
253 pub root_component_name: Option<(TokenStream, &'a str)>,
256 pub is_guest: bool,
259 pub is_wasmtime_guest: bool,
263}
264
265pub fn run_state<'b, F: for<'a> FnMut(&mut State<'a, 'b>)>(
269 is_guest: bool,
270 is_wasmtime_guest: bool,
271 mut f: F,
272) -> TokenStream {
273 let mut root_mod = Mod::empty();
274 let mut bound_vars = std::collections::VecDeque::new();
275 let mut vars_needs_vars = std::collections::VecDeque::new();
276 {
277 let mut state = State::new(
278 &mut root_mod,
279 &mut bound_vars,
280 &mut vars_needs_vars,
281 is_guest,
282 is_wasmtime_guest,
283 );
284 f(&mut state);
285 }
286 root_mod.into_tokens()
287}
288
289impl<'a, 'b> State<'a, 'b> {
290 pub fn new(
291 root_mod: &'a mut Mod,
292 bound_vars: &'a mut VecDeque<BoundedTyvar<'b>>,
293 vars_needs_vars: &'a mut VecDeque<BTreeSet<u32>>,
294 is_guest: bool,
295 is_wasmtime_guest: bool,
296 ) -> Self {
297 Self {
298 root_mod,
299 mod_cursor: Vec::new(),
300 cur_trait: None,
301 cur_helper_mod: None,
302 is_helper: false,
303 bound_vars,
304 var_offset: 0,
305 origin: Vec::new(),
306 cur_needs_vars: None,
307 vars_needs_vars,
308 import_param_var: None,
309 self_param_var: None,
310 is_impl: false,
311 root_component_name: None,
312 is_guest,
313 is_wasmtime_guest,
314 }
315 }
316 pub fn clone<'c>(&'c mut self) -> State<'c, 'b> {
317 State {
318 root_mod: self.root_mod,
319 mod_cursor: self.mod_cursor.clone(),
320 cur_trait: self.cur_trait.clone(),
321 cur_helper_mod: self.cur_helper_mod.clone(),
322 is_helper: self.is_helper,
323 bound_vars: self.bound_vars,
324 var_offset: self.var_offset,
325 origin: self.origin.clone(),
326 cur_needs_vars: self.cur_needs_vars.as_deref_mut(),
327 vars_needs_vars: self.vars_needs_vars,
328 import_param_var: self.import_param_var.clone(),
329 self_param_var: self.self_param_var.clone(),
330 is_impl: self.is_impl,
331 root_component_name: self.root_component_name.clone(),
332 is_guest: self.is_guest,
333 is_wasmtime_guest: self.is_wasmtime_guest,
334 }
335 }
336 pub fn cur_mod<'c>(&'c mut self) -> &'c mut Mod {
339 let mut m: &'c mut Mod = self.root_mod;
340 for i in &self.mod_cursor {
341 m = m.submod(i.clone());
342 }
343 if self.is_helper {
344 m = m.submod(self.cur_helper_mod.clone().unwrap());
345 }
346 m
347 }
348 pub fn cur_mod_immut<'c>(&'c self) -> &'c Mod {
353 let mut m: &'c Mod = self.root_mod;
354 for i in &self.mod_cursor {
355 m = m.submod_immut(i.clone());
356 }
357 if self.is_helper {
358 m = m.submod_immut(self.cur_helper_mod.clone().unwrap());
359 }
360 m
361 }
362 pub fn with_cursor<'c>(&'c mut self, cursor: Vec<Ident>) -> State<'c, 'b> {
365 let mut s = self.clone();
366 s.mod_cursor = cursor;
367 s
368 }
369 pub fn with_needs_vars<'c>(&'c mut self, needs_vars: &'c mut BTreeSet<u32>) -> State<'c, 'b> {
373 let mut s = self.clone();
374 s.cur_needs_vars = Some(needs_vars);
375 s
376 }
377 pub fn need_noff_var(&mut self, n: u32) {
380 self.cur_needs_vars.as_mut().map(|vs| vs.insert(n));
381 }
382 pub fn record_needs_vars(&mut self, n: u32) {
386 let un = n as usize;
387 if self.vars_needs_vars.len() < un + 1 {
388 self.vars_needs_vars.resize(un + 1, BTreeSet::new());
389 }
390 let Some(ref mut cnvs) = self.cur_needs_vars else {
391 return;
392 };
393 log::debug!("debug varref: recording {:?} for var {:?}", cnvs.iter(), un);
394 self.vars_needs_vars[un].extend(cnvs.iter());
395 }
396 pub fn get_noff_var_refs(&mut self, n: u32) -> BTreeSet<u32> {
399 let un = n as usize;
400 if self.vars_needs_vars.len() < un + 1 {
401 return BTreeSet::new();
402 };
403 log::debug!(
404 "debug varref: looking up {:?} for var {:?}",
405 self.vars_needs_vars[un].iter(),
406 un
407 );
408 self.vars_needs_vars[un].clone()
409 }
410 pub fn noff_var_id(&self, n: u32) -> Ident {
414 let Some(n) = self.bound_vars[n as usize].origin.last_name() else {
415 panic!("missing origin on tyvar in rust emit")
416 };
417 kebab_to_type(n)
418 }
419 pub fn helper<'c>(&'c mut self) -> State<'c, 'b> {
422 let mut s = self.clone();
423 s.is_helper = true;
424 s
425 }
426 pub fn root_path(&self) -> TokenStream {
429 if self.is_impl {
430 return TokenStream::new();
431 }
432 let mut s = self
433 .mod_cursor
434 .iter()
435 .map(|_| quote! { super })
436 .collect::<Vec<_>>();
437 if self.is_helper {
438 s.push(quote! { super });
439 }
440 quote! { #(#s::)* }
441 }
442 pub fn helper_path(&self) -> TokenStream {
445 if self.is_impl {
446 let c = &self.mod_cursor;
447 let helper = self.cur_helper_mod.clone().unwrap();
448 let h = if !self.is_helper {
449 quote! { #helper:: }
450 } else {
451 TokenStream::new()
452 };
453 quote! { #(#c::)*#h }
454 } else if self.is_helper {
455 quote! { self:: }
456 } else {
457 let helper = self.cur_helper_mod.clone().unwrap();
458 quote! { #helper:: }
459 }
460 }
461 pub fn cur_trait_path(&self) -> TokenStream {
464 let tns = &self.mod_cursor;
465 let tid = self.cur_trait.clone().unwrap();
466 quote! { #(#tns::)* #tid }
467 }
468 pub fn add_helper_supertrait(&mut self, r: Ident) {
472 let (Some(t), Some(hm)) = (self.cur_trait.clone(), &self.cur_helper_mod.clone()) else {
473 panic!("invariant violation")
474 };
475 self.cur_mod()
476 .r#trait(t)
477 .supertraits
478 .insert(vec![hm.clone(), r], TokenStream::new());
479 }
480 pub fn cur_trait<'c>(&'c mut self) -> &'c mut Trait {
486 let n = self.cur_trait.as_ref().unwrap().clone();
487 self.cur_mod().r#trait(n)
488 }
489 pub fn cur_trait_immut<'c>(&'c self) -> &'c Trait {
496 let n = self.cur_trait.as_ref().unwrap().clone();
497 self.cur_mod_immut().trait_immut(n)
498 }
499 pub fn r#trait<'c>(&'c mut self, namespace: &'c [Ident], name: Ident) -> &'c mut Trait {
503 let mut m: &'c mut Mod = self.root_mod;
504 for i in namespace {
505 m = m.submod(i.clone());
506 }
507 m.r#trait(name)
508 }
509 pub fn push_origin<'c>(&'c mut self, is_export: bool, name: &'b str) -> State<'c, 'b> {
512 let mut s = self.clone();
513 s.origin.push(if is_export {
514 ImportExport::Export(name)
515 } else {
516 ImportExport::Import(name)
517 });
518 s
519 }
520 pub fn is_var_defn(&self, t: &Defined<'b>) -> Option<(u32, TypeBound<'b>)> {
524 match t {
525 Defined::Handleable(Handleable::Var(tv)) => match tv {
526 Tyvar::Bound(n) => {
527 let bv = &self.bound_vars[self.var_offset + (*n as usize)];
528 log::debug!("checking an origin {:?} {:?}", bv.origin, self.origin);
529 if bv.origin.matches(self.origin.iter()) {
530 Some((*n, bv.bound.clone()))
531 } else {
532 None
533 }
534 }
535 Tyvar::Free(_) => panic!("free tyvar in finished type"),
536 },
537 _ => None,
538 }
539 }
540 pub fn is_noff_var_local<'c>(
543 &'c self,
544 n: u32,
545 ) -> Option<(Vec<ImportExport<'c>>, TypeBound<'a>)> {
546 let bv = &self.bound_vars[n as usize];
547 bv.origin
548 .is_local(self.origin.iter())
549 .map(|path| (path, bv.bound.clone()))
550 }
551 pub fn resolve_trait_immut(&self, absolute: bool, path: &[Ident]) -> &Trait {
557 log::debug!("resolving trait {:?} {:?}", absolute, path);
558 let mut m = if absolute {
559 &*self.root_mod
560 } else {
561 self.cur_mod_immut()
562 };
563 for x in &path[0..path.len() - 1] {
564 m = &m.submods[x];
565 }
566 &m.traits[&path[path.len() - 1]]
567 }
568 pub fn adjust_vars(&mut self, n: u32) {
575 self.vars_needs_vars
576 .iter_mut()
577 .enumerate()
578 .for_each(|(i, vs)| {
579 *vs = vs.iter().map(|v| v + n).collect();
580 log::debug!("updated {:?} to {:?}", i, *vs);
581 });
582 for _ in 0..n {
583 self.vars_needs_vars.push_front(BTreeSet::new());
584 }
585 self.root_mod.adjust_vars(n);
586 }
587 pub fn resolve_tv(&self, n: u32) -> (u32, Option<Defined<'b>>) {
592 match &self.bound_vars[self.var_offset + n as usize].bound {
593 TypeBound::Eq(Defined::Handleable(Handleable::Var(Tyvar::Bound(nn)))) => {
594 self.resolve_tv(n + 1 + nn)
595 }
596 TypeBound::Eq(t) => (n, Some(t.clone())),
597 TypeBound::SubResource => (n, None),
598 }
599 }
600 pub fn resource_trait_path(&self, r: Ident) -> Vec<Ident> {
603 let mut path = self.mod_cursor.clone();
604 let helper = self
605 .cur_helper_mod
606 .as_ref()
607 .expect("There should always be a helper mod to hold a resource trait")
608 .clone();
609 path.push(helper);
610 path.push(r);
611 path
612 }
613}
614
615#[derive(Debug, Clone)]
618pub struct WitName<'a> {
619 pub namespaces: Vec<&'a str>,
620 pub name: &'a str,
621 pub _version: Vec<&'a str>,
622}
623impl<'a> WitName<'a> {
624 pub fn namespace_idents(&self) -> Vec<Ident> {
627 self.namespaces
628 .iter()
629 .map(|x| kebab_to_namespace(x))
630 .collect::<Vec<_>>()
631 }
632 pub fn namespace_path(&self) -> TokenStream {
635 let ns = self.namespace_idents();
636 quote! { #(#ns)::* }
637 }
638}
639pub fn split_wit_name(n: &str) -> WitName {
641 let mut namespaces = Vec::new();
642 let mut colon_components = n.split(':').rev();
643 let last = colon_components.next().unwrap();
644 namespaces.extend(colon_components.rev());
645 let mut slash_components = last.split('/').rev();
646 let mut versioned_name = slash_components.next().unwrap().split('@');
647 let name = versioned_name.next().unwrap();
648 namespaces.extend(slash_components.rev());
649 WitName {
650 namespaces,
651 name,
652 _version: versioned_name.collect(),
653 }
654}
655
656fn kebab_to_snake(n: &str) -> Ident {
657 if n == "self" {
658 return format_ident!("self_");
659 }
660 let mut ret = String::new();
661 for c in n.chars() {
662 if c == '-' {
663 ret.push('_');
664 continue;
665 }
666 ret.push(c);
667 }
668 format_ident!("r#{}", ret)
669}
670
671fn kebab_to_camel(n: &str) -> Ident {
672 let mut word_start = true;
673 let mut ret = String::new();
674 for c in n.chars() {
675 if c == '-' {
676 word_start = true;
677 continue;
678 }
679 if word_start {
680 ret.extend(c.to_uppercase())
681 } else {
682 ret.push(c)
683 };
684 word_start = false;
685 }
686 format_ident!("{}", ret)
687}
688
689pub fn kebab_to_var(n: &str) -> Ident {
692 kebab_to_snake(n)
693}
694pub fn kebab_to_cons(n: &str) -> Ident {
697 kebab_to_camel(n)
698}
699pub fn kebab_to_getter(n: &str) -> Ident {
702 kebab_to_snake(n)
703}
704pub fn kebab_to_type(n: &str) -> Ident {
706 kebab_to_camel(n)
707}
708pub fn kebab_to_namespace(n: &str) -> Ident {
711 kebab_to_snake(n)
712}
713pub fn kebab_to_imports_name(trait_name: &str) -> Ident {
716 format_ident!("{}Imports", kebab_to_type(trait_name))
717}
718pub fn kebab_to_exports_name(trait_name: &str) -> Ident {
721 format_ident!("{}Exports", kebab_to_type(trait_name))
722}
723
724pub enum ResourceItemName {
727 Constructor,
728 Method(Ident),
729 Static(Ident),
730}
731
732pub enum FnName {
734 Associated(Ident, ResourceItemName),
735 Plain(Ident),
736}
737pub fn kebab_to_fn(n: &str) -> FnName {
740 if let Some(n) = n.strip_prefix("[constructor]") {
741 return FnName::Associated(kebab_to_type(n), ResourceItemName::Constructor);
742 }
743 if let Some(n) = n.strip_prefix("[method]") {
744 let mut i = n.split('.');
745 let r = i.next().unwrap();
746 let n = i.next().unwrap();
747 return FnName::Associated(
748 kebab_to_type(r),
749 ResourceItemName::Method(kebab_to_snake(n)),
750 );
751 }
752 if let Some(n) = n.strip_prefix("[static]") {
753 let mut i = n.split('.');
754 let r = i.next().unwrap();
755 let n = i.next().unwrap();
756 return FnName::Associated(
757 kebab_to_type(r),
758 ResourceItemName::Static(kebab_to_snake(n)),
759 );
760 }
761 FnName::Plain(kebab_to_snake(n))
762}