1use rucc_base::{Interner, Symbol};
32
33use crate::kind::{ArrayLen, FunctionId, Qualifiers, Type, TypeKind};
34use crate::types::{TypeId, Types};
35
36#[must_use]
38pub fn spell(types: &Types, names: &Interner, id: TypeId) -> String {
39 Speller { types, names }.declaration(id, String::new())
40}
41
42#[must_use]
44pub fn declare(types: &Types, names: &Interner, id: TypeId, name: Symbol) -> String {
45 Speller { types, names }.declaration(id, names.resolve(name).to_owned())
46}
47
48#[derive(Debug)]
50struct Speller<'a> {
51 types: &'a Types,
52 names: &'a Interner,
53}
54
55impl Speller<'_> {
56 fn declaration(&self, id: TypeId, inner: String) -> String {
62 let ty = self.types.get(id);
63 let base = match ty.kind {
64 TypeKind::Pointer(pointee) => return self.pointer(ty, pointee, inner),
65 TypeKind::Array { elem, len } => return self.array(ty, elem, len, inner),
66 TypeKind::Function(function) => return self.function(function, inner),
67 TypeKind::Void => String::from("void"),
68 TypeKind::Bool => String::from("_Bool"),
71 TypeKind::Int(kind) => String::from(kind.as_str()),
72 TypeKind::Float(kind) => String::from(kind.as_str()),
73 TypeKind::Complex(kind) => format!("_Complex {}", kind.as_str()),
74 TypeKind::BitInt { signed, width } => {
75 let sign = if signed { "" } else { "unsigned " };
76 format!("{sign}_BitInt({width})")
77 }
78 TypeKind::Atomic(inner) => format!("_Atomic({})", self.spell(inner)),
83 TypeKind::Vector { elem, len } => format!("__vector({len}) {}", self.spell(elem)),
86 TypeKind::Record(record) => {
87 let info = self.types.record_info(record);
88 format!("{} {}", info.kind.as_str(), self.tag(info.tag))
89 }
90 TypeKind::Enum(enumeration) => {
91 let info = self.types.enum_info(enumeration);
92 format!("enum {}", self.tag(info.tag))
93 }
94 TypeKind::Typedef { name, .. } => self.names.resolve(name).to_owned(),
95 };
96
97 let mut out = String::new();
98 if let Some(quals) = quals_text(ty.quals) {
99 out.push_str(quals);
100 out.push(' ');
101 }
102 out.push_str(&base);
103 if !inner.is_empty() {
104 out.push(' ');
105 out.push_str(&inner);
106 }
107 out
108 }
109
110 fn pointer(&self, ty: Type, pointee: TypeId, inner: String) -> String {
113 let mut declarator = String::from("*");
114 if let Some(quals) = quals_text(ty.quals) {
115 declarator.push_str(quals);
116 if !inner.is_empty() {
117 declarator.push(' ');
118 }
119 }
120 declarator.push_str(&inner);
121 if matches!(self.types.kind(pointee), TypeKind::Array { .. } | TypeKind::Function(_)) {
126 declarator = format!("({declarator})");
127 }
128 self.declaration(pointee, declarator)
129 }
130
131 fn array(&self, ty: Type, elem: TypeId, len: ArrayLen, inner: String) -> String {
133 let mut declarator = inner;
134 declarator.push('[');
135 if let Some(quals) = quals_text(ty.quals) {
136 declarator.push_str(quals);
137 if !matches!(len, ArrayLen::Unknown) {
138 declarator.push(' ');
139 }
140 }
141 match len {
142 ArrayLen::Fixed(count) => declarator.push_str(&count.to_string()),
143 ArrayLen::Unknown => {}
144 ArrayLen::Star | ArrayLen::Variable(_) => declarator.push('*'),
147 }
148 declarator.push(']');
149 self.declaration(elem, declarator)
150 }
151
152 fn function(&self, function: FunctionId, inner: String) -> String {
154 let signature = self.types.signature(function);
155 let mut declarator = inner;
156 declarator.push('(');
157 for (index, ¶m) in signature.params.iter().enumerate() {
158 if index > 0 {
159 declarator.push_str(", ");
160 }
161 declarator.push_str(&self.spell(param));
162 }
163 if signature.variadic {
164 if !signature.params.is_empty() {
165 declarator.push_str(", ");
166 }
167 declarator.push_str("...");
168 } else if signature.params.is_empty() && signature.prototyped {
169 declarator.push_str("void");
172 }
173 declarator.push(')');
174 self.declaration(signature.ret, declarator)
175 }
176
177 fn spell(&self, id: TypeId) -> String {
179 self.declaration(id, String::new())
180 }
181
182 fn tag(&self, tag: Option<Symbol>) -> String {
184 match tag {
185 Some(name) => self.names.resolve(name).to_owned(),
186 None => String::from("<anonymous>"),
187 }
188 }
189}
190
191fn quals_text(quals: Qualifiers) -> Option<&'static str> {
193 match (
196 quals.has(Qualifiers::CONST),
197 quals.has(Qualifiers::VOLATILE),
198 quals.has(Qualifiers::RESTRICT),
199 ) {
200 (false, false, false) => None,
201 (true, false, false) => Some("const"),
202 (false, true, false) => Some("volatile"),
203 (false, false, true) => Some("restrict"),
204 (true, true, false) => Some("const volatile"),
205 (true, false, true) => Some("const restrict"),
206 (false, true, true) => Some("volatile restrict"),
207 (true, true, true) => Some("const volatile restrict"),
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use rucc_base::Interner;
214
215 use super::*;
216 use crate::kind::{ArrayLen, FloatKind, FunctionType, IntKind, RecordKind};
217
218 fn fixture() -> (Types, Interner) {
220 (Types::new(), Interner::new())
221 }
222
223 #[test]
224 fn a_basic_type_is_its_keywords() {
225 let (types, names) = fixture();
226 let int = types.int(IntKind::Int);
227 assert_eq!(spell(&types, &names, int), "int");
228 assert_eq!(spell(&types, &names, types.void()), "void");
229 assert_eq!(spell(&types, &names, types.boolean()), "_Bool");
230 let long_double = types.float(FloatKind::LongDouble);
231 assert_eq!(spell(&types, &names, long_double), "long double");
232 }
233
234 #[test]
235 fn a_qualifier_goes_in_front_of_what_it_qualifies() {
236 let (mut types, names) = fixture();
237 let int = types.int(IntKind::Int);
238 let qualified = types.qualified(int, Qualifiers::CONST.with(Qualifiers::VOLATILE));
239 assert_eq!(spell(&types, &names, qualified), "const volatile int");
240 }
241
242 #[test]
243 fn a_pointers_own_qualifier_goes_after_the_star() {
244 let (mut types, names) = fixture();
245 let char_type = types.int(IntKind::Char);
246 let constant = types.qualified(char_type, Qualifiers::CONST);
247 let pointer = types.pointer(constant);
248 let constant_pointer = types.qualified(pointer, Qualifiers::CONST);
249 assert_eq!(spell(&types, &names, constant_pointer), "const char *const");
250 }
251
252 #[test]
253 fn a_qualified_pointer_with_a_name_keeps_them_apart() {
254 let (mut types, mut names) = fixture();
255 let int = types.int(IntKind::Int);
256 let pointer = types.pointer(int);
257 let restricted = types.qualified(pointer, Qualifiers::RESTRICT);
258 let p = names.intern("p");
259 assert_eq!(declare(&types, &names, restricted, p), "int *restrict p");
260 }
261
262 #[test]
263 fn a_declarator_is_written_around_the_name() {
264 let (mut types, mut names) = fixture();
265 let int = types.int(IntKind::Int);
266 let char_type = types.int(IntKind::Char);
267 let signature =
268 FunctionType { ret: int, params: vec![char_type], variadic: false, prototyped: true };
269 let function = types.function(signature);
270 let pointer = types.pointer(function);
271 let array = types.array(pointer, ArrayLen::Fixed(3));
272 let f = names.intern("f");
273 assert_eq!(declare(&types, &names, array, f), "int (*f[3])(char)");
274 }
275
276 #[test]
277 fn an_abstract_declarator_keeps_the_parentheses_the_name_would_have_needed() {
278 let (mut types, names) = fixture();
279 let int = types.int(IntKind::Int);
280 let array = types.array(int, ArrayLen::Fixed(3));
281 let pointer = types.pointer(array);
282 assert_eq!(spell(&types, &names, pointer), "int (*)[3]");
283 }
284
285 #[test]
286 fn an_array_of_arrays_reads_left_to_right() {
287 let (mut types, mut names) = fixture();
288 let int = types.int(IntKind::Int);
289 let inner = types.array(int, ArrayLen::Fixed(3));
290 let outer = types.array(inner, ArrayLen::Fixed(2));
291 let a = names.intern("a");
292 assert_eq!(declare(&types, &names, outer, a), "int a[2][3]");
293 }
294
295 #[test]
296 fn an_array_without_a_size_says_so_and_a_variable_one_says_only_that_it_has_one() {
297 let (mut types, names) = fixture();
298 let int = types.int(IntKind::Int);
299 let unknown = types.array(int, ArrayLen::Unknown);
300 let variable = types.array(int, ArrayLen::Variable(crate::kind::VlaId(0)));
301 assert_eq!(spell(&types, &names, unknown), "int []");
302 assert_eq!(spell(&types, &names, variable), "int [*]");
303 }
304
305 #[test]
306 fn a_prototype_with_no_parameters_is_not_a_function_without_one() {
307 let (mut types, names) = fixture();
308 let int = types.int(IntKind::Int);
309 let prototyped =
310 FunctionType { ret: int, params: Vec::new(), variadic: false, prototyped: true };
311 let old = FunctionType { ret: int, params: Vec::new(), variadic: false, prototyped: false };
312 let prototyped = types.function(prototyped);
313 let old = types.function(old);
314 let prototyped = types.pointer(prototyped);
315 let old = types.pointer(old);
316 assert_eq!(spell(&types, &names, prototyped), "int (*)(void)");
317 assert_eq!(spell(&types, &names, old), "int (*)()");
318 }
319
320 #[test]
321 fn a_variadic_function_ends_in_the_ellipsis() {
322 let (mut types, names) = fixture();
323 let int = types.int(IntKind::Int);
324 let char_type = types.int(IntKind::Char);
325 let signature =
326 FunctionType { ret: int, params: vec![char_type], variadic: true, prototyped: true };
327 let function = types.function(signature);
328 let pointer = types.pointer(function);
329 assert_eq!(spell(&types, &names, pointer), "int (*)(char, ...)");
330 }
331
332 #[test]
333 fn a_typedef_is_spelled_as_itself_and_its_canonical_form_as_what_it_stands_for() {
334 let (mut types, mut names) = fixture();
335 let ulong = types.int(IntKind::ULong);
336 let name = names.intern("size_t");
337 let size_t = types.typedef(name, ulong);
338 let pointer = types.pointer(size_t);
339 assert_eq!(spell(&types, &names, pointer), "size_t *");
340 let canonical = types.canonical(pointer);
341 assert_eq!(spell(&types, &names, canonical), "unsigned long *");
342 }
343
344 #[test]
345 fn a_tag_that_was_never_written_is_named_the_way_gcc_names_it() {
346 let (mut types, mut names) = fixture();
347 let tag = names.intern("S");
348 let named = types.declare_record(RecordKind::Struct, Some(tag));
349 let unnamed = types.declare_record(RecordKind::Union, None);
350 let named = types.record(named);
351 let unnamed = types.record(unnamed);
352 assert_eq!(spell(&types, &names, named), "struct S");
353 assert_eq!(spell(&types, &names, unnamed), "union <anonymous>");
354 }
355
356 #[test]
357 fn an_atomic_type_is_written_as_the_type_it_is() {
358 let (mut types, names) = fixture();
359 let int = types.int(IntKind::Int);
360 let atomic = types.atomic(int);
361 let pointer = types.pointer(atomic);
362 assert_eq!(spell(&types, &names, atomic), "_Atomic(int)");
363 assert_eq!(spell(&types, &names, pointer), "_Atomic(int) *");
364 }
365
366 #[test]
367 fn a_vector_is_written_the_way_gcc_writes_one() {
368 let (mut types, names) = fixture();
369 let int = types.int(IntKind::Int);
370 let vector = types.vector(int, 4);
371 assert_eq!(spell(&types, &names, vector), "__vector(4) int");
372 }
373}