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