Skip to main content

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}