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            // The half's own spelling after the keyword, which is `_Complex double` and is also
113            // `_Complex unsigned int`. A half is always a type with no declarator in it, so
114            // there is nothing to write around the name and the whole of it goes in front.
115            TypeKind::Complex(part) => {
116                format!("_Complex {}", self.declaration(part, Declarator::nothing()))
117            }
118            TypeKind::BitInt { signed, width } => {
119                let sign = if signed { "" } else { "unsigned " };
120                format!("{sign}_BitInt({width})")
121            }
122            // `_Atomic(T)` and not `_Atomic T`, which is what gcc writes. The two are the same
123            // type and only one of them can be written in front of a pointer without changing
124            // what it means, and this crate holds `_Atomic` as a type rather than a qualifier
125            // for that reason.
126            TypeKind::Atomic(inner) => format!("_Atomic({})", self.spell(inner)),
127            // gcc 13.3 writes a vector this way and so does its `{aka}` form, so a program
128            // that has a name for the type sees the name and everything else sees this.
129            TypeKind::Vector { elem, len } => format!("__vector({len}) {}", self.spell(elem)),
130            TypeKind::Record(record) => {
131                let info = self.types.record_info(record);
132                format!("{} {}", info.kind.as_str(), self.tag(info.tag))
133            }
134            TypeKind::Enum(enumeration) => {
135                let info = self.types.enum_info(enumeration);
136                format!("enum {}", self.tag(info.tag))
137            }
138            TypeKind::Typedef { name, .. } => self.names.resolve(name).to_owned(),
139        };
140
141        let mut out = String::new();
142        if let Some(quals) = quals_text(ty.quals) {
143            out.push_str(quals);
144            out.push(' ');
145        }
146        out.push_str(&base);
147        if !inner.text.is_empty() {
148            if !inner.glued {
149                out.push(' ');
150            }
151            out.push_str(&inner.text);
152        }
153        out
154    }
155
156    /// A pointer, whose qualifiers are written after the `*` because they are the pointer's own
157    /// and not the pointee's.
158    fn pointer(&self, ty: Type, pointee: TypeId, inner: Declarator) -> String {
159        let mut declarator = String::from("*");
160        if let Some(quals) = quals_text(ty.quals) {
161            declarator.push_str(quals);
162            if !inner.text.is_empty() {
163                declarator.push(' ');
164            }
165        }
166        declarator.push_str(&inner.text);
167        // An array or a function binds tighter than the `*`, so without these the type would
168        // read as an array of pointers or a function returning one. The sugar of a typedef
169        // stops the recursion before this can matter, which is why `A *` needs nothing when
170        // `A` is an array.
171        if matches!(self.types.kind(pointee), TypeKind::Array { .. } | TypeKind::Function(_)) {
172            declarator = format!("({declarator})");
173        }
174        self.declaration(pointee, Declarator::of(declarator))
175    }
176
177    /// An array, whose qualifiers have a spelling only inside the brackets.
178    fn array(&self, ty: Type, elem: TypeId, len: ArrayLen, inner: Declarator) -> String {
179        let mut suffix = String::from("[");
180        if let Some(quals) = quals_text(ty.quals) {
181            suffix.push_str(quals);
182            if !matches!(len, ArrayLen::Unknown) {
183                suffix.push(' ');
184            }
185        }
186        match len {
187            ArrayLen::Fixed(count) => suffix.push_str(&count.to_string()),
188            ArrayLen::Unknown => {}
189            // A variable length array's size is an expression the type does not hold, so this
190            // says that there is one rather than inventing a name for it.
191            ArrayLen::Star | ArrayLen::Variable(_) => suffix.push('*'),
192        }
193        suffix.push(']');
194        self.declaration(elem, inner.suffixed(&suffix))
195    }
196
197    /// A function, whose parameters are type names in their own right.
198    fn function(&self, function: FunctionId, inner: Declarator) -> String {
199        let signature = self.types.signature(function);
200        let mut suffix = String::from("(");
201        for (index, &param) in signature.params.iter().enumerate() {
202            if index > 0 {
203                suffix.push_str(", ");
204            }
205            suffix.push_str(&self.spell(param));
206        }
207        if signature.variadic {
208            if !signature.params.is_empty() {
209                suffix.push_str(", ");
210            }
211            suffix.push_str("...");
212        } else if signature.params.is_empty() && signature.prototyped {
213            // `()` is a function whose parameters are unknown and `(void)` is one that takes
214            // none, and the two are different types in every dialect before C23.
215            suffix.push_str("void");
216        }
217        suffix.push(')');
218        self.declaration(signature.ret, inner.suffixed(&suffix))
219    }
220
221    /// The type on its own, which is what a parameter and the inside of an `_Atomic` are.
222    fn spell(&self, id: TypeId) -> String {
223        self.declaration(id, Declarator::nothing())
224    }
225
226    /// A tag, or what gcc calls one that was never given.
227    fn tag(&self, tag: Option<Symbol>) -> String {
228        match tag {
229            Some(name) => self.names.resolve(name).to_owned(),
230            None => String::from("<anonymous>"),
231        }
232    }
233}
234
235/// The qualifier keywords in the order C writes them, or nothing at all.
236fn quals_text(quals: Qualifiers) -> Option<&'static str> {
237    // Sixteen combinations of three flags, written out rather than assembled, because the
238    // answer is a constant string in every case and this is on the path of every diagnostic.
239    match (
240        quals.has(Qualifiers::CONST),
241        quals.has(Qualifiers::VOLATILE),
242        quals.has(Qualifiers::RESTRICT),
243    ) {
244        (false, false, false) => None,
245        (true, false, false) => Some("const"),
246        (false, true, false) => Some("volatile"),
247        (false, false, true) => Some("restrict"),
248        (true, true, false) => Some("const volatile"),
249        (true, false, true) => Some("const restrict"),
250        (false, true, true) => Some("volatile restrict"),
251        (true, true, true) => Some("const volatile restrict"),
252    }
253}
254
255#[cfg(test)]
256mod tests {
257    use rucc_base::Interner;
258
259    use super::*;
260    use crate::kind::{ArrayLen, FloatKind, FunctionType, IntKind, RecordKind};
261
262    /// A table with a name in it, which is what every spelling below starts from.
263    fn fixture() -> (Types, Interner) {
264        (Types::new(), Interner::new())
265    }
266
267    #[test]
268    fn a_basic_type_is_its_keywords() {
269        let (types, names) = fixture();
270        let int = types.int(IntKind::Int);
271        assert_eq!(spell(&types, &names, int), "int");
272        assert_eq!(spell(&types, &names, types.void()), "void");
273        assert_eq!(spell(&types, &names, types.boolean()), "_Bool");
274        let long_double = types.float(FloatKind::LongDouble);
275        assert_eq!(spell(&types, &names, long_double), "long double");
276    }
277
278    #[test]
279    fn a_qualifier_goes_in_front_of_what_it_qualifies() {
280        let (mut types, names) = fixture();
281        let int = types.int(IntKind::Int);
282        let qualified = types.qualified(int, Qualifiers::CONST.with(Qualifiers::VOLATILE));
283        assert_eq!(spell(&types, &names, qualified), "const volatile int");
284    }
285
286    #[test]
287    fn a_pointers_own_qualifier_goes_after_the_star() {
288        let (mut types, names) = fixture();
289        let char_type = types.int(IntKind::Char);
290        let constant = types.qualified(char_type, Qualifiers::CONST);
291        let pointer = types.pointer(constant);
292        let constant_pointer = types.qualified(pointer, Qualifiers::CONST);
293        assert_eq!(spell(&types, &names, constant_pointer), "const char *const");
294    }
295
296    #[test]
297    fn a_qualified_pointer_with_a_name_keeps_them_apart() {
298        let (mut types, mut names) = fixture();
299        let int = types.int(IntKind::Int);
300        let pointer = types.pointer(int);
301        let restricted = types.qualified(pointer, Qualifiers::RESTRICT);
302        let p = names.intern("p");
303        assert_eq!(declare(&types, &names, restricted, p), "int *restrict p");
304    }
305
306    #[test]
307    fn a_declarator_is_written_around_the_name() {
308        let (mut types, mut names) = fixture();
309        let int = types.int(IntKind::Int);
310        let char_type = types.int(IntKind::Char);
311        let signature =
312            FunctionType { ret: int, params: vec![char_type], variadic: false, prototyped: true };
313        let function = types.function(signature);
314        let pointer = types.pointer(function);
315        let array = types.array(pointer, ArrayLen::Fixed(3));
316        let f = names.intern("f");
317        assert_eq!(declare(&types, &names, array, f), "int (*f[3])(char)");
318    }
319
320    #[test]
321    fn an_abstract_declarator_keeps_the_parentheses_the_name_would_have_needed() {
322        let (mut types, names) = fixture();
323        let int = types.int(IntKind::Int);
324        let array = types.array(int, ArrayLen::Fixed(3));
325        let pointer = types.pointer(array);
326        assert_eq!(spell(&types, &names, pointer), "int (*)[3]");
327    }
328
329    /// Measured against gcc 16, which writes all five of these in a `conflicting types` message.
330    #[test]
331    fn a_suffix_with_nothing_in_front_of_it_goes_against_the_type() {
332        let (mut types, names) = fixture();
333        let int = types.int(IntKind::Int);
334        let array = types.array(int, ArrayLen::Fixed(4));
335        let nested = types.array(array, ArrayLen::Fixed(2));
336        let takes_an_int =
337            FunctionType { ret: int, params: vec![int], variadic: false, prototyped: true };
338        let function = types.function(takes_an_int.clone());
339        let to_int = types.pointer(int);
340        let gives_a_pointer = types.function(FunctionType { ret: to_int, ..takes_an_int });
341        let to_array = types.pointer(array);
342
343        assert_eq!(spell(&types, &names, array), "int[4]");
344        assert_eq!(spell(&types, &names, nested), "int[2][4]");
345        assert_eq!(spell(&types, &names, function), "int(int)");
346        assert_eq!(spell(&types, &names, gives_a_pointer), "int *(int)");
347        // The `*` is something to separate, so the space comes back.
348        assert_eq!(spell(&types, &names, to_array), "int (*)[4]");
349    }
350
351    #[test]
352    fn an_array_of_arrays_reads_left_to_right() {
353        let (mut types, mut names) = fixture();
354        let int = types.int(IntKind::Int);
355        let inner = types.array(int, ArrayLen::Fixed(3));
356        let outer = types.array(inner, ArrayLen::Fixed(2));
357        let a = names.intern("a");
358        assert_eq!(declare(&types, &names, outer, a), "int a[2][3]");
359    }
360
361    #[test]
362    fn an_array_without_a_size_says_so_and_a_variable_one_says_only_that_it_has_one() {
363        let (mut types, names) = fixture();
364        let int = types.int(IntKind::Int);
365        let unknown = types.array(int, ArrayLen::Unknown);
366        let variable = types.array(int, ArrayLen::Variable(crate::kind::VlaId(0)));
367        assert_eq!(spell(&types, &names, unknown), "int[]");
368        assert_eq!(spell(&types, &names, variable), "int[*]");
369    }
370
371    #[test]
372    fn a_prototype_with_no_parameters_is_not_a_function_without_one() {
373        let (mut types, names) = fixture();
374        let int = types.int(IntKind::Int);
375        let prototyped =
376            FunctionType { ret: int, params: Vec::new(), variadic: false, prototyped: true };
377        let old = FunctionType { ret: int, params: Vec::new(), variadic: false, prototyped: false };
378        let prototyped = types.function(prototyped);
379        let old = types.function(old);
380        let prototyped = types.pointer(prototyped);
381        let old = types.pointer(old);
382        assert_eq!(spell(&types, &names, prototyped), "int (*)(void)");
383        assert_eq!(spell(&types, &names, old), "int (*)()");
384    }
385
386    #[test]
387    fn a_variadic_function_ends_in_the_ellipsis() {
388        let (mut types, names) = fixture();
389        let int = types.int(IntKind::Int);
390        let char_type = types.int(IntKind::Char);
391        let signature =
392            FunctionType { ret: int, params: vec![char_type], variadic: true, prototyped: true };
393        let function = types.function(signature);
394        let pointer = types.pointer(function);
395        assert_eq!(spell(&types, &names, pointer), "int (*)(char, ...)");
396    }
397
398    #[test]
399    fn a_typedef_is_spelled_as_itself_and_its_canonical_form_as_what_it_stands_for() {
400        let (mut types, mut names) = fixture();
401        let ulong = types.int(IntKind::ULong);
402        let name = names.intern("size_t");
403        let size_t = types.typedef(name, ulong);
404        let pointer = types.pointer(size_t);
405        assert_eq!(spell(&types, &names, pointer), "size_t *");
406        let canonical = types.canonical(pointer);
407        assert_eq!(spell(&types, &names, canonical), "unsigned long *");
408    }
409
410    #[test]
411    fn a_tag_that_was_never_written_is_named_the_way_gcc_names_it() {
412        let (mut types, mut names) = fixture();
413        let tag = names.intern("S");
414        let named = types.declare_record(RecordKind::Struct, Some(tag));
415        let unnamed = types.declare_record(RecordKind::Union, None);
416        let named = types.record(named);
417        let unnamed = types.record(unnamed);
418        assert_eq!(spell(&types, &names, named), "struct S");
419        assert_eq!(spell(&types, &names, unnamed), "union <anonymous>");
420    }
421
422    #[test]
423    fn an_atomic_type_is_written_as_the_type_it_is() {
424        let (mut types, names) = fixture();
425        let int = types.int(IntKind::Int);
426        let atomic = types.atomic(int);
427        let pointer = types.pointer(atomic);
428        assert_eq!(spell(&types, &names, atomic), "_Atomic(int)");
429        assert_eq!(spell(&types, &names, pointer), "_Atomic(int) *");
430    }
431
432    #[test]
433    fn a_vector_is_written_the_way_gcc_writes_one() {
434        let (mut types, names) = fixture();
435        let int = types.int(IntKind::Int);
436        let vector = types.vector(int, 4);
437        assert_eq!(spell(&types, &names, vector), "__vector(4) int");
438    }
439}