golem_wasm/analysis/
wave.rs

1use crate::analysis::{
2    AnalysedFunction, AnalysedType, TypeEnum, TypeFlags, TypeList, TypeOption, TypeRecord,
3    TypeResult, TypeTuple, TypeVariant,
4};
5use std::borrow::Cow;
6use std::fmt::Display;
7use wasm_wave::wasm::{DisplayType, WasmFunc, WasmType, WasmTypeKind};
8
9impl WasmType for AnalysedType {
10    fn kind(&self) -> WasmTypeKind {
11        match self {
12            AnalysedType::Bool(_) => WasmTypeKind::Bool,
13            AnalysedType::S8(_) => WasmTypeKind::S8,
14            AnalysedType::U8(_) => WasmTypeKind::U8,
15            AnalysedType::S16(_) => WasmTypeKind::S16,
16            AnalysedType::U16(_) => WasmTypeKind::U16,
17            AnalysedType::S32(_) => WasmTypeKind::S32,
18            AnalysedType::U32(_) => WasmTypeKind::U32,
19            AnalysedType::S64(_) => WasmTypeKind::S64,
20            AnalysedType::U64(_) => WasmTypeKind::U64,
21            AnalysedType::F32(_) => WasmTypeKind::F32,
22            AnalysedType::F64(_) => WasmTypeKind::F64,
23            AnalysedType::Chr(_) => WasmTypeKind::Char,
24            AnalysedType::Str(_) => WasmTypeKind::String,
25            AnalysedType::List(_) => WasmTypeKind::List,
26            AnalysedType::Tuple(_) => WasmTypeKind::Tuple,
27            AnalysedType::Record(_) => WasmTypeKind::Record,
28            AnalysedType::Flags(_) => WasmTypeKind::Flags,
29            AnalysedType::Enum(_) => WasmTypeKind::Enum,
30            AnalysedType::Option(_) => WasmTypeKind::Option,
31            AnalysedType::Result { .. } => WasmTypeKind::Result,
32            AnalysedType::Variant(_) => WasmTypeKind::Variant,
33            AnalysedType::Handle(_) => WasmTypeKind::Unsupported,
34        }
35    }
36
37    fn list_element_type(&self) -> Option<Self> {
38        if let AnalysedType::List(TypeList { inner: ty, .. }) = self {
39            Some(*ty.clone())
40        } else {
41            None
42        }
43    }
44
45    fn record_fields(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Self)> + '_> {
46        if let AnalysedType::Record(TypeRecord { fields, .. }) = self {
47            Box::new(
48                fields
49                    .iter()
50                    .map(|pair| (Cow::Borrowed(pair.name.as_str()), pair.typ.clone())),
51            )
52        } else {
53            Box::new(std::iter::empty())
54        }
55    }
56
57    fn tuple_element_types(&self) -> Box<dyn Iterator<Item = Self> + '_> {
58        if let AnalysedType::Tuple(TypeTuple { items, .. }) = self {
59            Box::new(items.clone().into_iter())
60        } else {
61            Box::new(std::iter::empty())
62        }
63    }
64
65    fn variant_cases(&self) -> Box<dyn Iterator<Item = (Cow<'_, str>, Option<Self>)> + '_> {
66        if let AnalysedType::Variant(TypeVariant { cases, .. }) = self {
67            Box::new(
68                cases
69                    .iter()
70                    .map(|case| (Cow::Borrowed(case.name.as_str()), case.typ.clone())),
71            )
72        } else {
73            Box::new(std::iter::empty())
74        }
75    }
76
77    fn enum_cases(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_> {
78        if let AnalysedType::Enum(TypeEnum { cases, .. }) = self {
79            Box::new(cases.iter().map(|name| Cow::Borrowed(name.as_str())))
80        } else {
81            Box::new(std::iter::empty())
82        }
83    }
84
85    fn option_some_type(&self) -> Option<Self> {
86        if let AnalysedType::Option(TypeOption { inner, .. }) = self {
87            Some(*inner.clone())
88        } else {
89            None
90        }
91    }
92
93    fn result_types(&self) -> Option<(Option<Self>, Option<Self>)> {
94        if let AnalysedType::Result(TypeResult { ok, err, .. }) = self {
95            Some((
96                ok.as_ref().map(|t| *t.clone()),
97                err.as_ref().map(|t| *t.clone()),
98            ))
99        } else {
100            None
101        }
102    }
103
104    fn flags_names(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_> {
105        if let AnalysedType::Flags(TypeFlags { names, .. }) = self {
106            Box::new(names.iter().map(|name| Cow::Borrowed(name.as_str())))
107        } else {
108            Box::new(std::iter::empty())
109        }
110    }
111}
112
113impl WasmFunc for AnalysedFunction {
114    type Type = AnalysedType;
115
116    fn params(&self) -> Box<dyn Iterator<Item = Self::Type> + '_> {
117        Box::new(self.parameters.iter().map(|p| p.typ.clone()))
118    }
119
120    fn param_names(&self) -> Box<dyn Iterator<Item = Cow<'_, str>> + '_> {
121        Box::new(
122            self.parameters
123                .iter()
124                .map(|p| Cow::Borrowed(p.name.as_str())),
125        )
126    }
127
128    fn results(&self) -> Box<dyn Iterator<Item = Self::Type> + '_> {
129        Box::new(self.result.iter().map(|r| r.typ.clone()))
130    }
131}
132
133/// Copy of DisplayFunc with additional name filed.
134/// DisplayFunc is always using func for name
135pub struct DisplayNamedFunc<T: WasmFunc> {
136    pub name: String,
137    pub func: T,
138}
139
140impl<T: WasmFunc> Display for DisplayNamedFunc<T> {
141    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142        f.write_str(&self.name)?;
143        f.write_str("(")?;
144        let mut param_names = self.func.param_names();
145        for (idx, ty) in self.func.params().enumerate() {
146            if idx != 0 {
147                f.write_str(", ")?;
148            }
149            if let Some(name) = param_names.next() {
150                write!(f, "{name}: ")?;
151            }
152            DisplayType(&ty).fmt(f)?
153        }
154        f.write_str(")")?;
155
156        let results = self.func.results().collect::<Vec<_>>();
157        if results.is_empty() {
158            return Ok(());
159        }
160
161        let mut result_names = self.func.result_names();
162        if results.len() == 1 {
163            let ty = DisplayType(&results.into_iter().next().unwrap()).to_string();
164            if let Some(name) = result_names.next() {
165                write!(f, " -> ({name}: {ty})")
166            } else {
167                write!(f, " -> {ty}")
168            }
169        } else {
170            f.write_str(" -> (")?;
171            for (idx, ty) in results.into_iter().enumerate() {
172                if idx != 0 {
173                    f.write_str(", ")?;
174                }
175                if let Some(name) = result_names.next() {
176                    write!(f, "{name}: ")?;
177                }
178                DisplayType(&ty).fmt(f)?;
179            }
180            f.write_str(")")
181        }
182    }
183}