Skip to main content

rucc_types/
print.rs

1//! Spelling a type the way a person would write it.
2//!
3//! Design: `spec/07-types-and-semantics.md` section 7.1.
4//!
5//! Every diagnostic that mentions a type needs one of these, and so does the typed tree's
6//! textual form. The rule the type table already follows is that a semantic decision reads the
7//! canonical type and a message reads the type as written, so this prints the sugar: a
8//! `size_t` prints as `size_t` and not as `unsigned long`, and a caller that wants both prints
9//! the canonical form as well, which is what gcc's `size_t {aka long unsigned int}` is doing.
10//!
11//! A type is not a string of words in C. It is a declaration with a hole in it, and the hole is
12//! where the name goes, so `int (*f[3])(char)` is the way an array of pointers to functions is
13//! written and there is no other. That is why this is assembled outward from the hole rather
14//! than printed left to right, and why the abstract form is the same algorithm with an empty
15//! hole, which gives `int (*)[3]` with the parentheses still in it. Both spellings were
16//! measured against gcc 13.3 rather than recalled.
17//!
18//! ```
19//! use rucc_base::Interner;
20//! use rucc_types::{ArrayLen, IntKind, Types, spell};
21//!
22//! let interner = Interner::new();
23//! let mut types = Types::new();
24//! let int = types.int(IntKind::Int);
25//! let array = types.array(int, ArrayLen::Fixed(3));
26//! let pointer = types.pointer(array);
27//!
28//! assert_eq!(spell(&types, &interner, pointer), "int (*)[3]");
29//! ```
30
31use rucc_base::{Interner, Symbol};
32
33use crate::kind::{ArrayLen, FunctionId, Qualifiers, Type, TypeKind};
34use crate::types::{TypeId, Types};
35
36/// The type as a type name, which is how it would be written in a cast or in a `sizeof`.
37#[must_use]
38pub fn spell(types: &Types, names: &Interner, id: TypeId) -> String {
39    Speller { types, names }.declaration(id, String::new())
40}
41
42/// The type as a declaration of `name`, which is how it would be written in the program.
43#[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/// What one spelling needs to reach for.
49#[derive(Debug)]
50struct Speller<'a> {
51    types: &'a Types,
52    names: &'a Interner,
53}
54
55impl Speller<'_> {
56    /// The declaration of something named `inner` whose type is `id`.
57    ///
58    /// `inner` is the declarator built so far, which starts as the name and grows outward. The
59    /// three shapes that are written around a name return early and the rest are written in
60    /// front of it, which is the whole of C's declarator grammar read backwards.
61    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            // `_Bool` rather than `bool` in both C17 and C23, which is what gcc 13.3 prints in
69            // either dialect and which is unambiguous in a program that has typedefed `bool`.
70            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            // `_Atomic(T)` and not `_Atomic T`, which is what gcc writes. The two are the same
79            // type and only one of them can be written in front of a pointer without changing
80            // what it means, and this crate holds `_Atomic` as a type rather than a qualifier
81            // for that reason.
82            TypeKind::Atomic(inner) => format!("_Atomic({})", self.spell(inner)),
83            // gcc 13.3 writes a vector this way and so does its `{aka}` form, so a program
84            // that has a name for the type sees the name and everything else sees this.
85            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    /// A pointer, whose qualifiers are written after the `*` because they are the pointer's own
111    /// and not the pointee's.
112    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        // An array or a function binds tighter than the `*`, so without these the type would
122        // read as an array of pointers or a function returning one. The sugar of a typedef
123        // stops the recursion before this can matter, which is why `A *` needs nothing when
124        // `A` is an array.
125        if matches!(self.types.kind(pointee), TypeKind::Array { .. } | TypeKind::Function(_)) {
126            declarator = format!("({declarator})");
127        }
128        self.declaration(pointee, declarator)
129    }
130
131    /// An array, whose qualifiers have a spelling only inside the brackets.
132    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            // A variable length array's size is an expression the type does not hold, so this
145            // says that there is one rather than inventing a name for it.
146            ArrayLen::Star | ArrayLen::Variable(_) => declarator.push('*'),
147        }
148        declarator.push(']');
149        self.declaration(elem, declarator)
150    }
151
152    /// A function, whose parameters are type names in their own right.
153    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, &param) 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            // `()` is a function whose parameters are unknown and `(void)` is one that takes
170            // none, and the two are different types in every dialect before C23.
171            declarator.push_str("void");
172        }
173        declarator.push(')');
174        self.declaration(signature.ret, declarator)
175    }
176
177    /// The type on its own, which is what a parameter and the inside of an `_Atomic` are.
178    fn spell(&self, id: TypeId) -> String {
179        self.declaration(id, String::new())
180    }
181
182    /// A tag, or what gcc calls one that was never given.
183    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
191/// The qualifier keywords in the order C writes them, or nothing at all.
192fn quals_text(quals: Qualifiers) -> Option<&'static str> {
193    // Sixteen combinations of three flags, written out rather than assembled, because the
194    // answer is a constant string in every case and this is on the path of every diagnostic.
195    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    /// A table with a name in it, which is what every spelling below starts from.
219    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}