rucc_sema/stmt.rs
1//! Typed statements.
2//!
3//! Design: `spec/07-types-and-semantics.md` section 7.14.
4//!
5//! The shapes are the ones the parser produced, because a `for` loop that has become a `while`
6//! loop by the time anything reports on it is a `for` loop nobody can be told about. What is
7//! different is that the conditions have been converted to `bool`, the labels and the `goto`s
8//! that reach them have been resolved to each other, and a `switch` carries the table of cases
9//! that the walk to the IR would otherwise have to collect by searching its body.
10
11use rucc_base::{Idx, IdxRange};
12
13use crate::asm::AsmId;
14use crate::decl::DeclList;
15use crate::expr::ExprId;
16use crate::tast::LabelId;
17
18/// One `case` of a `switch`, in the case table.
19pub type CaseId = Idx<Case>;
20
21/// One typed statement in the arena.
22pub type StmtId = Idx<Stmt>;
23
24/// The table of references to statements, which is what a block is a run of.
25#[derive(Debug)]
26pub struct StmtRef;
27
28/// A run of statements.
29pub type StmtList = IdxRange<StmtRef>;
30
31/// A run of the cases of one `switch`.
32pub type CaseList = IdxRange<Case>;
33
34/// A statement.
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum Stmt {
37 /// A statement that was already the subject of a diagnostic.
38 Error,
39 /// `;`, which is a statement and does nothing.
40 Empty,
41 /// An expression evaluated for its effects, whose value is discarded.
42 Expr(ExprId),
43 /// `{ ... }`, which is also a scope, though the scope has been resolved by now.
44 Block(StmtList),
45 /// The declarations of one declaration statement, which introduce objects into the block.
46 Decls(DeclList),
47 /// `if (cond) then else otherwise`.
48 If {
49 /// The condition, converted to `bool`.
50 cond: ExprId,
51 /// The statement taken when it is true.
52 then: StmtId,
53 /// The statement taken when it is false, if there is one.
54 otherwise: Option<StmtId>,
55 },
56 /// `while (cond) body`.
57 While {
58 /// The condition, converted to `bool`.
59 cond: ExprId,
60 /// The body.
61 body: StmtId,
62 },
63 /// `do body while (cond);`.
64 DoWhile {
65 /// The body, which runs before the condition is first evaluated.
66 body: StmtId,
67 /// The condition, converted to `bool`.
68 cond: ExprId,
69 },
70 /// `for (init; cond; step) body`.
71 For {
72 /// The initial clause, which is a declaration or an expression or nothing.
73 init: Option<StmtId>,
74 /// The condition, converted to `bool`, or nothing for `for (;;)`.
75 cond: Option<ExprId>,
76 /// The step, evaluated for its effects.
77 step: Option<ExprId>,
78 /// The body.
79 body: StmtId,
80 },
81 /// `switch (cond) body`.
82 Switch {
83 /// The controlling expression, after its integer promotion.
84 cond: ExprId,
85 /// The body, which holds the labelled statements themselves.
86 body: StmtId,
87 /// Where each value goes, collected here so that the walk to the IR builds a jump
88 /// table from a table rather than by searching the body for labels.
89 cases: CaseList,
90 /// Where a value that matches nothing goes, absent when there is no `default`, which
91 /// is the same statement the [`Stmt::Default`] in the body labels.
92 default: Option<StmtId>,
93 },
94 /// `case value:`, which is a label on the statement it precedes.
95 ///
96 /// The value is in the case table rather than here, because two `i128` bounds would make
97 /// every statement in the arena the size of the widest one.
98 Case {
99 /// Which entry of the enclosing `switch`'s table, so that reaching a case gives its
100 /// value without searching the table for the statement that is already in hand.
101 case: CaseId,
102 /// The statement it labels.
103 body: StmtId,
104 },
105 /// `default:`, which is a label and not a case, since it has no value to be in a table.
106 ///
107 /// It is here as well as in the enclosing `switch` because the two say different things:
108 /// this says where in the body it was written, and the field on the `switch` is the entry
109 /// of the jump table. A reader that only had the field could not say where `default:` went.
110 Default {
111 /// The statement it labels.
112 body: StmtId,
113 },
114 /// `name: body`, with the label resolved.
115 Label {
116 /// Which label.
117 label: LabelId,
118 /// The statement it labels.
119 body: StmtId,
120 },
121 /// `goto name;`, with the label resolved.
122 Goto(LabelId),
123 /// `goto *expr;`, GNU's computed goto, whose target is a label address.
124 IndirectGoto(ExprId),
125 /// `asm(...)`, whose operands and labels are in the assembly table.
126 Asm(AsmId),
127 /// `break;`, which leaves the innermost loop or `switch`.
128 Break,
129 /// `continue;`, which starts the next iteration of the innermost loop.
130 Continue,
131 /// `return;` or `return expr;`, with the value already converted to the return type.
132 Return(Option<ExprId>),
133}
134
135/// One `case` of a `switch`, after its value has been folded.
136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137pub struct Case {
138 /// The lowest value that reaches this case.
139 ///
140 /// The value is held in the promoted type of the controlling expression, converted there
141 /// once, so that the comparison the IR emits is between two values of one type.
142 pub low: i128,
143 /// The highest value that reaches it, which equals `low` unless this is GNU's `case 1 ... 9`.
144 pub high: i128,
145 /// The statement it labels.
146 pub body: StmtId,
147}