Rust · 7742 bytes Raw Blame History
1 //! Statement AST nodes.
2 //!
3 //! Control flow, assignments, calls, and all executable Fortran statements.
4
5 use super::decl::SpannedDecl;
6 use super::expr::SpannedExpr;
7 use super::Spanned;
8
9 /// A spanned statement.
10 pub type SpannedStmt = Spanned<Stmt>;
11
12 /// A Fortran executable statement.
13 #[derive(Debug, Clone, PartialEq)]
14 #[allow(clippy::large_enum_variant)]
15 #[allow(clippy::enum_variant_names)]
16 pub enum Stmt {
17 // ---- Assignment ----
18 Assignment {
19 target: SpannedExpr,
20 value: SpannedExpr,
21 },
22 PointerAssignment {
23 target: SpannedExpr,
24 value: SpannedExpr,
25 },
26
27 // ---- IF ----
28 IfConstruct {
29 name: Option<String>,
30 condition: SpannedExpr,
31 then_body: Vec<SpannedStmt>,
32 else_ifs: Vec<(SpannedExpr, Vec<SpannedStmt>)>,
33 else_body: Option<Vec<SpannedStmt>>,
34 },
35 IfStmt {
36 condition: SpannedExpr,
37 action: Box<SpannedStmt>,
38 },
39
40 // ---- DO loops ----
41 DoLoop {
42 name: Option<String>,
43 var: Option<String>,
44 start: Option<SpannedExpr>,
45 end: Option<SpannedExpr>,
46 step: Option<SpannedExpr>,
47 body: Vec<SpannedStmt>,
48 },
49 DoWhile {
50 name: Option<String>,
51 condition: SpannedExpr,
52 body: Vec<SpannedStmt>,
53 },
54 DoConcurrent {
55 name: Option<String>,
56 controls: Vec<ConcurrentControl>,
57 mask: Option<SpannedExpr>,
58 locality: Vec<LocalitySpec>,
59 body: Vec<SpannedStmt>,
60 },
61
62 // ---- SELECT CASE ----
63 SelectCase {
64 name: Option<String>,
65 selector: SpannedExpr,
66 cases: Vec<CaseBlock>,
67 },
68
69 // ---- SELECT TYPE ----
70 SelectType {
71 name: Option<String>,
72 selector: SpannedExpr,
73 assoc_name: Option<String>, // SELECT TYPE (assoc => expr)
74 guards: Vec<TypeGuard>,
75 },
76
77 // ---- WHERE / FORALL ----
78 WhereConstruct {
79 name: Option<String>,
80 mask: SpannedExpr,
81 body: Vec<SpannedStmt>,
82 elsewhere: Vec<(Option<SpannedExpr>, Vec<SpannedStmt>)>,
83 },
84 WhereStmt {
85 mask: SpannedExpr,
86 stmt: Box<SpannedStmt>,
87 },
88 ForallConstruct {
89 name: Option<String>,
90 specs: Vec<ForallSpec>,
91 mask: Option<SpannedExpr>,
92 body: Vec<SpannedStmt>,
93 },
94 ForallStmt {
95 specs: Vec<ForallSpec>,
96 mask: Option<SpannedExpr>,
97 stmt: Box<SpannedStmt>,
98 },
99
100 // ---- BLOCK / ASSOCIATE ----
101 Block {
102 name: Option<String>,
103 /// USE statements declared inside the BLOCK specification part.
104 /// These imports are scoped to the block body and do not leak
105 /// into the enclosing procedure.
106 uses: Vec<super::decl::SpannedDecl>,
107 /// Interface blocks declared inside the BLOCK specification part.
108 /// They are only visible within the block body.
109 ifaces: Vec<super::unit::SpannedUnit>,
110 /// IMPLICIT statements declared inside the BLOCK. F2018 §11.1.4
111 /// gives a BLOCK its own implicit-type rule environment that does
112 /// not leak out and is independent of the enclosing scope's
113 /// IMPLICIT NONE state.
114 implicit: Vec<super::decl::SpannedDecl>,
115 decls: Vec<super::decl::SpannedDecl>,
116 body: Vec<SpannedStmt>,
117 },
118 Associate {
119 name: Option<String>,
120 assocs: Vec<(String, SpannedExpr)>,
121 body: Vec<SpannedStmt>,
122 },
123
124 // ---- Branch/transfer ----
125 Exit {
126 name: Option<String>,
127 },
128 Cycle {
129 name: Option<String>,
130 },
131 Stop {
132 code: Option<SpannedExpr>,
133 quiet: bool,
134 },
135 ErrorStop {
136 code: Option<SpannedExpr>,
137 quiet: bool,
138 },
139 Return {
140 value: Option<SpannedExpr>,
141 },
142 Goto {
143 label: u64,
144 },
145 ComputedGoto {
146 labels: Vec<u64>,
147 selector: SpannedExpr,
148 },
149 ArithmeticIf {
150 expr: SpannedExpr,
151 neg: u64,
152 zero: u64,
153 pos: u64,
154 },
155 /// Statement label on any executable statement: `10 i = i + 1`.
156 /// The parser emits this when it sees an integer literal at statement start.
157 Labeled {
158 label: u64,
159 stmt: Box<SpannedStmt>,
160 },
161
162 // ---- I/O ----
163 Write {
164 controls: Vec<IoControl>,
165 items: Vec<SpannedExpr>,
166 },
167 Read {
168 controls: Vec<IoControl>,
169 items: Vec<SpannedExpr>,
170 },
171 Open {
172 specs: Vec<IoControl>,
173 },
174 Close {
175 specs: Vec<IoControl>,
176 },
177 Inquire {
178 specs: Vec<IoControl>,
179 items: Vec<SpannedExpr>,
180 },
181 Rewind {
182 specs: Vec<IoControl>,
183 },
184 Backspace {
185 specs: Vec<IoControl>,
186 },
187 Endfile {
188 specs: Vec<IoControl>,
189 },
190 Flush {
191 specs: Vec<IoControl>,
192 },
193 Wait {
194 specs: Vec<IoControl>,
195 },
196
197 // ---- Memory ----
198 Allocate {
199 items: Vec<SpannedExpr>,
200 opts: Vec<IoControl>,
201 },
202 Deallocate {
203 items: Vec<SpannedExpr>,
204 opts: Vec<IoControl>,
205 },
206 Nullify {
207 items: Vec<SpannedExpr>,
208 },
209
210 // ---- Other executable ----
211 Continue {
212 label: Option<u64>,
213 },
214 Call {
215 callee: SpannedExpr,
216 args: Vec<crate::ast::expr::Argument>,
217 },
218 Print {
219 format: SpannedExpr,
220 items: Vec<SpannedExpr>,
221 },
222 Namelist {
223 groups: Vec<(String, Vec<String>)>,
224 },
225
226 // ---- Declaration (embedded in statement context) ----
227 Declaration(SpannedDecl),
228 }
229
230 /// I/O control specifier: either a positional value or keyword=value pair.
231 /// Used for WRITE/READ control lists, OPEN/CLOSE/INQUIRE specifiers, and
232 /// ALLOCATE options (stat=, errmsg=, source=, mold=).
233 #[derive(Debug, Clone, PartialEq)]
234 pub struct IoControl {
235 pub keyword: Option<String>,
236 pub value: SpannedExpr,
237 }
238
239 // ---- Supporting types ----
240
241 /// A type guard in SELECT TYPE.
242 #[derive(Debug, Clone, PartialEq)]
243 pub enum TypeGuard {
244 /// TYPE IS (type_name) — exact type match.
245 TypeIs {
246 type_name: String,
247 body: Vec<SpannedStmt>,
248 },
249 /// CLASS IS (type_name) — matches type or any extension.
250 ClassIs {
251 type_name: String,
252 body: Vec<SpannedStmt>,
253 },
254 /// CLASS DEFAULT — fallback.
255 ClassDefault { body: Vec<SpannedStmt> },
256 }
257
258 /// A CASE block: case selector + body.
259 #[derive(Debug, Clone, PartialEq)]
260 pub struct CaseBlock {
261 pub selectors: Vec<CaseSelector>,
262 pub body: Vec<SpannedStmt>,
263 }
264
265 /// A CASE selector: single value, range, or default.
266 #[derive(Debug, Clone, PartialEq)]
267 pub enum CaseSelector {
268 Value(SpannedExpr),
269 Range {
270 low: Option<SpannedExpr>,
271 high: Option<SpannedExpr>,
272 },
273 Default,
274 }
275
276 /// DO CONCURRENT locality specification (F2018).
277 #[derive(Debug, Clone, PartialEq)]
278 pub enum LocalitySpec {
279 /// LOCAL(var_list) — private to each iteration.
280 Local(Vec<String>),
281 /// LOCAL_INIT(var_list) — private, initialized from outer scope.
282 LocalInit(Vec<String>),
283 /// SHARED(var_list) — shared across iterations.
284 Shared(Vec<String>),
285 /// DEFAULT(NONE) — all variables must be explicitly specified.
286 DefaultNone,
287 /// REDUCE(op: var_list) — reduction variable.
288 Reduce { op: String, vars: Vec<String> },
289 }
290
291 /// DO CONCURRENT control: `i = 1:n`
292 #[derive(Debug, Clone, PartialEq)]
293 pub struct ConcurrentControl {
294 pub var: String,
295 pub start: SpannedExpr,
296 pub end: SpannedExpr,
297 pub step: Option<SpannedExpr>,
298 }
299
300 /// FORALL specification: `i = 1:n:step`
301 #[derive(Debug, Clone, PartialEq)]
302 pub struct ForallSpec {
303 pub var: String,
304 pub start: SpannedExpr,
305 pub end: SpannedExpr,
306 pub step: Option<SpannedExpr>,
307 }
308