1#![allow(unused_variables)]
4
5use std::sync::Arc;
6
7use gramatika::{Parse, ParseStreamer, Spanned, SpannedError, Token as _};
8
9use crate::{
10 decl::VarDecl,
11 expr::{Expr, IdentExpr},
12 parser::ErrorRecoveringParseStream,
13 token::{brace, keyword, punct},
14 ParseStream, Span, Token, TokenKind,
15};
16
17#[allow(clippy::large_enum_variant)] #[derive(Clone, DebugLisp)]
19pub enum Stmt {
20 Block(BlockStmt),
21 Return(ReturnStmt),
22 If(IfStmt),
23 Switch(SwitchStmt),
24 Loop(LoopStmt),
25 Continuing(ContinuingStmt),
26 For(ForStmt),
27 Var(VarDecl),
28 Break(KeywordStmt),
29 Continue(KeywordStmt),
30 Discard(KeywordStmt),
31 Fallthrough(KeywordStmt),
32 Expr(ExprStmt),
33 Empty(Token),
34}
35
36#[derive(Clone, DebugLisp)]
37pub struct BlockStmt {
38 pub brace_open: Token,
39 pub stmts: Arc<[Stmt]>,
40 pub brace_close: Token,
41}
42
43#[derive(Clone, DebugLisp)]
44pub struct ReturnStmt {
45 pub keyword: Token,
46 pub value: Option<Expr>,
47 pub semicolon: Token,
48}
49
50#[derive(Clone, DebugLisp)]
51pub struct IfStmt {
52 pub keyword: Token,
53 pub condition: Expr,
54 pub then_branch: BlockStmt,
55 pub else_branch: Option<ElseStmt>,
56}
57
58#[derive(Clone, DebugLisp)]
59pub struct ElseStmt {
60 pub keyword: Token,
61 pub body: Arc<Stmt>,
62}
63
64#[derive(Clone, DebugLisp)]
65pub struct SwitchStmt {
66 pub keyword: Token,
67 pub subject: Expr,
68 pub body: SwitchBody,
69}
70
71#[derive(Clone, DebugLisp)]
72pub struct SwitchBody {
73 pub brace_open: Token,
74 pub cases: Arc<[CaseStmt]>,
75 pub brace_close: Token,
76}
77
78#[derive(Clone, DebugLisp)]
79pub struct CaseStmt {
80 pub keyword: Token,
81 pub selectors: Arc<[Expr]>,
82 pub body: BlockStmt,
83}
84
85#[derive(Clone, DebugLisp)]
86pub struct LoopStmt {
87 pub keyword: Token,
88 pub body: BlockStmt,
89}
90
91#[derive(Clone, DebugLisp)]
92pub struct ContinuingStmt {
93 pub keyword: Token,
94 pub body: BlockStmt,
95}
96
97#[derive(Clone, DebugLisp)]
98pub struct ForStmt {
99 pub keyword: Token,
100 pub initializer: Option<Arc<Stmt>>,
101 pub condition: Option<Arc<Stmt>>,
102 pub increment: Option<Expr>,
103 pub body: BlockStmt,
104}
105
106#[derive(Clone, DebugLisp)]
107pub struct KeywordStmt {
108 pub keyword: Token,
109 pub semicolon: Token,
110}
111
112#[derive(Clone, DebugLisp)]
113pub struct ExprStmt {
114 pub expr: Expr,
115 pub semicolon: Token,
116}
117
118impl Parse for Stmt {
121 type Stream = ParseStream;
122
123 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
124 use TokenKind::*;
125
126 match input.peek() {
127 #[rustfmt::skip]
128 Some(token) => match token.as_matchable() {
129 (Keyword, "return", _) => Ok(Stmt::Return(input.parse()?)),
130 (Keyword, "if", _) => Ok(Stmt::If(input.parse()?)),
131 (Keyword, "switch", _) => Ok(Stmt::Switch(input.parse()?)),
132 (Keyword, "loop", _) => Ok(Stmt::Loop(input.parse()?)),
133 (Keyword, "continuing", _) => Ok(Stmt::Continuing(input.parse()?)),
134 (Keyword, "for", _) => Ok(Stmt::For(input.parse()?)),
135 (Keyword, "const" |"var" | "let", _) => Ok(Stmt::Var(input.parse()?)),
136 (Keyword, "break", _) => Ok(Stmt::Break(input.parse()?)),
137 (Keyword, "continue", _) => Ok(Stmt::Continue(input.parse()?)),
138 (Keyword, "discard", _) => Ok(Stmt::Discard(input.parse()?)),
139 (Keyword, "fallthrough", _) => Ok(Stmt::Fallthrough(input.parse()?)),
140 (Brace, "{", _) => Ok(Stmt::Block(input.parse()?)),
141 (Punct, ";", _) => Ok(Stmt::Empty(input.next().unwrap())),
142 _ => Ok(Stmt::Expr(input.parse()?)),
143 },
144 None => Err(SpannedError {
145 message: "Unexpected end of input".into(),
146 source: input.source(),
147 span: input.prev().map(|token| token.span()),
148 }),
149 }
150 }
151}
152
153impl Spanned for Stmt {
154 fn span(&self) -> Span {
155 use Stmt::*;
156
157 match self {
158 Block(inner) => inner.span(),
159 Return(inner) => inner.span(),
160 If(inner) => inner.span(),
161 Switch(inner) => inner.span(),
162 Loop(inner) => inner.span(),
163 Continuing(inner) => inner.span(),
164 For(inner) => inner.span(),
165 Var(inner) => inner.span(),
166 Break(inner) => inner.span(),
167 Continue(inner) => inner.span(),
168 Discard(inner) => inner.span(),
169 Fallthrough(inner) => inner.span(),
170 Expr(inner) => inner.span(),
171 Empty(inner) => inner.span(),
172 }
173 }
174}
175
176impl Parse for BlockStmt {
177 type Stream = ParseStream;
178
179 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
180 let brace_open = input.consume(brace!["{"])?;
181 let stmts = input.parse_seq(|input| !input.check(brace!["}"]));
182 let brace_close = input.consume(brace!["}"])?;
183
184 Ok(Self {
185 brace_open,
186 stmts: stmts.into(),
187 brace_close,
188 })
189 }
190}
191
192impl Spanned for BlockStmt {
193 fn span(&self) -> Span {
194 self.brace_open.span().through(self.brace_close.span())
195 }
196}
197
198impl Parse for ReturnStmt {
199 type Stream = ParseStream;
200
201 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
202 let keyword = input.consume(keyword![return])?;
203
204 if input.check(punct![;]) {
205 let semicolon = input.consume(punct![;])?;
206
207 Ok(Self {
208 keyword,
209 value: None,
210 semicolon,
211 })
212 } else {
213 let value = input.parse::<Expr>()?;
214 let semicolon = input.consume(punct![;])?;
215
216 Ok(Self {
217 keyword,
218 value: Some(value),
219 semicolon,
220 })
221 }
222 }
223}
224
225impl Spanned for ReturnStmt {
226 fn span(&self) -> Span {
227 self.keyword.span().through(self.semicolon.span())
228 }
229}
230
231impl Parse for IfStmt {
232 type Stream = ParseStream;
233
234 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
235 let keyword = input.consume_kind(TokenKind::Keyword)?;
236 let condition = input.parse::<Expr>()?;
237 let then_branch = input.parse::<BlockStmt>()?;
238
239 let else_branch = if input.check(keyword![else]) {
240 Some(input.parse::<ElseStmt>()?)
241 } else {
242 None
243 };
244
245 Ok(Self {
246 keyword,
247 condition,
248 then_branch,
249 else_branch,
250 })
251 }
252}
253
254impl Spanned for IfStmt {
255 fn span(&self) -> Span {
256 let end_span = self
257 .else_branch
258 .as_ref()
259 .map(|stmt| stmt.span())
260 .unwrap_or_else(|| self.then_branch.span());
261
262 self.keyword.span().through(end_span)
263 }
264}
265
266impl Parse for ElseStmt {
267 type Stream = ParseStream;
268
269 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
270 let keyword = input.consume(keyword![else])?;
271 let body = Arc::new(input.parse::<Stmt>()?);
272
273 Ok(Self { keyword, body })
274 }
275}
276
277impl Spanned for ElseStmt {
278 fn span(&self) -> Span {
279 self.keyword.span().through(self.body.span())
280 }
281}
282
283impl Parse for SwitchStmt {
284 type Stream = ParseStream;
285
286 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
287 let keyword = input.consume(keyword![switch])?;
288 let subject = input.parse::<Expr>()?;
289 let body = input.parse::<SwitchBody>()?;
290
291 Ok(Self {
292 keyword,
293 subject,
294 body,
295 })
296 }
297}
298
299impl Spanned for SwitchStmt {
300 fn span(&self) -> Span {
301 self.keyword.span().through(self.body.span())
302 }
303}
304
305impl Parse for SwitchBody {
306 type Stream = ParseStream;
307
308 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
309 use TokenKind::*;
310
311 let brace_open = input.consume(brace!["{"])?;
312
313 let mut cases = vec![];
314
315 while !input.check(brace!["}"]) {
316 match input.peek() {
317 Some(token) => match token.as_matchable() {
318 (Keyword, "case" | "default", _) => cases.push(input.parse::<CaseStmt>()?),
319 (_, _, span) => {
320 return Err(SpannedError {
321 message: "Expected `case` or `default`".into(),
322 span: Some(span),
323 source: input.source(),
324 })
325 }
326 },
327 None => {
328 return Err(SpannedError {
329 message: "Unexpected end of input".into(),
330 source: input.source(),
331 span: input.prev().map(|token| token.span()),
332 })
333 }
334 };
335 }
336
337 let brace_close = input.consume(brace!["}"])?;
338
339 Ok(Self {
340 brace_open,
341 cases: cases.into(),
342 brace_close,
343 })
344 }
345}
346
347impl Spanned for SwitchBody {
348 fn span(&self) -> Span {
349 self.brace_open.span().through(self.brace_close.span())
350 }
351}
352
353impl Parse for CaseStmt {
354 type Stream = ParseStream;
355
356 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
357 use TokenKind::*;
358
359 let keyword = match input.next() {
360 Some(token) => match token.as_matchable() {
361 (Keyword, "case" | "default", _) => token,
362 (_, _, span) => {
363 return Err(SpannedError {
364 message: "Expected `case` or `default`".into(),
365 source: input.source(),
366 span: Some(span),
367 });
368 }
369 },
370 None => {
371 return Err(SpannedError {
372 message: "Unexpected end of input".into(),
373 source: input.source(),
374 span: input.prev().map(|token| token.span()),
375 });
376 }
377 };
378
379 let mut selectors = vec![];
380 while !input.check(punct![:]) && !input.check(brace!["{"]) {
381 if input.check(keyword![default]) {
382 selectors.push(Expr::Ident(IdentExpr::Leaf(input.next().unwrap())));
383 } else {
384 selectors.push(input.parse()?);
385 }
386
387 if !input.check(punct![:]) && !input.check(brace!["{"]) {
388 input.consume(punct![,])?;
389 }
390 }
391
392 if input.check(punct![:]) {
393 input.consume(punct![:])?;
394 }
395
396 let body = input.parse::<BlockStmt>()?;
397
398 Ok(Self {
399 keyword,
400 selectors: selectors.into(),
401 body,
402 })
403 }
404}
405
406impl Spanned for CaseStmt {
407 fn span(&self) -> Span {
408 self.keyword.span().through(self.body.span())
409 }
410}
411
412impl Parse for LoopStmt {
413 type Stream = ParseStream;
414
415 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
416 let keyword = input.consume(keyword![loop])?;
417 let body = input.parse::<BlockStmt>()?;
418
419 Ok(Self { keyword, body })
420 }
421}
422
423impl Spanned for LoopStmt {
424 fn span(&self) -> Span {
425 self.keyword.span().through(self.body.span())
426 }
427}
428
429impl Parse for ContinuingStmt {
430 type Stream = ParseStream;
431
432 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
433 let keyword = input.consume(keyword![continuing])?;
434 let body = input.parse::<BlockStmt>()?;
435
436 Ok(Self { keyword, body })
437 }
438}
439
440impl Spanned for ContinuingStmt {
441 fn span(&self) -> Span {
442 self.keyword.span().through(self.body.span())
443 }
444}
445
446impl Parse for ForStmt {
447 type Stream = ParseStream;
448
449 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
450 let keyword = input.consume(keyword![for])?;
451 input.consume(brace!["("])?;
452
453 let mut initializer = None;
454 let mut condition = None;
455 let mut increment = None;
456
457 let mut semis = 0u8;
458
459 while !input.check(brace![")"]) {
460 match input.peek() {
461 Some(token) => match semis {
462 0 => {
463 initializer = Some(Arc::new(input.parse::<Stmt>()?));
464 semis += 1;
465 }
466 1 => {
467 condition = Some(Arc::new(input.parse::<Stmt>()?));
468 semis += 1;
469 }
470 2 => increment = Some(input.parse::<Expr>()?),
471 _ => {
472 return Err(SpannedError {
473 message: "Expected `)`".into(),
474 span: Some(token.span()),
475 source: input.source(),
476 })
477 }
478 },
479 None => {
480 return Err(SpannedError {
481 message: "Unexpected end of input".into(),
482 source: input.source(),
483 span: input.prev().map(|token| token.span()),
484 })
485 }
486 };
487 }
488
489 input.consume(brace![")"])?;
490 let body = input.parse::<BlockStmt>()?;
491
492 Ok(Self {
493 keyword,
494 initializer,
495 condition,
496 increment,
497 body,
498 })
499 }
500}
501
502impl Spanned for ForStmt {
503 fn span(&self) -> Span {
504 self.keyword.span().through(self.body.span())
505 }
506}
507
508impl Parse for KeywordStmt {
509 type Stream = ParseStream;
510
511 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
512 let keyword = input.consume_kind(TokenKind::Keyword)?;
513 let semicolon = input.consume(punct![;])?;
514
515 Ok(Self { keyword, semicolon })
516 }
517}
518
519impl Spanned for KeywordStmt {
520 fn span(&self) -> Span {
521 self.keyword.span().through(self.semicolon.span())
522 }
523}
524
525impl Parse for ExprStmt {
526 type Stream = ParseStream;
527
528 fn parse(input: &mut Self::Stream) -> gramatika::Result<Self> {
529 let expr = input.parse::<Expr>()?;
530 let semicolon = input.consume(punct![;])?;
531
532 Ok(Self { expr, semicolon })
533 }
534}
535
536impl Spanned for ExprStmt {
537 fn span(&self) -> Span {
538 self.expr.span().through(self.semicolon.span())
539 }
540}