Rust · 7792 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 type_spec: Option<super::decl::TypeSpec>,
200 items: Vec<SpannedExpr>,
201 opts: Vec<IoControl>,
202 },
203 Deallocate {
204 items: Vec<SpannedExpr>,
205 opts: Vec<IoControl>,
206 },
207 Nullify {
208 items: Vec<SpannedExpr>,
209 },
210
211 // ---- Other executable ----
212 Continue {
213 label: Option<u64>,
214 },
215 Call {
216 callee: SpannedExpr,
217 args: Vec<crate::ast::expr::Argument>,
218 },
219 Print {
220 format: SpannedExpr,
221 items: Vec<SpannedExpr>,
222 },
223 Namelist {
224 groups: Vec<(String, Vec<String>)>,
225 },
226
227 // ---- Declaration (embedded in statement context) ----
228 Declaration(SpannedDecl),
229 }
230
231 /// I/O control specifier: either a positional value or keyword=value pair.
232 /// Used for WRITE/READ control lists, OPEN/CLOSE/INQUIRE specifiers, and
233 /// ALLOCATE options (stat=, errmsg=, source=, mold=).
234 #[derive(Debug, Clone, PartialEq)]
235 pub struct IoControl {
236 pub keyword: Option<String>,
237 pub value: SpannedExpr,
238 }
239
240 // ---- Supporting types ----
241
242 /// A type guard in SELECT TYPE.
243 #[derive(Debug, Clone, PartialEq)]
244 pub enum TypeGuard {
245 /// TYPE IS (type_name) — exact type match.
246 TypeIs {
247 type_name: String,
248 body: Vec<SpannedStmt>,
249 },
250 /// CLASS IS (type_name) — matches type or any extension.
251 ClassIs {
252 type_name: String,
253 body: Vec<SpannedStmt>,
254 },
255 /// CLASS DEFAULT — fallback.
256 ClassDefault { body: Vec<SpannedStmt> },
257 }
258
259 /// A CASE block: case selector + body.
260 #[derive(Debug, Clone, PartialEq)]
261 pub struct CaseBlock {
262 pub selectors: Vec<CaseSelector>,
263 pub body: Vec<SpannedStmt>,
264 }
265
266 /// A CASE selector: single value, range, or default.
267 #[derive(Debug, Clone, PartialEq)]
268 pub enum CaseSelector {
269 Value(SpannedExpr),
270 Range {
271 low: Option<SpannedExpr>,
272 high: Option<SpannedExpr>,
273 },
274 Default,
275 }
276
277 /// DO CONCURRENT locality specification (F2018).
278 #[derive(Debug, Clone, PartialEq)]
279 pub enum LocalitySpec {
280 /// LOCAL(var_list) — private to each iteration.
281 Local(Vec<String>),
282 /// LOCAL_INIT(var_list) — private, initialized from outer scope.
283 LocalInit(Vec<String>),
284 /// SHARED(var_list) — shared across iterations.
285 Shared(Vec<String>),
286 /// DEFAULT(NONE) — all variables must be explicitly specified.
287 DefaultNone,
288 /// REDUCE(op: var_list) — reduction variable.
289 Reduce { op: String, vars: Vec<String> },
290 }
291
292 /// DO CONCURRENT control: `i = 1:n`
293 #[derive(Debug, Clone, PartialEq)]
294 pub struct ConcurrentControl {
295 pub var: String,
296 pub start: SpannedExpr,
297 pub end: SpannedExpr,
298 pub step: Option<SpannedExpr>,
299 }
300
301 /// FORALL specification: `i = 1:n:step`
302 #[derive(Debug, Clone, PartialEq)]
303 pub struct ForallSpec {
304 pub var: String,
305 pub start: SpannedExpr,
306 pub end: SpannedExpr,
307 pub step: Option<SpannedExpr>,
308 }
309