nifty_syntax/parser/
stmt.rs1use super::expr::TrailingBlocks;
4use super::{ParseResult, Parser, Reported};
5use crate::ast::{AssignOp, Block, ElseBranch, IfStmt, Iterable, Stmt, StmtKind};
6use crate::token::TokenKind;
7
8impl Parser<'_> {
9 pub(super) fn parse_block(&mut self) -> ParseResult<Block> {
10 let start = self.expect(TokenKind::LBrace)?.span.start;
11 let mut stmts = Vec::new();
12 loop {
13 self.skip_newlines();
14 match self.peek() {
15 TokenKind::RBrace => {
16 self.bump();
17 break;
18 }
19 TokenKind::Eof => return self.unexpected("`}`"),
20 _ => match self.parse_stmt() {
21 Ok(stmt) => {
22 stmts.push(stmt);
23 self.finish_line();
24 }
25 Err(Reported) => self.recover_to_line_end(),
26 },
27 }
28 }
29 Ok(Block {
30 stmts,
31 span: self.span_from(start),
32 })
33 }
34
35 pub(super) fn parse_stmt(&mut self) -> ParseResult<Stmt> {
36 let start = self.current().span.start;
37 let kind = match self.peek() {
38 TokenKind::Let => self.parse_let()?,
39 TokenKind::If => StmtKind::If(self.parse_if()?),
40 TokenKind::For => self.parse_for()?,
41 TokenKind::Return => self.parse_return()?,
42 _ => self.parse_expr_or_assign()?,
43 };
44 Ok(Stmt {
45 kind,
46 span: self.span_from(start),
47 })
48 }
49
50 fn parse_let(&mut self) -> ParseResult<StmtKind> {
51 self.bump();
52 let name = self.expect_ident()?;
53 let ty = self.parse_type_annotation()?;
54 self.expect(TokenKind::Eq)?;
55 let value = self.parse_expr(TrailingBlocks::Allowed)?;
56 Ok(StmtKind::Let { name, ty, value })
57 }
58
59 fn parse_if(&mut self) -> ParseResult<IfStmt> {
60 self.bump();
61 let condition = self.parse_expr(TrailingBlocks::Forbidden)?;
62 let then_block = self.parse_block()?;
63 let else_branch = match self.eat(TokenKind::Else) {
64 None => None,
65 Some(_) if self.at(TokenKind::If) => Some(ElseBranch::If(Box::new(self.parse_if()?))),
66 Some(_) => Some(ElseBranch::Block(self.parse_block()?)),
67 };
68 Ok(IfStmt {
69 condition,
70 then_block,
71 else_branch,
72 })
73 }
74
75 fn parse_for(&mut self) -> ParseResult<StmtKind> {
76 self.bump();
77 let first = self.expect_ident()?;
78 let (mut index, item) = match self.eat(TokenKind::Comma) {
79 Some(_) => (Some(first), self.expect_ident()?),
80 None => (None, first),
81 };
82 self.expect(TokenKind::In)?;
83 let iterable = self.parse_iterable()?;
84 if let (Some(extra), Iterable::Range { .. }) = (&index, &iterable) {
85 self.report(
86 format!(
87 "a range loop has no separate index; `{}` already counts, as in `for {} in 0..n`",
88 item.name, item.name
89 ),
90 extra.span,
91 );
92 index = None;
93 }
94 let body = self.parse_block()?;
95 Ok(StmtKind::For {
96 index,
97 item,
98 iterable,
99 body,
100 })
101 }
102
103 fn parse_iterable(&mut self) -> ParseResult<Iterable> {
104 let start = self.parse_expr(TrailingBlocks::Forbidden)?;
105 if self.eat(TokenKind::DotDot).is_none() {
106 return Ok(Iterable::List(start));
107 }
108 let end = self.parse_expr(TrailingBlocks::Forbidden)?;
109 Ok(Iterable::Range { start, end })
110 }
111
112 fn parse_return(&mut self) -> ParseResult<StmtKind> {
113 self.bump();
114 let value = match self.peek() {
115 TokenKind::Newline | TokenKind::RBrace | TokenKind::Eof => None,
116 _ => Some(self.parse_expr(TrailingBlocks::Allowed)?),
117 };
118 Ok(StmtKind::Return(value))
119 }
120
121 fn parse_expr_or_assign(&mut self) -> ParseResult<StmtKind> {
122 let target = self.parse_expr(TrailingBlocks::Allowed)?;
123 let Some(op) = assign_op(self.peek()) else {
124 return Ok(StmtKind::Expr(target));
125 };
126 self.bump();
127 self.skip_newlines();
128 let value = self.parse_expr(TrailingBlocks::Allowed)?;
129 Ok(StmtKind::Assign { target, op, value })
130 }
131}
132
133fn assign_op(kind: TokenKind) -> Option<AssignOp> {
134 Some(match kind {
135 TokenKind::Eq => AssignOp::Set,
136 TokenKind::PlusEq => AssignOp::Add,
137 TokenKind::MinusEq => AssignOp::Sub,
138 TokenKind::StarEq => AssignOp::Mul,
139 TokenKind::SlashEq => AssignOp::Div,
140 _ => return None,
141 })
142}