Skip to main content

rucc_ast/
print.rs

1//! The printer, which turns a tree back into C.
2//!
3//! Design: `spec/06-lexer-and-parser.md` section 6.2.
4//!
5//! What comes out is not the source that went in. Comments are gone, the layout is the
6//! printer's own, and a constant is written in the spelling the printer has rather than the one
7//! the author had. What is guaranteed is that parsing the output gives the same tree back, and
8//! so that printing it a second time gives the same text. That is the property `--emit=ast` is
9//! worth having: a printer that agrees with the parser is a check on both of them, and one that
10//! merely looks right is a check on nothing.
11//!
12//! # What that costs
13//!
14//! Three things are written in a way that reads oddly and round-trips exactly.
15//!
16//! A floating constant comes out in hexadecimal, so `1.0` prints as `0x1p+0`. A decimal
17//! constant that reads back unchanged needs a shortest-round-trip algorithm, and printing one
18//! without such an algorithm quietly changes the program. Hexadecimal is exact by construction.
19//!
20//! A keyword comes out in the spelling that is a keyword in every dialect, so `_Bool` rather
21//! than `bool` and `__asm__` rather than `asm`. The tree does not record which dialect it was
22//! parsed in, and the ugly spelling is the one that survives all of them.
23//!
24//! Parentheses come out where the grammar needs them and not where the author wrote them,
25//! because the tree does not record them. `(a) + (b)` prints as `a + b`, and `a + b * c` keeps
26//! the parentheses it needs and loses the ones it does not.
27//!
28//! # Using it
29//!
30//! ```
31//! use rucc_ast::{Ast, BinaryOp, Expr, Printer};
32//! use rucc_base::Interner;
33//! use rucc_diag::Span;
34//!
35//! let mut interner = Interner::new();
36//! let a = interner.intern("a");
37//! let mut ast = Ast::new();
38//! let left = ast.expr(Expr::Name(a), Span::DUMMY);
39//! let right = ast.expr(Expr::Bool(true), Span::DUMMY);
40//! let both = ast.expr(Expr::Binary { op: BinaryOp::Add, lhs: left, rhs: right }, Span::DUMMY);
41//!
42//! let mut printer = Printer::new(&ast, &interner);
43//! printer.expr(both);
44//! assert_eq!(printer.finish(), "a + true");
45//! ```
46
47use rucc_base::{Interner, Symbol};
48
49use crate::asm::{AsmId, AsmQuals};
50use crate::ast::{
51    AsmOperandList, Ast, AttrList, DesignatorList, EnumeratorList, ExprList, GenericList,
52    MemberList, ParamList, StrId, StrList, SymbolList,
53};
54use crate::attr::{AttrArg, AttrSyntax};
55use crate::decl::{
56    ArraySize, Decl, DeclId, DeclaratorId, Derived, Field, Member, Param, ParamKind, TypeNameId,
57};
58use crate::expr::{BinaryOp, Expr, ExprId, UnaryOp};
59use crate::init::{Designator, Init, InitId};
60use crate::spec::TypeofArg;
61use crate::spec::{AlignSpec, Builtin, BuiltinSet, DeclSpecsId, FuncSpecs, Quals, TypeSpec};
62use crate::stmt::{ForInit, Stmt, StmtId};
63
64/// The comma operator, which binds least of all.
65const COMMA: u8 = 1;
66/// Assignment, and the compound assignments.
67const ASSIGN: u8 = 2;
68/// The conditional operator, which is also what a constant expression is.
69const COND: u8 = 3;
70/// `||`.
71const LOG_OR: u8 = 4;
72/// `&&`.
73const LOG_AND: u8 = 5;
74/// `|`.
75const BIT_OR: u8 = 6;
76/// `^`.
77const BIT_XOR: u8 = 7;
78/// `&`.
79const BIT_AND: u8 = 8;
80/// `==` and `!=`.
81const EQUALITY: u8 = 9;
82/// `<`, `>`, `<=` and `>=`.
83const RELATIONAL: u8 = 10;
84/// `<<` and `>>`.
85const SHIFT: u8 = 11;
86/// `+` and `-`.
87const ADDITIVE: u8 = 12;
88/// `*`, `/` and `%`.
89const MULTIPLICATIVE: u8 = 13;
90/// A cast.
91const CAST: u8 = 14;
92/// The prefix operators.
93const UNARY: u8 = 15;
94/// The postfix operators, which is also where a compound literal sits.
95const POSTFIX: u8 = 16;
96/// A name, a constant, and anything that is bracketed all the way round.
97const PRIMARY: u8 = 17;
98
99/// How tightly a binary operator binds.
100const fn binding(op: BinaryOp) -> u8 {
101    match op {
102        BinaryOp::Mul | BinaryOp::Div | BinaryOp::Rem => MULTIPLICATIVE,
103        BinaryOp::Add | BinaryOp::Sub => ADDITIVE,
104        BinaryOp::Shl | BinaryOp::Shr => SHIFT,
105        BinaryOp::Lt | BinaryOp::Gt | BinaryOp::Le | BinaryOp::Ge => RELATIONAL,
106        BinaryOp::Eq | BinaryOp::Ne => EQUALITY,
107        BinaryOp::BitAnd => BIT_AND,
108        BinaryOp::BitXor => BIT_XOR,
109        BinaryOp::BitOr => BIT_OR,
110        BinaryOp::LogAnd => LOG_AND,
111        BinaryOp::LogOr => LOG_OR,
112    }
113}
114
115/// The type keywords, in the order they are written back out.
116///
117/// `long` is not here because it is the one that may be written twice, so it is counted rather
118/// than held in the set and is put back where it belongs by hand.
119const BUILTIN_SPELLINGS: &[(BuiltinSet, &str)] = &[
120    (BuiltinSet::SIGNED, "signed"),
121    (BuiltinSet::UNSIGNED, "unsigned"),
122    (BuiltinSet::SHORT, "short"),
123    (BuiltinSet::VOID, "void"),
124    (BuiltinSet::BOOL, "_Bool"),
125    (BuiltinSet::CHAR, "char"),
126    (BuiltinSet::INT, "int"),
127    (BuiltinSet::INT128, "__int128"),
128    (BuiltinSet::FLOAT, "float"),
129    (BuiltinSet::DOUBLE, "double"),
130    (BuiltinSet::COMPLEX, "_Complex"),
131    (BuiltinSet::IMAGINARY, "_Imaginary"),
132    (BuiltinSet::FLOAT16, "_Float16"),
133    (BuiltinSet::FLOAT32, "_Float32"),
134    (BuiltinSet::FLOAT64, "_Float64"),
135    (BuiltinSet::FLOAT128, "_Float128"),
136    (BuiltinSet::FLOAT32X, "_Float32x"),
137    (BuiltinSet::FLOAT64X, "_Float64x"),
138    (BuiltinSet::FLOAT128X, "_Float128x"),
139    (BuiltinSet::FLOAT80, "__float80"),
140    (BuiltinSet::DECIMAL32, "_Decimal32"),
141    (BuiltinSet::DECIMAL64, "_Decimal64"),
142    (BuiltinSet::DECIMAL128, "_Decimal128"),
143];
144
145/// Whether writing `next` straight after `last` would make one token out of two.
146///
147/// The check is on the two characters that meet, which is enough: every C token that could be
148/// formed by accident starts with a pair that is listed here or is two identifier characters
149/// running together. Getting this wrong is how a printer turns `a / *p` into a comment.
150fn pastes(last: char, next: char) -> bool {
151    let word = |c: char| c.is_ascii_alphanumeric() || c == '_' || c == '$';
152    if word(last) && word(next) {
153        return true;
154    }
155    // A pp-number takes a dot on either side of it, which is what makes `case 1 ... 2` need its
156    // spaces and `1 .x` need one too.
157    if (last == '.' && next.is_ascii_digit()) || (last.is_ascii_digit() && next == '.') {
158        return true;
159    }
160    matches!(
161        (last, next),
162        ('+', '+' | '=')
163            | ('-', '-' | '=' | '>')
164            | ('*', '=')
165            | ('/', '=' | '/' | '*')
166            | ('%', '=' | '>' | ':')
167            | ('<', '<' | '=' | ':' | '%')
168            | ('>', '>' | '=')
169            | ('=', '=')
170            | ('!', '=')
171            | ('&', '&' | '=')
172            | ('|', '|' | '=')
173            | ('^', '=')
174            | ('.', '.')
175            | (':', '>' | ':')
176            | ('#', '#')
177    )
178}
179
180/// Joins two pieces of a declarator, keeping them two tokens if they would otherwise be one.
181fn join(mut left: String, right: &str) -> String {
182    if let (Some(last), Some(next)) = (left.chars().next_back(), right.chars().next()) {
183        if pastes(last, next) {
184            left.push(' ');
185        }
186    }
187    left.push_str(right);
188    left
189}
190
191/// The whole translation unit, as text.
192#[must_use]
193pub fn print(ast: &Ast, names: &Interner) -> String {
194    let mut printer = Printer::new(ast, names);
195    printer.unit();
196    printer.finish()
197}
198
199/// A tree being written out as C.
200#[derive(Debug)]
201pub struct Printer<'a> {
202    ast: &'a Ast,
203    names: &'a Interner,
204    out: String,
205    depth: usize,
206}
207
208impl<'a> Printer<'a> {
209    /// A printer over one tree, whose names are in `names`.
210    #[must_use]
211    pub fn new(ast: &'a Ast, names: &'a Interner) -> Printer<'a> {
212        Printer { ast, names, out: String::new(), depth: 0 }
213    }
214
215    /// The text written so far.
216    #[must_use]
217    pub fn finish(self) -> String {
218        self.out
219    }
220
221    /// Every declaration of the translation unit, one after another.
222    pub fn unit(&mut self) {
223        let ast = self.ast;
224        for (index, &decl) in ast.top_level().iter().enumerate() {
225            if index > 0 {
226                self.newline();
227            }
228            self.decl(decl);
229        }
230        if !self.out.is_empty() {
231            self.out.push('\n');
232        }
233    }
234
235    /// One declaration, semicolon included.
236    pub fn decl(&mut self, id: DeclId) {
237        let ast = self.ast;
238        match ast[id] {
239            // A poisoned declaration is written as the empty one, which is what it parses back
240            // as and which keeps a broken tree printing to a fixed point like any other.
241            Decl::Error => self.token(";"),
242            Decl::Var { specs, declarators } => {
243                self.decl_specs(specs);
244                for (index, item) in ast[declarators].iter().enumerate() {
245                    if index > 0 {
246                        self.token(",");
247                    }
248                    self.space();
249                    let text = self.declarator_text(item.declarator);
250                    self.token(&text);
251                    if let Some(label) = item.asm_label {
252                        self.space();
253                        self.token("__asm__");
254                        self.token("(");
255                        self.string(label);
256                        self.token(")");
257                    }
258                    self.attributes(item.attrs);
259                    if let Some(init) = item.init {
260                        self.space();
261                        self.token("=");
262                        self.space();
263                        self.init(init);
264                    }
265                }
266                self.token(";");
267            }
268            Decl::Function { specs, declarator, params, body } => {
269                self.decl_specs(specs);
270                self.space();
271                let text = self.declarator_text(declarator);
272                self.token(&text);
273                self.depth += 1;
274                for &param in &ast[params] {
275                    self.newline();
276                    self.decl(param);
277                }
278                self.depth -= 1;
279                self.newline();
280                self.stmt(body);
281            }
282            Decl::StaticAssert { cond, message } => {
283                self.static_assert(cond, message);
284            }
285            Decl::Asm(asm) => {
286                self.asm(asm);
287                self.token(";");
288            }
289            Decl::Attributes(attrs) => {
290                self.attributes(attrs);
291                self.token(";");
292            }
293        }
294    }
295
296    /// One statement, on the line it was put on.
297    pub fn stmt(&mut self, id: StmtId) {
298        let ast = self.ast;
299        match ast[id] {
300            // Poisoned, and written as the empty statement for the reason a poisoned
301            // declaration is written as the empty one.
302            Stmt::Error | Stmt::Empty => self.token(";"),
303            Stmt::Expr(expr) => {
304                self.expr_at(expr, COMMA);
305                self.token(";");
306            }
307            Stmt::Decl(decl) => self.decl(decl),
308            Stmt::Compound(items) => {
309                self.token("{");
310                self.depth += 1;
311                for &item in &ast[items] {
312                    self.newline();
313                    self.stmt(item);
314                }
315                self.depth -= 1;
316                self.newline();
317                self.token("}");
318            }
319            Stmt::If { cond, then, otherwise } => {
320                self.token("if");
321                self.space();
322                self.token("(");
323                self.expr_at(cond, COMMA);
324                self.token(")");
325                if otherwise.is_some() && self.dangling(then) {
326                    self.braced(then);
327                } else {
328                    self.body(then);
329                }
330                if let Some(otherwise) = otherwise {
331                    self.newline();
332                    self.token("else");
333                    if matches!(ast[otherwise], Stmt::If { .. }) {
334                        self.space();
335                        self.stmt(otherwise);
336                    } else {
337                        self.body(otherwise);
338                    }
339                }
340            }
341            Stmt::Switch { scrutinee, body } => {
342                self.token("switch");
343                self.space();
344                self.token("(");
345                self.expr_at(scrutinee, COMMA);
346                self.token(")");
347                self.body(body);
348            }
349            Stmt::While { cond, body } => {
350                self.token("while");
351                self.space();
352                self.token("(");
353                self.expr_at(cond, COMMA);
354                self.token(")");
355                self.body(body);
356            }
357            Stmt::DoWhile { body, cond } => {
358                self.token("do");
359                self.body(body);
360                self.newline();
361                self.token("while");
362                self.space();
363                self.token("(");
364                self.expr_at(cond, COMMA);
365                self.token(")");
366                self.token(";");
367            }
368            Stmt::For { init, cond, step, body } => {
369                self.token("for");
370                self.space();
371                self.token("(");
372                match init {
373                    ForInit::None => self.token(";"),
374                    ForInit::Expr(expr) => {
375                        self.expr_at(expr, COMMA);
376                        self.token(";");
377                    }
378                    // The declaration writes its own semicolon, since it is a whole declaration
379                    // and not an expression that happens to be in a loop header.
380                    ForInit::Decl(decl) => self.decl(decl),
381                }
382                if let Some(cond) = cond {
383                    self.space();
384                    self.expr_at(cond, COMMA);
385                }
386                self.token(";");
387                if let Some(step) = step {
388                    self.space();
389                    self.expr_at(step, COMMA);
390                }
391                self.token(")");
392                self.body(body);
393            }
394            Stmt::Goto(name) => {
395                self.token("goto");
396                self.space();
397                self.name(name);
398                self.token(";");
399            }
400            Stmt::GotoExpr(expr) => {
401                self.token("goto");
402                self.space();
403                self.token("*");
404                self.expr_at(expr, CAST);
405                self.token(";");
406            }
407            Stmt::Continue => {
408                self.token("continue");
409                self.token(";");
410            }
411            Stmt::Break => {
412                self.token("break");
413                self.token(";");
414            }
415            Stmt::Return(value) => {
416                self.token("return");
417                if let Some(value) = value {
418                    self.space();
419                    self.expr_at(value, COMMA);
420                }
421                self.token(";");
422            }
423            Stmt::Label { name, body, attrs } => {
424                self.attributes(attrs);
425                self.space();
426                self.name(name);
427                self.token(":");
428                self.labelled(body);
429            }
430            Stmt::Case { lo, hi, body } => {
431                self.token("case");
432                self.space();
433                self.expr_at(lo, COND);
434                if let Some(hi) = hi {
435                    self.space();
436                    self.token("...");
437                    self.space();
438                    self.expr_at(hi, COND);
439                }
440                self.token(":");
441                self.labelled(body);
442            }
443            Stmt::Default { body } => {
444                self.token("default");
445                self.token(":");
446                self.labelled(body);
447            }
448            Stmt::LocalLabels(names) => {
449                self.token("__label__");
450                self.name_list(names);
451                self.token(";");
452            }
453            Stmt::Asm(asm) => {
454                self.asm(asm);
455                self.token(";");
456            }
457        }
458    }
459
460    /// One expression, with no parentheses around it that the grammar does not need.
461    pub fn expr(&mut self, id: ExprId) {
462        self.expr_at(id, COMMA);
463    }
464
465    /// One type name, as it would be written in a cast.
466    pub fn type_name(&mut self, id: TypeNameId) {
467        let ast = self.ast;
468        let name = ast[id];
469        self.decl_specs(name.specs);
470        let text = self.declarator_text(name.declarator);
471        if !text.is_empty() {
472            self.space();
473            self.token(&text);
474        }
475    }
476
477    /// The statement a control structure controls, on the same line when it is a block and
478    /// indented on the next line when it is not.
479    fn body(&mut self, id: StmtId) {
480        if matches!(self.ast[id], Stmt::Compound(_)) {
481            self.space();
482            self.stmt(id);
483        } else {
484            self.depth += 1;
485            self.newline();
486            self.stmt(id);
487            self.depth -= 1;
488        }
489    }
490
491    /// A statement in braces it did not have, which is what stops an `else` binding to an `if`
492    /// nested inside the branch before it.
493    fn braced(&mut self, id: StmtId) {
494        self.space();
495        self.token("{");
496        self.depth += 1;
497        self.newline();
498        self.stmt(id);
499        self.depth -= 1;
500        self.newline();
501        self.token("}");
502    }
503
504    /// The statement a label labels, which C23 allows to be missing at the end of a block.
505    fn labelled(&mut self, body: Option<StmtId>) {
506        if let Some(body) = body {
507            self.newline();
508            self.stmt(body);
509        }
510    }
511
512    /// Whether a statement ends in an `if` with no `else`, and so would take one written after
513    /// it.
514    fn dangling(&self, id: StmtId) -> bool {
515        match self.ast[id] {
516            Stmt::If { otherwise: Some(otherwise), .. } => self.dangling(otherwise),
517            Stmt::If { otherwise: None, .. } => true,
518            Stmt::While { body, .. } | Stmt::Switch { body, .. } | Stmt::For { body, .. } => {
519                self.dangling(body)
520            }
521            Stmt::Label { body: Some(body), .. }
522            | Stmt::Case { body: Some(body), .. }
523            | Stmt::Default { body: Some(body) } => self.dangling(body),
524            _ => false,
525        }
526    }
527
528    /// `_Static_assert(cond)` or `_Static_assert(cond, "message")`, semicolon included.
529    fn static_assert(&mut self, cond: ExprId, message: Option<StrId>) {
530        self.token("_Static_assert");
531        self.token("(");
532        self.expr_at(cond, ASSIGN);
533        if let Some(message) = message {
534            self.token(",");
535            self.space();
536            self.string(message);
537        }
538        self.token(")");
539        self.token(";");
540    }
541
542    /// An `asm` statement or a file-scope `asm`, without its semicolon.
543    fn asm(&mut self, id: AsmId) {
544        let ast = self.ast;
545        let asm = ast[id];
546        self.token("__asm__");
547        if asm.quals.has(AsmQuals::VOLATILE) {
548            self.token("volatile");
549        }
550        if asm.quals.has(AsmQuals::INLINE) {
551            self.token("inline");
552        }
553        if asm.quals.has(AsmQuals::GOTO) {
554            self.token("goto");
555        }
556        self.token("(");
557        self.string(asm.template);
558        // A section is only written when something after it has to be, since the colons are
559        // what count the sections and an empty one before a full one cannot be left out.
560        let sections = if !asm.labels.is_empty() {
561            4
562        } else if !asm.clobbers.is_empty() {
563            3
564        } else if !asm.inputs.is_empty() {
565            2
566        } else {
567            usize::from(!asm.outputs.is_empty())
568        };
569        for section in 0..sections {
570            self.space();
571            self.token(":");
572            match section {
573                0 => self.asm_operands(asm.outputs),
574                1 => self.asm_operands(asm.inputs),
575                2 => self.string_list(asm.clobbers),
576                _ => self.name_list(asm.labels),
577            }
578        }
579        self.token(")");
580    }
581
582    /// One section of an `asm` statement's operands.
583    fn asm_operands(&mut self, list: AsmOperandList) {
584        let ast = self.ast;
585        for (index, operand) in ast[list].iter().enumerate() {
586            if index > 0 {
587                self.token(",");
588            }
589            self.space();
590            if let Some(name) = operand.name {
591                self.token("[");
592                self.name(name);
593                self.token("]");
594                self.space();
595            }
596            self.string(operand.constraint);
597            self.space();
598            self.token("(");
599            self.expr_at(operand.value, COMMA);
600            self.token(")");
601        }
602    }
603
604    /// A comma-separated run of string literals.
605    fn string_list(&mut self, list: StrList) {
606        let ast = self.ast;
607        for (index, &item) in ast[list].iter().enumerate() {
608            if index > 0 {
609                self.token(",");
610            }
611            self.space();
612            self.string(item);
613        }
614    }
615
616    /// A comma-separated run of identifiers.
617    fn name_list(&mut self, list: SymbolList) {
618        let ast = self.ast;
619        for (index, &item) in ast[list].iter().enumerate() {
620            if index > 0 {
621                self.token(",");
622            }
623            self.space();
624            self.name(item);
625        }
626    }
627
628    /// Everything a declaration says before its first declarator.
629    fn decl_specs(&mut self, id: DeclSpecsId) {
630        let specs = self.ast[id];
631        self.attributes(specs.attrs);
632        if let Some(storage) = specs.storage {
633            self.token(storage.spelling());
634        }
635        if specs.thread_local {
636            self.token("_Thread_local");
637        }
638        if specs.constexpr {
639            self.token("constexpr");
640        }
641        if specs.func.has(FuncSpecs::INLINE) {
642            self.token("inline");
643        }
644        if specs.func.has(FuncSpecs::NORETURN) {
645            self.token("_Noreturn");
646        }
647        if let Some(align) = specs.align {
648            self.token("_Alignas");
649            self.token("(");
650            match align {
651                AlignSpec::Type(ty) => self.type_name(ty),
652                AlignSpec::Expr(expr) => self.expr_at(expr, ASSIGN),
653            }
654            self.token(")");
655        }
656        self.quals(specs.quals);
657        self.type_spec(specs.ty);
658    }
659
660    /// The type qualifiers that were written, in a fixed order.
661    fn quals(&mut self, quals: Quals) {
662        if quals.has(Quals::CONST) {
663            self.token("const");
664        }
665        if quals.has(Quals::VOLATILE) {
666            self.token("volatile");
667        }
668        if quals.has(Quals::RESTRICT) {
669            self.token("restrict");
670        }
671        if quals.has(Quals::ATOMIC) {
672            self.token("_Atomic");
673        }
674    }
675
676    /// What type a declaration named.
677    fn type_spec(&mut self, ty: TypeSpec) {
678        match ty {
679            TypeSpec::None => {}
680            TypeSpec::Builtin(builtin) => self.builtin(builtin),
681            // The `#pragma pack` is not written back out. It was not written on the declaration
682            // in the first place, it was a line somewhere above it, and there is no attribute
683            // that means the same thing, since `pack` caps an alignment where `aligned` raises
684            // one. Printing the line here would also put a directive in the middle of whatever
685            // the record is nested in, which is not always a place a directive can go.
686            TypeSpec::Record { kind, tag, fields, attrs, pack: _ } => {
687                self.token(kind.spelling());
688                self.attributes(attrs);
689                if let Some(tag) = tag {
690                    self.space();
691                    self.name(tag);
692                }
693                if let Some(fields) = fields {
694                    self.members(fields);
695                }
696            }
697            TypeSpec::Enum { tag, enumerators, underlying, attrs } => {
698                self.token("enum");
699                self.attributes(attrs);
700                if let Some(tag) = tag {
701                    self.space();
702                    self.name(tag);
703                }
704                if let Some(underlying) = underlying {
705                    self.space();
706                    self.token(":");
707                    self.space();
708                    self.type_name(underlying);
709                }
710                if let Some(enumerators) = enumerators {
711                    self.enumerators(enumerators);
712                }
713            }
714            TypeSpec::Typedef(name) => self.name(name),
715            TypeSpec::Typeof { unqual, operand } => {
716                self.token(if unqual { "__typeof_unqual__" } else { "__typeof__" });
717                self.token("(");
718                match operand {
719                    TypeofArg::Expr(expr) => self.expr_at(expr, COMMA),
720                    TypeofArg::Type(ty) => self.type_name(ty),
721                }
722                self.token(")");
723            }
724            TypeSpec::Atomic(ty) => {
725                self.token("_Atomic");
726                self.token("(");
727                self.type_name(ty);
728                self.token(")");
729            }
730            TypeSpec::Auto(which) => self.token(which.spelling()),
731            TypeSpec::VaList => self.token("__builtin_va_list"),
732        }
733    }
734
735    /// The type keywords, in the printer's order rather than the one they were written in.
736    fn builtin(&mut self, builtin: Builtin) {
737        for &(which, spelling) in BUILTIN_SPELLINGS {
738            if builtin.set.has(which) {
739                self.token(spelling);
740            }
741            // `long` goes where it reads, which is after `short` could have been and before
742            // everything it can qualify.
743            if which == BuiltinSet::SHORT {
744                for _ in 0..builtin.longs {
745                    self.token("long");
746                }
747            }
748        }
749        // `_BitInt` is last because its width follows it, so writing it anywhere else would
750        // put a sign between the keyword and the parenthesis it belongs to.
751        if let Some(width) = builtin.width {
752            self.token("_BitInt");
753            self.token("(");
754            self.expr_at(width, COMMA);
755            self.token(")");
756        }
757    }
758
759    /// The `{ ... }` of a struct or a union.
760    fn members(&mut self, list: MemberList) {
761        let ast = self.ast;
762        let members = &ast[list];
763        self.space();
764        self.token("{");
765        self.depth += 1;
766        let mut index = 0;
767        while index < members.len() {
768            self.newline();
769            match members[index] {
770                Member::StaticAssert { cond, message, .. } => {
771                    self.static_assert(cond, message);
772                    index += 1;
773                }
774                Member::Field(first) => {
775                    self.decl_specs(first.specs);
776                    if first.declarator.is_none() && first.bits.is_none() {
777                        // An anonymous struct or union member, or a tag declared among the
778                        // members. Either way it is a declaration on its own.
779                        index += 1;
780                    } else {
781                        // The members declared together share their specifiers, and they are
782                        // written back together so that an anonymous type in them stays one
783                        // type rather than becoming one per member.
784                        let mut written = 0;
785                        while let Some(&Member::Field(field)) = members.get(index) {
786                            if field.specs != first.specs
787                                || (field.declarator.is_none() && field.bits.is_none())
788                            {
789                                break;
790                            }
791                            if written > 0 {
792                                self.token(",");
793                            }
794                            self.space();
795                            self.field(field);
796                            written += 1;
797                            index += 1;
798                        }
799                    }
800                    self.token(";");
801                }
802            }
803        }
804        self.depth -= 1;
805        self.newline();
806        self.token("}");
807    }
808
809    /// One member, without the specifiers it shares with the members beside it.
810    fn field(&mut self, field: Field) {
811        if let Some(declarator) = field.declarator {
812            let text = self.declarator_text(declarator);
813            self.token(&text);
814        }
815        if let Some(bits) = field.bits {
816            self.space();
817            self.token(":");
818            self.space();
819            self.expr_at(bits, COND);
820        }
821        self.attributes(field.attrs);
822    }
823
824    /// The `{ ... }` of an enumeration, one enumerator to a line.
825    fn enumerators(&mut self, list: EnumeratorList) {
826        let ast = self.ast;
827        self.space();
828        self.token("{");
829        self.depth += 1;
830        for (index, enumerator) in ast[list].iter().enumerate() {
831            if index > 0 {
832                self.token(",");
833            }
834            self.newline();
835            self.name(enumerator.name);
836            self.attributes(enumerator.attrs);
837            if let Some(value) = enumerator.value {
838                self.space();
839                self.token("=");
840                self.space();
841                self.expr_at(value, COND);
842            }
843        }
844        self.depth -= 1;
845        self.newline();
846        self.token("}");
847    }
848
849    /// A declarator, built from the name outward and given back as its own text.
850    ///
851    /// Outward is the direction the type reads in and the wrong direction to write in, so the
852    /// pieces are assembled here rather than streamed: a pointer step wraps what came before it
853    /// on the left, and an array or function step that follows one needs the parentheses that
854    /// tell `int (*p)[4]` from `int *p[4]`.
855    fn declarator_text(&mut self, id: DeclaratorId) -> String {
856        let ast = self.ast;
857        let declarator = ast[id];
858        let mut text = match declarator.name {
859            Some(name) => self.names.resolve(name).to_string(),
860            None => String::new(),
861        };
862        let mut pointered = false;
863        for step in &ast[declarator.derived] {
864            match *step {
865                Derived::Pointer { quals, attrs } => {
866                    let prefix = self.capture(|p| {
867                        p.token("*");
868                        p.quals(quals);
869                        p.attributes(attrs);
870                    });
871                    text = join(prefix, &text);
872                    pointered = true;
873                }
874                Derived::Array { size, quals, has_static } => {
875                    if pointered {
876                        text = format!("({text})");
877                    }
878                    let suffix = self.capture(|p| {
879                        p.token("[");
880                        if has_static {
881                            p.token("static");
882                        }
883                        p.quals(quals);
884                        match size {
885                            ArraySize::Unspecified => {}
886                            ArraySize::Star => p.token("*"),
887                            ArraySize::Expr(expr) => p.expr_at(expr, ASSIGN),
888                        }
889                        p.token("]");
890                    });
891                    text = join(text, &suffix);
892                    pointered = false;
893                }
894                Derived::Function { params, variadic, kind } => {
895                    if pointered {
896                        text = format!("({text})");
897                    }
898                    let suffix = self.capture(|p| p.parameters(params, variadic, kind));
899                    text = join(text, &suffix);
900                    pointered = false;
901                }
902            }
903        }
904        text
905    }
906
907    /// A function declarator's parameter list, parentheses included.
908    fn parameters(&mut self, params: ParamList, variadic: bool, kind: ParamKind) {
909        let ast = self.ast;
910        self.token("(");
911        match kind {
912            ParamKind::Void => self.token("void"),
913            ParamKind::Empty => {}
914            ParamKind::Identifiers => {
915                for (index, param) in ast[params].iter().enumerate() {
916                    if index > 0 {
917                        self.token(",");
918                        self.space();
919                    }
920                    if let Some(name) = ast[param.declarator].name {
921                        self.name(name);
922                    }
923                }
924            }
925            ParamKind::Prototype => {
926                for (index, param) in ast[params].iter().enumerate() {
927                    if index > 0 {
928                        self.token(",");
929                        self.space();
930                    }
931                    self.parameter(*param);
932                }
933                if variadic {
934                    if !params.is_empty() {
935                        self.token(",");
936                        self.space();
937                    }
938                    self.token("...");
939                }
940            }
941        }
942        self.token(")");
943    }
944
945    /// One parameter of a prototype.
946    fn parameter(&mut self, param: Param) {
947        if let Some(specs) = param.specs {
948            self.decl_specs(specs);
949        }
950        let text = self.declarator_text(param.declarator);
951        if !text.is_empty() {
952            self.space();
953            self.token(&text);
954        }
955        self.attributes(param.attrs);
956    }
957
958    /// Every attribute of a list, each in the syntax it was written in.
959    fn attributes(&mut self, list: AttrList) {
960        let ast = self.ast;
961        for attr in &ast[list] {
962            self.space();
963            match attr.syntax {
964                AttrSyntax::Standard => self.token("[["),
965                AttrSyntax::Gnu => self.token("__attribute__(("),
966                AttrSyntax::Declspec => self.token("__declspec("),
967            }
968            if let Some(namespace) = attr.namespace {
969                self.name(namespace);
970                self.token("::");
971            }
972            self.name(attr.name);
973            if !attr.args.is_empty() {
974                self.token("(");
975                for (index, arg) in ast[attr.args].iter().enumerate() {
976                    if index > 0 {
977                        self.token(",");
978                        self.space();
979                    }
980                    match *arg {
981                        AttrArg::Ident(name) => self.name(name),
982                        AttrArg::Expr(expr) => self.expr_at(expr, ASSIGN),
983                    }
984                }
985                self.token(")");
986            }
987            match attr.syntax {
988                AttrSyntax::Standard => self.token("]]"),
989                AttrSyntax::Gnu => self.token("))"),
990                AttrSyntax::Declspec => self.token(")"),
991            }
992            // Whatever comes next reads as part of the attribute without this. Nothing needs it
993            // to lex, and `token` takes it back where what follows is punctuation.
994            self.space();
995        }
996    }
997
998    /// An initializer, which is an expression or a braced list.
999    fn init(&mut self, id: InitId) {
1000        let ast = self.ast;
1001        match ast[id] {
1002            Init::Expr(expr) => self.expr_at(expr, ASSIGN),
1003            Init::List(items) => {
1004                self.token("{");
1005                for (index, item) in ast[items].iter().enumerate() {
1006                    if index > 0 {
1007                        self.token(",");
1008                    }
1009                    self.space();
1010                    let designators = &ast[item.designators];
1011                    for designator in designators {
1012                        self.designator(*designator);
1013                    }
1014                    // The obsolete `name:` form carries its own colon and takes no `=`.
1015                    let obsolete = matches!(designators.last(), Some(Designator::ObsoleteField(_)));
1016                    if !designators.is_empty() && !obsolete {
1017                        self.space();
1018                        self.token("=");
1019                        self.space();
1020                    }
1021                    self.init(item.init);
1022                }
1023                self.space();
1024                self.token("}");
1025            }
1026        }
1027    }
1028
1029    /// One step of a designation, or of a `__builtin_offsetof` path.
1030    fn designator(&mut self, designator: Designator) {
1031        match designator {
1032            Designator::Field(name) => {
1033                self.token(".");
1034                self.name(name);
1035            }
1036            Designator::Index(index) => {
1037                self.token("[");
1038                self.expr_at(index, COMMA);
1039                self.token("]");
1040            }
1041            Designator::Range { lo, hi } => {
1042                self.token("[");
1043                self.expr_at(lo, COND);
1044                self.space();
1045                self.token("...");
1046                self.space();
1047                self.expr_at(hi, COND);
1048                self.token("]");
1049            }
1050            Designator::ObsoleteField(name) => {
1051                self.name(name);
1052                self.token(":");
1053                self.space();
1054            }
1055        }
1056    }
1057
1058    /// An expression, in parentheses when what encloses it binds more tightly than it does.
1059    fn expr_at(&mut self, id: ExprId, min: u8) {
1060        if self.precedence(id) < min {
1061            self.token("(");
1062            self.expression(id);
1063            self.token(")");
1064        } else {
1065            self.expression(id);
1066        }
1067    }
1068
1069    /// How tightly an expression holds together, which decides whether it needs parentheses.
1070    fn precedence(&self, id: ExprId) -> u8 {
1071        match self.ast[id] {
1072            Expr::Comma { .. } => COMMA,
1073            Expr::Assign { .. } => ASSIGN,
1074            Expr::Cond { .. } => COND,
1075            Expr::Binary { op, .. } => binding(op),
1076            Expr::Cast { .. } => CAST,
1077            Expr::Unary { op, .. } => {
1078                if op.is_postfix() {
1079                    POSTFIX
1080                } else {
1081                    UNARY
1082                }
1083            }
1084            Expr::SizeofExpr(_) | Expr::AlignofExpr(_) | Expr::Extension(_) => UNARY,
1085            Expr::Index { .. }
1086            | Expr::Call { .. }
1087            | Expr::Member { .. }
1088            | Expr::CompoundLiteral { .. } => POSTFIX,
1089            _ => PRIMARY,
1090        }
1091    }
1092
1093    /// One expression, with no regard for what encloses it.
1094    fn expression(&mut self, id: ExprId) {
1095        let ast = self.ast;
1096        match ast[id] {
1097            // Poisoned, and written as a constant so that a broken tree still prints to
1098            // something that parses.
1099            Expr::Error => self.token("0"),
1100            Expr::Name(name) => self.name(name),
1101            Expr::Int(constant) => {
1102                let constant = ast[constant];
1103                let text = format!("{}{}", constant.value, constant.ty.suffix());
1104                self.token(&text);
1105            }
1106            Expr::Float(constant) => {
1107                let constant = ast[constant];
1108                let mut text = constant.value.to_hex();
1109                text.push_str(constant.ty.suffix());
1110                if constant.imaginary {
1111                    text.push('i');
1112                }
1113                self.token(&text);
1114            }
1115            Expr::Char(constant) => {
1116                let text = ast[constant].spell();
1117                self.token(&text);
1118            }
1119            Expr::Str(literal) => self.string(literal),
1120            Expr::Bool(value) => self.token(if value { "true" } else { "false" }),
1121            Expr::Nullptr => self.token("nullptr"),
1122            Expr::Index { base, index } => {
1123                self.expr_at(base, POSTFIX);
1124                self.token("[");
1125                self.expr_at(index, COMMA);
1126                self.token("]");
1127            }
1128            Expr::Call { callee, args } => {
1129                self.expr_at(callee, POSTFIX);
1130                self.token("(");
1131                self.arguments(args);
1132                self.token(")");
1133            }
1134            Expr::Member { base, name, arrow } => {
1135                self.expr_at(base, POSTFIX);
1136                self.token(if arrow { "->" } else { "." });
1137                self.name(name);
1138            }
1139            Expr::Unary { op, operand } => {
1140                if op.is_postfix() {
1141                    self.expr_at(operand, POSTFIX);
1142                    self.token(op.spelling());
1143                } else {
1144                    self.token(op.spelling());
1145                    let inner = match op {
1146                        UnaryOp::PreInc | UnaryOp::PreDec => UNARY,
1147                        _ => CAST,
1148                    };
1149                    self.expr_at(operand, inner);
1150                }
1151            }
1152            Expr::Binary { op, lhs, rhs } => {
1153                let at = binding(op);
1154                self.expr_at(lhs, at);
1155                self.space();
1156                self.token(op.spelling());
1157                self.space();
1158                // The right operand needs one more, since every binary operator in C groups to
1159                // the left and `a - (b - c)` is not `a - b - c`.
1160                self.expr_at(rhs, at + 1);
1161            }
1162            Expr::Assign { op, lhs, rhs } => {
1163                self.expr_at(lhs, UNARY);
1164                self.space();
1165                match op {
1166                    Some(op) => {
1167                        let text = format!("{}=", op.spelling());
1168                        self.token(&text);
1169                    }
1170                    None => self.token("="),
1171                }
1172                self.space();
1173                self.expr_at(rhs, ASSIGN);
1174            }
1175            Expr::Cond { cond, then, otherwise } => {
1176                self.expr_at(cond, COND + 1);
1177                self.space();
1178                self.token("?");
1179                if let Some(then) = then {
1180                    self.space();
1181                    self.expr_at(then, COMMA);
1182                }
1183                self.space();
1184                self.token(":");
1185                self.space();
1186                self.expr_at(otherwise, COND);
1187            }
1188            Expr::Comma { lhs, rhs } => {
1189                self.expr_at(lhs, COMMA);
1190                self.token(",");
1191                self.space();
1192                self.expr_at(rhs, ASSIGN);
1193            }
1194            Expr::Cast { ty, operand } => {
1195                self.token("(");
1196                self.type_name(ty);
1197                self.token(")");
1198                self.expr_at(operand, CAST);
1199            }
1200            Expr::CompoundLiteral { ty, init } => {
1201                self.token("(");
1202                self.type_name(ty);
1203                self.token(")");
1204                self.init(init);
1205            }
1206            // The operand is bracketed unless it is already a name or a constant, because
1207            // `sizeof (T){ 0 }` reads as a type in parentheses and is not one.
1208            Expr::SizeofExpr(operand) => {
1209                self.token("sizeof");
1210                self.space();
1211                self.expr_at(operand, PRIMARY);
1212            }
1213            Expr::SizeofType(ty) => {
1214                self.token("sizeof");
1215                self.token("(");
1216                self.type_name(ty);
1217                self.token(")");
1218            }
1219            Expr::AlignofExpr(operand) => {
1220                self.token("__alignof__");
1221                self.space();
1222                self.expr_at(operand, PRIMARY);
1223            }
1224            Expr::AlignofType(ty) => {
1225                self.token("_Alignof");
1226                self.token("(");
1227                self.type_name(ty);
1228                self.token(")");
1229            }
1230            Expr::Generic { control, assocs } => {
1231                self.token("_Generic");
1232                self.token("(");
1233                self.expr_at(control, ASSIGN);
1234                self.associations(assocs);
1235                self.token(")");
1236            }
1237            Expr::StmtExpr(body) => {
1238                self.token("(");
1239                self.stmt(body);
1240                self.token(")");
1241            }
1242            Expr::LabelAddr(name) => {
1243                self.token("&&");
1244                self.name(name);
1245            }
1246            Expr::Offsetof { ty, path } => {
1247                self.token("__builtin_offsetof");
1248                self.token("(");
1249                self.type_name(ty);
1250                self.token(",");
1251                self.space();
1252                self.member_path(path);
1253                self.token(")");
1254            }
1255            Expr::ChooseExpr { cond, then, otherwise } => {
1256                self.token("__builtin_choose_expr");
1257                self.token("(");
1258                self.expr_at(cond, ASSIGN);
1259                self.token(",");
1260                self.space();
1261                self.expr_at(then, ASSIGN);
1262                self.token(",");
1263                self.space();
1264                self.expr_at(otherwise, ASSIGN);
1265                self.token(")");
1266            }
1267            Expr::TypesCompatible { a, b } => {
1268                self.token("__builtin_types_compatible_p");
1269                self.token("(");
1270                self.type_name(a);
1271                self.token(",");
1272                self.space();
1273                self.type_name(b);
1274                self.token(")");
1275            }
1276            Expr::VaArg { list, ty } => {
1277                self.token("__builtin_va_arg");
1278                self.token("(");
1279                self.expr_at(list, ASSIGN);
1280                self.token(",");
1281                self.space();
1282                self.type_name(ty);
1283                self.token(")");
1284            }
1285            Expr::VaStart { list, last } => {
1286                self.token("__builtin_va_start");
1287                self.token("(");
1288                self.expr_at(list, ASSIGN);
1289                if let Some(last) = last {
1290                    self.token(",");
1291                    self.space();
1292                    self.expr_at(last, ASSIGN);
1293                }
1294                self.token(")");
1295            }
1296            Expr::VaEnd { list } => {
1297                self.token("__builtin_va_end");
1298                self.token("(");
1299                self.expr_at(list, ASSIGN);
1300                self.token(")");
1301            }
1302            Expr::VaCopy { dst, src } => {
1303                self.token("__builtin_va_copy");
1304                self.token("(");
1305                self.expr_at(dst, ASSIGN);
1306                self.token(",");
1307                self.space();
1308                self.expr_at(src, ASSIGN);
1309                self.token(")");
1310            }
1311            Expr::Extension(operand) => {
1312                self.token("__extension__");
1313                self.space();
1314                self.expr_at(operand, CAST);
1315            }
1316        }
1317    }
1318
1319    /// The arguments of a call, which are assignment-expressions so that the commas between
1320    /// them stay separators.
1321    fn arguments(&mut self, args: ExprList) {
1322        let ast = self.ast;
1323        for (index, &arg) in ast[args].iter().enumerate() {
1324            if index > 0 {
1325                self.token(",");
1326                self.space();
1327            }
1328            self.expr_at(arg, ASSIGN);
1329        }
1330    }
1331
1332    /// The arms of a `_Generic`, the leading comma of each included.
1333    fn associations(&mut self, assocs: GenericList) {
1334        let ast = self.ast;
1335        for assoc in &ast[assocs] {
1336            self.token(",");
1337            self.space();
1338            match assoc.ty {
1339                Some(ty) => self.type_name(ty),
1340                None => self.token("default"),
1341            }
1342            self.token(":");
1343            self.space();
1344            self.expr_at(assoc.value, ASSIGN);
1345        }
1346    }
1347
1348    /// The member path of a `__builtin_offsetof`, whose first step is written with no dot.
1349    fn member_path(&mut self, path: DesignatorList) {
1350        let ast = self.ast;
1351        for (index, step) in ast[path].iter().enumerate() {
1352            match (index, *step) {
1353                (0, Designator::Field(name)) => self.name(name),
1354                (_, step) => self.designator(step),
1355            }
1356        }
1357    }
1358
1359    /// A string literal, prefix and quotes included.
1360    fn string(&mut self, id: StrId) {
1361        let ast = self.ast;
1362        let text = ast[id].spell();
1363        self.token(&text);
1364    }
1365
1366    /// An identifier.
1367    fn name(&mut self, symbol: Symbol) {
1368        let names = self.names;
1369        self.token(names.resolve(symbol));
1370    }
1371
1372    /// Writes with the output redirected into a buffer of its own, and gives the buffer back.
1373    fn capture(&mut self, write: impl FnOnce(&mut Printer<'a>)) -> String {
1374        let held = std::mem::take(&mut self.out);
1375        write(self);
1376        std::mem::replace(&mut self.out, held)
1377    }
1378
1379    /// Appends one token, with a space in front of it if it would otherwise join the one before.
1380    fn token(&mut self, text: &str) {
1381        if text.is_empty() {
1382            return;
1383        }
1384        if text.starts_with([';', ',', ')', ']']) {
1385            self.unspace();
1386        }
1387        if let (Some(last), Some(next)) = (self.out.chars().next_back(), text.chars().next()) {
1388            if pastes(last, next) {
1389                self.out.push(' ');
1390            }
1391        }
1392        self.out.push_str(text);
1393    }
1394
1395    /// Takes back a space that was written for reading, where what follows turns out not to want
1396    /// one in front of it. An indent is not one of those spaces and stays.
1397    fn unspace(&mut self) {
1398        let kept = self.out.trim_end_matches(' ');
1399        if !kept.ends_with('\n') {
1400            self.out.truncate(kept.len());
1401        }
1402    }
1403
1404    /// Appends a space, where one is wanted for reading rather than needed for lexing.
1405    fn space(&mut self) {
1406        if !self.out.is_empty() && !self.out.ends_with([' ', '\n']) {
1407            self.out.push(' ');
1408        }
1409    }
1410
1411    /// Ends the line and indents the next one.
1412    fn newline(&mut self) {
1413        while self.out.ends_with(' ') {
1414            self.out.pop();
1415        }
1416        self.out.push('\n');
1417        for _ in 0..self.depth {
1418            self.out.push_str("    ");
1419        }
1420    }
1421}
1422
1423#[cfg(test)]
1424mod tests {
1425    use rucc_diag::Span;
1426    use rucc_lex::{CharConstant, Encoding, StringLiteral};
1427
1428    use super::*;
1429    use crate::decl::Declarator;
1430    use crate::spec::{DeclSpecs, StorageClass};
1431
1432    struct Fixture {
1433        ast: Ast,
1434        names: Interner,
1435    }
1436
1437    impl Fixture {
1438        fn new() -> Fixture {
1439            Fixture { ast: Ast::new(), names: Interner::new() }
1440        }
1441
1442        fn text(&self, write: impl FnOnce(&mut Printer<'_>)) -> String {
1443            let mut printer = Printer::new(&self.ast, &self.names);
1444            write(&mut printer);
1445            printer.finish()
1446        }
1447    }
1448
1449    #[test]
1450    fn two_tokens_that_would_join_get_a_space() {
1451        let mut fixture = Fixture::new();
1452        let one = fixture.ast.expr(Expr::Bool(true), Span::DUMMY);
1453        let minus = fixture.ast.expr(Expr::Unary { op: UnaryOp::Minus, operand: one }, Span::DUMMY);
1454        let twice =
1455            fixture.ast.expr(Expr::Unary { op: UnaryOp::Minus, operand: minus }, Span::DUMMY);
1456        assert_eq!(fixture.text(|p| p.expr(twice)), "- -true");
1457    }
1458
1459    #[test]
1460    fn the_variable_argument_family_prints_as_it_was_written() {
1461        let mut fixture = Fixture::new();
1462        let ap = fixture.names.intern("ap");
1463        let copy = fixture.names.intern("copy");
1464        let n = fixture.names.intern("n");
1465        let ap = fixture.ast.expr(Expr::Name(ap), Span::DUMMY);
1466        let copy = fixture.ast.expr(Expr::Name(copy), Span::DUMMY);
1467        let n = fixture.ast.expr(Expr::Name(n), Span::DUMMY);
1468
1469        let start = fixture.ast.expr(Expr::VaStart { list: ap, last: Some(n) }, Span::DUMMY);
1470        assert_eq!(fixture.text(|p| p.expr(start)), "__builtin_va_start(ap, n)");
1471
1472        // The second argument is missing rather than written as nothing, which is what a
1473        // program that leaves it out gets and which is reported later rather than here.
1474        let alone = fixture.ast.expr(Expr::VaStart { list: ap, last: None }, Span::DUMMY);
1475        assert_eq!(fixture.text(|p| p.expr(alone)), "__builtin_va_start(ap)");
1476
1477        let copied = fixture.ast.expr(Expr::VaCopy { dst: copy, src: ap }, Span::DUMMY);
1478        assert_eq!(fixture.text(|p| p.expr(copied)), "__builtin_va_copy(copy, ap)");
1479
1480        let end = fixture.ast.expr(Expr::VaEnd { list: ap }, Span::DUMMY);
1481        assert_eq!(fixture.text(|p| p.expr(end)), "__builtin_va_end(ap)");
1482    }
1483
1484    #[test]
1485    fn parentheses_go_where_the_grammar_needs_them_and_nowhere_else() {
1486        let mut fixture = Fixture::new();
1487        let a = fixture.names.intern("a");
1488        let b = fixture.names.intern("b");
1489        let c = fixture.names.intern("c");
1490        let a = fixture.ast.expr(Expr::Name(a), Span::DUMMY);
1491        let b = fixture.ast.expr(Expr::Name(b), Span::DUMMY);
1492        let c = fixture.ast.expr(Expr::Name(c), Span::DUMMY);
1493
1494        let sum = fixture.ast.expr(Expr::Binary { op: BinaryOp::Add, lhs: a, rhs: b }, Span::DUMMY);
1495        let scaled =
1496            fixture.ast.expr(Expr::Binary { op: BinaryOp::Mul, lhs: sum, rhs: c }, Span::DUMMY);
1497        assert_eq!(fixture.text(|p| p.expr(scaled)), "(a + b) * c");
1498
1499        let product =
1500            fixture.ast.expr(Expr::Binary { op: BinaryOp::Mul, lhs: b, rhs: c }, Span::DUMMY);
1501        let total =
1502            fixture.ast.expr(Expr::Binary { op: BinaryOp::Add, lhs: a, rhs: product }, Span::DUMMY);
1503        assert_eq!(fixture.text(|p| p.expr(total)), "a + b * c");
1504
1505        // Left grouping, so the right operand of a subtraction keeps its parentheses.
1506        let inner =
1507            fixture.ast.expr(Expr::Binary { op: BinaryOp::Sub, lhs: b, rhs: c }, Span::DUMMY);
1508        let outer =
1509            fixture.ast.expr(Expr::Binary { op: BinaryOp::Sub, lhs: a, rhs: inner }, Span::DUMMY);
1510        assert_eq!(fixture.text(|p| p.expr(outer)), "a - (b - c)");
1511    }
1512
1513    #[test]
1514    fn a_declarator_reads_outward_from_its_name() {
1515        let mut fixture = Fixture::new();
1516        let f = fixture.names.intern("f");
1517        let three = fixture.ast.expr(Expr::Bool(true), Span::DUMMY);
1518        let derived = fixture.ast.add_derived_list(&[
1519            Derived::Array { size: ArraySize::Expr(three), quals: Quals::NONE, has_static: false },
1520            Derived::Pointer { quals: Quals::NONE, attrs: AttrList::EMPTY },
1521            Derived::Function { params: ParamList::EMPTY, variadic: false, kind: ParamKind::Void },
1522        ]);
1523        let declarator = fixture.ast.add_declarator(Declarator {
1524            name: Some(f),
1525            name_span: Span::DUMMY,
1526            derived,
1527            span: Span::DUMMY,
1528        });
1529        let specs = fixture.ast.add_specs(DeclSpecs::empty(Span::DUMMY));
1530        let ty = fixture.ast.add_type_name(crate::decl::TypeName {
1531            specs,
1532            declarator,
1533            span: Span::DUMMY,
1534        });
1535        assert_eq!(fixture.text(|p| p.type_name(ty)), "(*f[true])(void)");
1536    }
1537
1538    #[test]
1539    fn a_declaration_keeps_its_declarators_together() {
1540        let mut fixture = Fixture::new();
1541        let a = fixture.names.intern("a");
1542        let b = fixture.names.intern("b");
1543        let mut specs = DeclSpecs::empty(Span::DUMMY);
1544        specs.storage = Some(StorageClass::Static);
1545        specs.ty = TypeSpec::Builtin(Builtin { set: BuiltinSet::INT, longs: 0, width: None });
1546        let specs = fixture.ast.add_specs(specs);
1547        let mut declarators = Vec::new();
1548        for (name, stars) in [(a, 0), (b, 1)] {
1549            let derived = if stars == 0 {
1550                crate::ast::DerivedList::EMPTY
1551            } else {
1552                fixture.ast.add_derived_list(&[Derived::Pointer {
1553                    quals: Quals::NONE,
1554                    attrs: AttrList::EMPTY,
1555                }])
1556            };
1557            let declarator = fixture.ast.add_declarator(Declarator {
1558                name: Some(name),
1559                name_span: Span::DUMMY,
1560                derived,
1561                span: Span::DUMMY,
1562            });
1563            declarators.push(crate::decl::InitDeclarator {
1564                declarator,
1565                init: None,
1566                asm_label: None,
1567                attrs: AttrList::EMPTY,
1568                span: Span::DUMMY,
1569            });
1570        }
1571        let declarators = fixture.ast.add_init_declarator_list(&declarators);
1572        let decl = fixture.ast.decl(Decl::Var { specs, declarators }, Span::DUMMY);
1573        assert_eq!(fixture.text(|p| p.decl(decl)), "static int a, *b;");
1574    }
1575
1576    #[test]
1577    fn a_byte_escape_in_a_string_takes_three_octal_digits() {
1578        let literal = StringLiteral {
1579            elements: vec![0xff, u32::from(b'0'), u32::from(b'a')],
1580            encoding: Encoding::Plain,
1581            remarks: rucc_lex::Remarks::NONE,
1582        };
1583        assert_eq!(literal.spell(), "\"\\3770a\"");
1584    }
1585
1586    #[test]
1587    fn a_wide_escape_closes_the_literal_rather_than_swallowing_what_follows() {
1588        let literal = StringLiteral {
1589            elements: vec![0x1234, u32::from(b'a'), u32::from(b'z')],
1590            encoding: Encoding::Utf32,
1591            remarks: rucc_lex::Remarks::NONE,
1592        };
1593        assert_eq!(literal.spell(), "U\"\\x1234\" U\"az\"");
1594    }
1595
1596    #[test]
1597    fn a_character_constant_is_written_as_a_character_where_it_can_be() {
1598        let plain = CharConstant {
1599            value: i64::from(b'a'),
1600            encoding: Encoding::Plain,
1601            remarks: rucc_lex::Remarks::NONE,
1602        };
1603        assert_eq!(plain.spell(), "'a'");
1604
1605        let quote = CharConstant { encoding: Encoding::Plain, value: i64::from(b'\''), ..plain };
1606        assert_eq!(quote.spell(), "'\\''");
1607
1608        let negative = CharConstant { value: -1, ..plain };
1609        assert_eq!(negative.spell(), "'\\xff'");
1610
1611        let many = CharConstant { value: 0x6162, ..plain };
1612        assert_eq!(many.spell(), "'\\x61\\x62'");
1613    }
1614}