1use super::{
2 signature::Signature,
3 types::{FieldType, Fields, HeapType, OperandType, RefType, StorageType, ValType},
4};
5use crate::{helpers::RenderWithDb, idx::InternIdent};
6use std::fmt::{self, Display, Write};
7use wat_syntax::SyntaxKind;
8
9impl<'db> Signature<'db> {
10 pub(crate) fn render(&self, db: &'db dyn salsa::Database) -> RenderWithDb<'db, (&Self, bool)> {
11 RenderWithDb {
12 value: (self, false),
13 db,
14 }
15 }
16 pub(crate) fn render_compact(
17 &self,
18 db: &'db dyn salsa::Database,
19 ) -> RenderWithDb<'db, (&Self, bool)> {
20 RenderWithDb {
21 value: (self, true),
22 db,
23 }
24 }
25}
26impl Display for RenderWithDb<'_, (&Signature<'_>, bool)> {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 if self.value.1 {
29 write!(f, "[")?;
30 let mut params = self.value.0.params.iter();
31 if let Some((ty, _)) = params.next() {
32 write!(f, "{}", ty.render(self.db))?;
33 params.try_for_each(|(ty, _)| write!(f, ", {}", ty.render(self.db)))?;
34 }
35 write!(f, "] -> [")?;
36 let mut results = self.value.0.results.iter();
37 if let Some(ty) = results.next() {
38 write!(f, "{}", ty.render(self.db))?;
39 results.try_for_each(|ty| write!(f, ", {}", ty.render(self.db)))?;
40 }
41 write!(f, "]")
42 } else {
43 let mut has_params = false;
44 let mut params = self.value.0.params.iter();
45 if let Some((ty, name)) = params.next() {
46 has_params = true;
47 if let Some(name) = name {
48 write!(f, "(param {} {})", name.ident(self.db), ty.render(self.db))?;
49 } else {
50 write!(f, "(param {})", ty.render(self.db))?;
51 }
52 params.try_for_each(|(ty, name)| {
53 if let Some(name) = name {
54 write!(f, " (param {} {})", name.ident(self.db), ty.render(self.db))
55 } else {
56 write!(f, " (param {})", ty.render(self.db))
57 }
58 })?;
59 }
60 let mut results = self.value.0.results.iter();
61 if let Some(ty) = results.next() {
62 if has_params {
63 write!(f, " ")?;
64 }
65 write!(f, "(result {})", ty.render(self.db))?;
66 results.try_for_each(|ty| write!(f, " (result {})", ty.render(self.db)))
67 } else {
68 Ok(())
69 }
70 }
71 }
72}
73
74#[salsa::tracked]
75pub(crate) fn render_func_header<'db>(
76 db: &'db dyn salsa::Database,
77 name: Option<InternIdent<'db>>,
78 signature: Signature<'db>,
79) -> String {
80 let mut content = "(func".to_string();
81 if let Some(name) = name {
82 content.push(' ');
83 content.push_str(name.ident(db));
84 }
85 if !signature.params.is_empty() || !signature.results.is_empty() {
86 content.push(' ');
87 let _ = write!(content, "{}", signature.render(db));
88 }
89 content.push(')');
90 content
91}
92
93#[salsa::tracked]
94pub(crate) fn render_block_header<'db>(
95 db: &'db dyn salsa::Database,
96 kind: SyntaxKind,
97 name: Option<InternIdent<'db>>,
98 signature: Signature<'db>,
99) -> String {
100 let mut content = format!(
101 "({}",
102 match kind {
103 SyntaxKind::BLOCK_IF => "if",
104 SyntaxKind::BLOCK_LOOP => "loop",
105 SyntaxKind::MODULE_FIELD_FUNC => "func",
106 _ => "block",
107 }
108 );
109 if let Some(name) = name {
110 content.push(' ');
111 content.push_str(name.ident(db));
112 }
113 if !signature.params.is_empty() || !signature.results.is_empty() {
114 content.push(' ');
115 let _ = write!(content, "{}", signature.render(db));
116 }
117 content.push(')');
118 content
119}
120
121impl<'db> RefType<'db> {
122 pub(crate) fn render(&self, db: &'db dyn salsa::Database) -> RenderWithDb<'db, &Self> {
123 RenderWithDb { value: self, db }
124 }
125}
126impl Display for RenderWithDb<'_, &RefType<'_>> {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 if matches!(self.value.heap_ty, HeapType::DefFunc(..)) {
129 write!(f, "(func ")?;
130 } else {
131 write!(f, "(ref ")?;
132 }
133 if self.value.nullable {
134 write!(f, "null ")?;
135 }
136 match self.value.heap_ty {
137 HeapType::Type(idx) | HeapType::DefFunc(idx) => {
138 if let Some(name) = idx.name {
139 write!(f, "{}", name.ident(self.db))?;
140 } else if let Some(num) = idx.num {
141 write!(f, "{num}")?;
142 }
143 }
144 HeapType::Any => write!(f, "any")?,
145 HeapType::Eq => write!(f, "eq")?,
146 HeapType::I31 => write!(f, "i31")?,
147 HeapType::Struct => write!(f, "struct")?,
148 HeapType::Array => write!(f, "array")?,
149 HeapType::None => write!(f, "none")?,
150 HeapType::Func => write!(f, "func")?,
151 HeapType::NoFunc => write!(f, "nofunc")?,
152 HeapType::Extern => write!(f, "extern")?,
153 HeapType::NoExtern => write!(f, "noextern")?,
154 HeapType::Rec(..) => unreachable!("rec type is only for internal use"),
155 }
156 write!(f, ")")
157 }
158}
159
160impl<'db> ValType<'db> {
161 pub(crate) fn render(&self, db: &'db dyn salsa::Database) -> RenderWithDb<'db, &Self> {
162 RenderWithDb { value: self, db }
163 }
164}
165impl Display for RenderWithDb<'_, &ValType<'_>> {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 match &self.value {
168 ValType::I32 => write!(f, "i32"),
169 ValType::I64 => write!(f, "i64"),
170 ValType::F32 => write!(f, "f32"),
171 ValType::F64 => write!(f, "f64"),
172 ValType::V128 => write!(f, "v128"),
173 ValType::Ref(ty) => ty.render(self.db).fmt(f),
174 }
175 }
176}
177
178impl<'db> OperandType<'db> {
179 pub(crate) fn render(&self, db: &'db dyn salsa::Database) -> RenderWithDb<'db, &Self> {
180 RenderWithDb { value: self, db }
181 }
182}
183impl Display for RenderWithDb<'_, &OperandType<'_>> {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 match self.value {
186 OperandType::Val(ty) => write!(f, "{}", ty.render(self.db)),
187 OperandType::Any => write!(f, "any"),
188 }
189 }
190}
191
192impl<'db> FieldType<'db> {
193 pub(crate) fn render(&self, db: &'db dyn salsa::Database) -> RenderWithDb<'db, &Self> {
194 RenderWithDb { value: self, db }
195 }
196}
197impl Display for RenderWithDb<'_, &FieldType<'_>> {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 if self.value.mutable {
200 write!(f, "(mut ")?;
201 }
202 match &self.value.storage {
203 StorageType::Val(ty) => write!(f, "{}", ty.render(self.db))?,
204 StorageType::PackedI8 => write!(f, "i8")?,
205 StorageType::PackedI16 => write!(f, "i16")?,
206 }
207 if self.value.mutable {
208 write!(f, ")")?;
209 }
210 Ok(())
211 }
212}
213
214impl<'db> Fields<'db> {
215 pub(crate) fn render(&self, db: &'db dyn salsa::Database) -> RenderWithDb<'db, &Self> {
216 RenderWithDb { value: self, db }
217 }
218}
219impl Display for RenderWithDb<'_, &Fields<'_>> {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 self.value.0.iter().try_fold(true, |first, field| {
222 if !first {
223 write!(f, " ")?;
224 }
225 write!(f, "(field ")?;
226 if let Some(name) = field.1.name {
227 write!(f, "{} ", name.ident(self.db))?;
228 }
229 write!(f, "{}", field.0.render(self.db))?;
230 write!(f, ")")?;
231 Ok(false)
232 })?;
233 Ok(())
234 }
235}