duskphantom_frontend/parse/
stmt.rs

1// Copyright 2024 Duskphantom Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15// SPDX-License-Identifier: Apache-2.0
16
17use rayon::iter::Either;
18
19use super::*;
20
21pub fn box_stmt(input: &mut &str) -> PResult<Box<Stmt>> {
22    stmt.map(Box::new).parse_next(input)
23}
24
25pub fn vec_stmt(input: &mut &str) -> PResult<Vec<Stmt>> {
26    repeat(0.., stmt).parse_next(input)
27}
28
29/// Expression with semicolon.
30pub fn expr_sc(input: &mut &str) -> PResult<Expr> {
31    (expr, cut_err(token(";")))
32        .map(|(e, _)| e)
33        .parse_next(input)
34}
35
36/// Decl or Expr.
37pub fn decl_or_expr(input: &mut &str) -> PResult<Either<Decl, Expr>> {
38    alt((decl.map(Either::Left), expr_sc.map(Either::Right))).parse_next(input)
39}
40
41pub fn stmt(input: &mut &str) -> PResult<Stmt> {
42    let disp = dispatch! { peek(any);
43        'b' => (token("break"), cut_err(token(";"))).value(Stmt::Break),
44        'c' => (token("continue"), cut_err(token(";"))).value(Stmt::Continue),
45        'i' => (token("if"), cut_err((paren(expr), box_stmt, opt((token("else"), box_stmt)))))
46            .map(|(_, (cond, pass, fail))| Stmt::If(cond, pass, fail.map_or(Stmt::Block(vec![]).into(), |(_, s)| s))),
47        'w' => (token("while"), cut_err((paren(expr), box_stmt))).map(|(_, (cond, body))| Stmt::While(cond, body)),
48        'd' => (token("do"), cut_err((box_stmt, token("while"), paren(expr), token(";"))))
49            .map(|(_, (body, _, cond, _))| Stmt::DoWhile(body, cond)),
50        'r' => (token("return"), cut_err((opt(expr), token(";"))))
51            .map(|(_, (e, _))| Stmt::Return(e)),
52        '{' => curly(cut_err(vec_stmt)).map(Stmt::Block),
53        _ => fail
54    };
55    alt((
56        disp,
57        decl.map(Stmt::Decl),
58        (opt(terminated(expr, token("="))), expr_sc).map(|(lval, expr)| Stmt::Expr(lval, expr)),
59        token(";").value(Stmt::Nothing),
60    ))
61    .parse_next(input)
62}