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 rather than recalled.
17//!
18//! The one place the two spellings differ in more than the name is the space in front of the
19//! declarator. gcc writes `int[3]` and `int(void)` with nothing between them, because there is
20//! nothing there to separate, and writes `int (*)[3]` with a space, because there is. That is
21//! what [`Declarator::glued`] carries, and it is why an array of a type and a declaration of
22//! one do not look the same.
23//!
24//! ```
25//! use rucc_base::Interner;
26//! use rucc_types::{ArrayLen, IntKind, Types, spell};
27//!
28//! let interner = Interner::new();
29//! let mut types = Types::new();
30//! let int = types.int(IntKind::Int);
31//! let array = types.array(int, ArrayLen::Fixed(3));
32//! let pointer = types.pointer(array);
33//!
34//! assert_eq!(spell(&types, &interner, pointer), "int (*)[3]");
35//! ```
36
37use rucc_base::{Interner, Symbol};
38
39use crate::kind::{ArrayLen, FunctionId, Qualifiers, Type, TypeKind};
40use crate::types::{TypeId, Types};
41
42/// The type as a type name, which is how it would be written in a cast or in a `sizeof`.
43#[must_use]
44pub fn spell(types: &Types, names: &Interner, id: TypeId) -> String {
45    Speller { types, names }.declaration(id, Declarator::nothing())
46}
47
48/// The type as a declaration of `name`, which is how it would be written in the program.
49#[must_use]
50pub fn declare(types: &Types, names: &Interner, id: TypeId, name: Symbol) -> String {
51    Speller { types, names }.declaration(id, Declarator::of(names.resolve(name).to_owned()))
52}
53
54/// The part of a declaration that is not the type in front of it, built outward from the hole
55/// where the name goes.
56#[derive(Debug)]
57struct Declarator {
58    /// What has been written around the hole so far.
59    text: String,
60    /// Whether it sits against the type with no space between them. The suffixes a type wears on
61    /// its right go hard against it, which is `int[3]` and `int(void)`, and anything with a `*`
62    /// in front of them takes the space back, which is `int (*)[3]`. That is gcc's spelling and
63    /// it is not a test of the first character, since `(*)[3]` starts with the same bracket a
64    /// parameter list does.
65    glued: bool,
66}
67
68impl Declarator {
69    /// The empty declarator, which is what a type name has.
70    fn nothing() -> Declarator {
71        Declarator { text: String::new(), glued: false }
72    }
73
74    /// A declarator that is a name, or a piece of one that has a `*` in it.
75    fn of(text: String) -> Declarator {
76        Declarator { text, glued: false }
77    }
78
79    /// The declarator with a suffix written after it, which keeps it against the type when there
80    /// was nothing in front of the suffix to separate them.
81    fn suffixed(self, suffix: &str) -> Declarator {
82        let glued = self.glued || self.text.is_empty();
83        Declarator { text: self.text + suffix, glued }
84    }
85}
86
87/// What one spelling needs to reach for.
88#[derive(Debug)]
89struct Speller<'a> {
90    types: &'a Types,
91    names: &'a Interner,
92}
93
94impl Speller<'_> {
95    /// The declaration of something named `inner` whose type is `id`.
96    ///
97    /// `inner` is the declarator built so far, which starts as the name and grows outward. The
98    /// three shapes that are written around a name return early and the rest are written in
99    /// front of it, which is the whole of C's declarator grammar read backwards.
100    fn declaration(&self, id: TypeId, inner: Declarator) -> String {
101        let ty = self.types.get(id);
102        let base = match ty.kind {
103            TypeKind::Pointer(pointee) => return self.pointer(ty, pointee, inner),
104            TypeKind::Array { elem, len } => return self.array(ty, elem, len, inner),
105            TypeKind::Function(function) => return self.function(function, inner),
106            TypeKind::Void => String::from("void"),
107            // `_Bool` rather than `bool` in both C17 and C23, which is what gcc 13.3 prints in
108            // either dialect and which is unambiguous in a program that has typedefed `bool`.
109            TypeKind::Bool => String::from("_Bool"),
110            TypeKind::Int(kind) => String::from(kind.as_str()),
111            TypeKind::Float(kind) => String::from(kind.as_str()),
112            TypeKind::Complex(kind) => format!("_Complex {}", kind.as_str()),
113            TypeKind::BitInt { signed, width } => {
114                let sign = if signed { "" } else { "unsigned " };
115                format!("{sign}_BitInt({width})")
116            }
117            // `_Atomic(T)` and not `_Atomic T`, which is what gcc writes. The two are the same
118            // type and only one of them can be written in front of a pointer without changing
119            // what it means, and this crate holds `_Atomic` as a type rather than a qualifier
120            // for that reason.
121            TypeKind::Atomic(inner) => format!("_Atomic({})", self.spell(inner)),
122            // gcc 13.3 writes a vector this way and so does its `{aka}` form, so a program
123            // that has a name for the type sees the name and everything else sees this.
124            TypeKind::Vector { elem, len } => format!("__vector({len}) {}", self.spell(elem)),
125            TypeKind::Record(record) => {
126                let info = self.types.record_info(record);
127                format!("{} {}", info.kind.as_str(), self.tag(info.tag))
128            }
129            TypeKind::Enum(enumeration) => {
130                let info = self.types.enum_info(enumeration);
131                format!("enum {}", self.tag(info.tag))
132            }
133            TypeKind::Typedef { name, .. } => self.names.resolve(name).to_owned(),
134        };
135
136        let mut out = String::new();
137        if let Some(quals) = quals_text(ty.quals) {
138            out.push_str(quals);
139            out.push(' ');
140        }
141        out.push_str(&base);
142        if !inner.text.is_empty() {
143            if !inner.glued {
144                out.push(' ');
145            }
146            out.push_str(&inner.text);
147        }
148        out
149    }
150
151    /// A pointer, whose qualifiers are written after the `*` because they are the pointer's own
152    /// and not the pointee's.
153    fn pointer(&self, ty: Type, pointee: TypeId, inner: Declarator) -> String {
154        let mut declarator = String::from("*");
155        if let Some(quals) = quals_text(ty.quals) {
156            declarator.push_str(quals);
157            if !inner.text.is_empty() {
158                declarator.push(' ');
159            }
160        }
161        declarator.push_str(&inner.text);
162        // An array or a function binds tighter than the `*`, so without these the type would
163        // read as an array of pointers or a function returning one. The sugar of a typedef
164        // stops the recursion before this can matter, which is why `A *` needs nothing when
165        // `A` is an array.
166        if matches!(self.types.kind(pointee), TypeKind::Array { .. } | TypeKind::Function(_)) {
167            declarator = format!("({declarator})");
168        }
169        self.declaration(pointee, Declarator::of(declarator))
170    }
171
172    /// An array, whose qualifiers have a spelling only inside the brackets.
173    fn array(&self, ty: Type, elem: TypeId, len: ArrayLen, inner: Declarator) -> String {
174        let mut suffix = String::from("[");
175        if let Some(quals) = quals_text(ty.quals) {
176            suffix.push_str(quals);
177            if !matches!(len, ArrayLen::Unknown) {
178                suffix.push(' ');
179            }
180        }
181        match len {
182            ArrayLen::Fixed(count) => suffix.push_str(&count.to_string()),
183            ArrayLen::Unknown => {}
184            // A variable length array's size is an expression the type does not hold, so this
185            // says that there is one rather than inventing a name for it.
186            ArrayLen::Star | ArrayLen::Variable(_) => suffix.push('*'),
187        }
188        suffix.push(']');
189        self.declaration(elem, inner.suffixed(&suffix))
190    }
191
192    /// A function, whose parameters are type names in their own right.
193    fn function(&self, function: FunctionId, inner: Declarator) -> String {
194        let signature = self.types.signature(function);
195        let mut suffix = String::from("(");
196        for (index, &param) in signature.params.iter().enumerate() {
197            if index > 0 {
198                suffix.push_str(", ");
199            }
200            suffix.push_str(&self.spell(param));
201        }
202        if signature.variadic {
203            if !signature.params.is_empty() {
204                suffix.push_str(", ");
205            }
206            suffix.push_str("...");
207        } else if signature.params.is_empty() && signature.prototyped {
208            // `()` is a function whose parameters are unknown and `(void)` is one that takes
209            // none, and the two are different types in every dialect before C23.
210            suffix.push_str("void");
211        }
212        suffix.push(')');
213        self.declaration(signature.ret, inner.suffixed(&suffix))
214    }
215
216    /// The type on its own, which is what a parameter and the inside of an `_Atomic` are.
217    fn spell(&self, id: TypeId) -> String {
218        self.declaration(id, Declarator::nothing())
219    }
220
221    /// A tag, or what gcc calls one that was never given.
222    fn tag(&self, tag: Option<Symbol>) -> String {
223        match tag {
224            Some(name) => self.names.resolve(name).to_owned(),
225            None => String::from("<anonymous>"),
226        }
227    }
228}
229
230/// The qualifier keywords in the order C writes them, or nothing at all.
231fn quals_text(quals: Qualifiers) -> Option<&'static str> {
232    // Sixteen combinations of three flags, written out rather than assembled, because the
233    // answer is a constant string in every case and this is on the path of every diagnostic.
234    match (
235        quals.has(Qualifiers::CONST),
236        quals.has(Qualifiers::VOLATILE),
237        quals.has(Qualifiers::RESTRICT),
238    ) {
239        (false, false, false) => None,
240        (true, false, false) => Some("const"),
241        (false, true, false) => Some("volatile"),
242        (false, false, true) => Some("restrict"),
243        (true, true, false) => Some("const volatile"),
244        (true, false, true) => Some("const restrict"),
245        (false, true, true) => Some("volatile restrict"),
246        (true, true, true) => Some("const volatile restrict"),
247    }
248}
249
250#[cfg(test)]
251mod tests {
252    use rucc_base::Interner;
253
254    use super::*;
255    use crate::kind::{ArrayLen, FloatKind, FunctionType, IntKind, RecordKind};
256
257    /// A table with a name in it, which is what every spelling below starts from.
258    fn fixture() -> (Types, Interner) {
259        (Types::new(), Interner::new())
260    }
261
262    #[test]
263    fn a_basic_type_is_its_keywords() {
264        let (types, names) = fixture();
265        let int = types.int(IntKind::Int);
266        assert_eq!(spell(&types, &names, int), "int");
267        assert_eq!(spell(&types, &names, types.void()), "void");
268        assert_eq!(spell(&types, &names, types.boolean()), "_Bool");
269        let long_double = types.float(FloatKind::LongDouble);
270        assert_eq!(spell(&types, &names, long_double), "long double");
271    }
272
273    #[test]
274    fn a_qualifier_goes_in_front_of_what_it_qualifies() {
275        let (mut types, names) = fixture();
276        let int = types.int(IntKind::Int);
277        let qualified = types.qualified(int, Qualifiers::CONST.with(Qualifiers::VOLATILE));
278        assert_eq!(spell(&types, &names, qualified), "const volatile int");
279    }
280
281    #[test]
282    fn a_pointers_own_qualifier_goes_after_the_star() {
283        let (mut types, names) = fixture();
284        let char_type = types.int(IntKind::Char);
285        let constant = types.qualified(char_type, Qualifiers::CONST);
286        let pointer = types.pointer(constant);
287        let constant_pointer = types.qualified(pointer, Qualifiers::CONST);
288        assert_eq!(spell(&types, &names, constant_pointer), "const char *const");
289    }
290
291    #[test]
292    fn a_qualified_pointer_with_a_name_keeps_them_apart() {
293        let (mut types, mut names) = fixture();
294        let int = types.int(IntKind::Int);
295        let pointer = types.pointer(int);
296        let restricted = types.qualified(pointer, Qualifiers::RESTRICT);
297        let p = names.intern("p");
298        assert_eq!(declare(&types, &names, restricted, p), "int *restrict p");
299    }
300
301    #[test]
302    fn a_declarator_is_written_around_the_name() {
303        let (mut types, mut names) = fixture();
304        let int = types.int(IntKind::Int);
305        let char_type = types.int(IntKind::Char);
306        let signature =
307            FunctionType { ret: int, params: vec![char_type], variadic: false, prototyped: true };
308        let function = types.function(signature);
309        let pointer = types.pointer(function);
310        let array = types.array(pointer, ArrayLen::Fixed(3));
311        let f = names.intern("f");
312        assert_eq!(declare(&types, &names, array, f), "int (*f[3])(char)");
313    }
314
315    #[test]
316    fn an_abstract_declarator_keeps_the_parentheses_the_name_would_have_needed() {
317        let (mut types, names) = fixture();
318        let int = types.int(IntKind::Int);
319        let array = types.array(int, ArrayLen::Fixed(3));
320        let pointer = types.pointer(array);
321        assert_eq!(spell(&types, &names, pointer), "int (*)[3]");
322    }
323
324    /// Measured against gcc 16, which writes all five of these in a `conflicting types` message.
325    #[test]
326    fn a_suffix_with_nothing_in_front_of_it_goes_against_the_type() {
327        let (mut types, names) = fixture();
328        let int = types.int(IntKind::Int);
329        let array = types.array(int, ArrayLen::Fixed(4));
330        let nested = types.array(array, ArrayLen::Fixed(2));
331        let takes_an_int =
332            FunctionType { ret: int, params: vec![int], variadic: false, prototyped: true };
333        let function = types.function(takes_an_int.clone());
334        let to_int = types.pointer(int);
335        let gives_a_pointer = types.function(FunctionType { ret: to_int, ..takes_an_int });
336        let to_array = types.pointer(array);
337
338        assert_eq!(spell(&types, &names, array), "int[4]");
339        assert_eq!(spell(&types, &names, nested), "int[2][4]");
340        assert_eq!(spell(&types, &names, function), "int(int)");
341        assert_eq!(spell(&types, &names, gives_a_pointer), "int *(int)");
342        // The `*` is something to separate, so the space comes back.
343        assert_eq!(spell(&types, &names, to_array), "int (*)[4]");
344    }
345
346    #[test]
347    fn an_array_of_arrays_reads_left_to_right() {
348        let (mut types, mut names) = fixture();
349        let int = types.int(IntKind::Int);
350        let inner = types.array(int, ArrayLen::Fixed(3));
351        let outer = types.array(inner, ArrayLen::Fixed(2));
352        let a = names.intern("a");
353        assert_eq!(declare(&types, &names, outer, a), "int a[2][3]");
354    }
355
356    #[test]
357    fn an_array_without_a_size_says_so_and_a_variable_one_says_only_that_it_has_one() {
358        let (mut types, names) = fixture();
359        let int = types.int(IntKind::Int);
360        let unknown = types.array(int, ArrayLen::Unknown);
361        let variable = types.array(int, ArrayLen::Variable(crate::kind::VlaId(0)));
362        assert_eq!(spell(&types, &names, unknown), "int[]");
363        assert_eq!(spell(&types, &names, variable), "int[*]");
364    }
365
366    #[test]
367    fn a_prototype_with_no_parameters_is_not_a_function_without_one() {
368        let (mut types, names) = fixture();
369        let int = types.int(IntKind::Int);
370        let prototyped =
371            FunctionType { ret: int, params: Vec::new(), variadic: false, prototyped: true };
372        let old = FunctionType { ret: int, params: Vec::new(), variadic: false, prototyped: false };
373        let prototyped = types.function(prototyped);
374        let old = types.function(old);
375        let prototyped = types.pointer(prototyped);
376        let old = types.pointer(old);
377        assert_eq!(spell(&types, &names, prototyped), "int (*)(void)");
378        assert_eq!(spell(&types, &names, old), "int (*)()");
379    }
380
381    #[test]
382    fn a_variadic_function_ends_in_the_ellipsis() {
383        let (mut types, names) = fixture();
384        let int = types.int(IntKind::Int);
385        let char_type = types.int(IntKind::Char);
386        let signature =
387            FunctionType { ret: int, params: vec![char_type], variadic: true, prototyped: true };
388        let function = types.function(signature);
389        let pointer = types.pointer(function);
390        assert_eq!(spell(&types, &names, pointer), "int (*)(char, ...)");
391    }
392
393    #[test]
394    fn a_typedef_is_spelled_as_itself_and_its_canonical_form_as_what_it_stands_for() {
395        let (mut types, mut names) = fixture();
396        let ulong = types.int(IntKind::ULong);
397        let name = names.intern("size_t");
398        let size_t = types.typedef(name, ulong);
399        let pointer = types.pointer(size_t);
400        assert_eq!(spell(&types, &names, pointer), "size_t *");
401        let canonical = types.canonical(pointer);
402        assert_eq!(spell(&types, &names, canonical), "unsigned long *");
403    }
404
405    #[test]
406    fn a_tag_that_was_never_written_is_named_the_way_gcc_names_it() {
407        let (mut types, mut names) = fixture();
408        let tag = names.intern("S");
409        let named = types.declare_record(RecordKind::Struct, Some(tag));
410        let unnamed = types.declare_record(RecordKind::Union, None);
411        let named = types.record(named);
412        let unnamed = types.record(unnamed);
413        assert_eq!(spell(&types, &names, named), "struct S");
414        assert_eq!(spell(&types, &names, unnamed), "union <anonymous>");
415    }
416
417    #[test]
418    fn an_atomic_type_is_written_as_the_type_it_is() {
419        let (mut types, names) = fixture();
420        let int = types.int(IntKind::Int);
421        let atomic = types.atomic(int);
422        let pointer = types.pointer(atomic);
423        assert_eq!(spell(&types, &names, atomic), "_Atomic(int)");
424        assert_eq!(spell(&types, &names, pointer), "_Atomic(int) *");
425    }
426
427    #[test]
428    fn a_vector_is_written_the_way_gcc_writes_one() {
429        let (mut types, names) = fixture();
430        let int = types.int(IntKind::Int);
431        let vector = types.vector(int, 4);
432        assert_eq!(spell(&types, &names, vector), "__vector(4) int");
433    }
434}