welly_parser/
stmt.rs

1//! Welly's imperative statements.
2
3use super::{expr, bracket, Tree, Location, Loc, Stream, Context, Parse};
4use expr::{MaybeExpr, Expr, Op};
5use bracket::{Brace};
6
7pub const MISSING_SEMICOLON: &'static str = "Missing `;`";
8pub const MISSING_ELSE_BODY: &'static str = "Missing `else` body";
9pub const MISSING_IF_BODY: &'static str = "Missing `if` body";
10pub const MISSING_LOOP_BODY: &'static str = "Missing loop body";
11pub const MISSING_CASE_BODY: &'static str = "Missing `case` body";
12pub const SPURIOUS_CASE: &'static str = "Unexpected `case` without a preceding `switch`";
13pub const SPURIOUS_ELSE: &'static str = "Unexpected `else` without a preceding `switch`, `if`, `while` or `for`";
14
15// ----------------------------------------------------------------------------
16
17/// Represents a verb keyword.
18///
19/// A `Verb` optionally followed by an [`Expr`] parses as a [`Stmt`].
20#[derive(Debug, Copy, Clone, PartialEq)]
21pub enum Verb { Break, Continue, Return, Throw, Assert, Assume }
22
23/// Represents a statement keyword.
24#[derive(Debug, Copy, Clone, PartialEq)]
25pub enum Keyword { Case, Else, Switch, If, While, For, Verb(Verb) }
26
27impl Tree for Keyword {
28    fn declare_keywords(mut declare: impl FnMut(&'static str, Self)) {
29        declare("case", Self::Case);
30        declare("else", Self::Else);
31        declare("switch", Self::Switch);
32        declare("if", Self::If);
33        declare("while", Self::While);
34        declare("for", Self::For);
35        declare("break", Self::Verb(Verb::Break));
36        declare("continue", Self::Verb(Verb::Continue));
37        declare("return", Self::Verb(Verb::Return));
38        declare("throw", Self::Verb(Verb::Throw));
39        declare("assert", Self::Verb(Verb::Assert));
40        declare("assume", Self::Verb(Verb::Assume));
41    }
42}
43
44/// An assignment operator, e.g. the `+=` in `x += 1;`.
45#[derive(Debug, Copy, Clone, PartialEq)]
46pub enum AssignOp {
47    /// `x = 1` declares the name `x` and initialises it to `1`.
48    Let,
49
50    /// `x := 1` overwrites the value of the name `x` with `1`.
51    Set,
52
53    /// `x += 1` is an abbreviation for `x := x + 1`.
54    Op(Op),
55}
56
57impl Tree for AssignOp {
58    fn declare_keywords(mut declare: impl FnMut(&'static str, Self)) {
59        declare("=", Self::Let);
60        declare(":=", Self::Set);
61        declare("|=", Self::Op(Op::BitOr));
62        declare("^=", Self::Op(Op::BitXor));
63        declare("&=", Self::Op(Op::BitAnd));
64        declare("<<=", Self::Op(Op::SL));
65        declare(">>=", Self::Op(Op::ASR));
66        declare(">>>=", Self::Op(Op::LSR));
67        declare("+=", Self::Op(Op::Add));
68        declare("-=", Self::Op(Op::Sub));
69        declare("*=", Self::Op(Op::Mul));
70        declare("/=", Self::Op(Op::Div));
71        declare("%=", Self::Op(Op::Rem));
72        declare("**=", Self::Op(Op::Pow));
73    }
74}
75
76// ----------------------------------------------------------------------------
77
78/// Represents an `case` clause.
79///
80/// We allow the pattern [`Expr`]s to be `None`, though it's an error.
81#[derive(Debug)]
82pub struct Case(pub Location, pub MaybeExpr, pub Brace);
83
84/// Represents an `else` clause.
85#[derive(Debug)]
86pub struct Else(pub Location, pub Brace);
87
88/// Represents a statement, including the trailing `;` if any.
89///
90/// `Stmt`s frequently contain `Expr`s, and never two consecutively. We allow
91/// every such `Expr` to be optional, so that a later pass can report a helpful
92/// error when it's missing.
93#[derive(Debug)]
94pub enum Stmt {
95    /// E.g. `print("Hello");`.
96    Expr(MaybeExpr),
97
98    /// E.g. `x += 1;`.
99    Assign(MaybeExpr, Loc<AssignOp>, MaybeExpr),
100
101    /// E.g. `if ... {...} else {...}`.
102    ///
103    /// Allow the condition [`Expr`] to be `None`, though it's an error.
104    If(Location, MaybeExpr, Brace, Option<Else>),
105
106    /// E.g. `while ... {...} else {...}`.
107    ///
108    /// Allow the condition [`Expr`] to be `None`, though it's an error.
109    While(Location, MaybeExpr, Brace, Option<Else>),
110
111    /// E.g. `for ... in ... {...} else {...}`.
112    ///
113    /// Allow an arbitrary [`Expr`], or a missing one, though anything but
114    /// `... in ...` is an error.
115    For(Location, MaybeExpr, Brace, Option<Else>),
116
117    /// E.g. `switch ... case ... {...} case ... {...} else {...}`.
118    ///
119    /// Allow the discriminant [`Expr`] to be `None`, though it's an error.
120    Switch(Location, MaybeExpr, Vec<Case>, Option<Else>),
121
122    /// E.g. `return ...;` or `continue;`.
123    ///
124    /// Allow the [`Expr`] to be present or missing, though for some [`Verb`]s
125    /// one of those cases is an error.
126    Verb(Loc<Verb>, MaybeExpr),
127}
128
129impl Tree for Stmt {}
130
131// ----------------------------------------------------------------------------
132
133/// A [`Parse`] implementation that recognises Welly [`Stmt`]s.
134#[derive(Default, Debug)]
135pub struct Parser;
136
137impl Parser {
138    /// Parse `;` otherwise it's an error.
139    fn parse_semicolon(
140        &self,
141        input: &mut Context<impl Stream>,
142    ) -> Result<char, String> {
143        Ok(*input.read_if(|&k| k == ';')?.ok_or(MISSING_SEMICOLON)?)
144    }
145
146    /// Parse `case pattern {...}` if possible.
147    ///
148    /// `case` without `{...}` is an error.
149    fn parse_case(
150        &self,
151        input: &mut Context<impl Stream>,
152    ) -> Result<Option<Case>, String> {
153        let loc = input.last();
154        Ok(if input.read_if(|k| matches!(k, Keyword::Case))?.is_some() {
155            let pattern = input.read::<Expr>()?;
156            let body = input.read::<Brace>()?.ok_or(MISSING_CASE_BODY);
157            Some(Case(loc, pattern, *body?))
158        } else { None })
159    }
160
161    /// Parse `else {...}` if possible.
162    ///
163    /// `else` without `{...}` is an error.
164    fn parse_else(
165        &self,
166        input: &mut Context<impl Stream>,
167    ) -> Result<Option<Else>, String> {
168        Ok(if input.read_if(|k| matches!(k, Keyword::Else))?.is_some() {
169            let loc = input.last();
170            let brace = *input.read::<Brace>()?.ok_or(MISSING_ELSE_BODY)?;
171            Some(Else(loc, brace))
172        } else { None })
173    }
174
175    /// After a keyword, parse `expr {...}` optionally followed by
176    /// `else {...}`.
177    ///
178    /// If the `{...}` is missing it's an error.
179    ///
180    /// - constructor - E.g. `Stmt::If`, `Stmt::While` or `Stmt::For`.
181    /// - missing_body - E.g. `MISSING_IF_BODY` or `MISSING_LOOP_BODY`.
182    fn parse_control(
183        &self,
184        input: &mut Context<impl Stream>,
185        constructor: fn(Location, MaybeExpr, Brace, Option<Else>) -> Stmt,
186        missing_body: &'static str,
187    ) -> Result<Box<dyn Tree>, String> {
188        let loc = input.last();
189        let condition = input.read::<Expr>()?;
190        let body = input.read::<Brace>()?.ok_or(missing_body);
191        let else_ = self.parse_else(input)?;
192        Ok(Box::new(constructor(loc, condition, *body?, else_)))
193    }
194}
195
196impl Parse for Parser {
197    fn parse(
198        &self,
199        input: &mut Context<impl Stream>,
200    ) -> Result<Box<dyn Tree>, String> {
201        if let Some(expr) = input.read::<Expr>()? {
202            if let Some(op) = input.read::<AssignOp>()? {
203                let op = input.locate(*op);
204                let rhs = input.read::<Expr>()?;
205                self.parse_semicolon(input)?;
206                Ok(Box::new(Stmt::Assign(Some(expr), op, rhs)))
207            } else {
208                self.parse_semicolon(input)?;
209                Ok(Box::new(Stmt::Expr(Some(expr))))
210            }
211        } else if let Some(keyword) = input.read::<Keyword>()? {
212            let loc = input.last();
213            match *keyword {
214                Keyword::Case => {
215                    let _ = input.read::<Expr>()?;
216                    let _ = input.read::<Brace>()?;
217                    Err(SPURIOUS_CASE)?
218                },
219                Keyword::Else => {
220                    let _ = input.read::<Brace>()?;
221                    Err(SPURIOUS_ELSE)?
222                },
223                Keyword::Switch => {
224                    let discriminant = input.read::<Expr>()?;
225                    let mut cases = Vec::new();
226                    while let Some(case) = self.parse_case(input)? { cases.push(case); }
227                    let else_ = self.parse_else(input)?;
228                    Ok(Box::new(Stmt::Switch(loc, discriminant, cases, else_)))
229                },
230                Keyword::If => {
231                    self.parse_control(input, Stmt::If, MISSING_IF_BODY)
232                },
233                Keyword::While => {
234                    self.parse_control(input, Stmt::While, MISSING_LOOP_BODY)
235                },
236                Keyword::For => {
237                    self.parse_control(input, Stmt::For, MISSING_LOOP_BODY)
238                },
239                Keyword::Verb(verb) => {
240                    let verb = input.locate(verb);
241                    let expr = input.read::<Expr>()?;
242                    self.parse_semicolon(input)?;
243                    Ok(Box::new(Stmt::Verb(verb, expr)))
244                },
245            }
246        } else if let Some(op) = input.read::<AssignOp>()? {
247            // Parse `+= ...;` as an `Assign` with a missing LHS.
248            let op = input.locate(*op);
249            let rhs = input.read::<Expr>()?;
250            Ok(Box::new(Stmt::Assign(None, op, rhs)))
251        } else if input.read_if::<char>(|&k| k == ';')?.is_some() {
252            // Parse `;` as a missing `Expr`.
253            Ok(Box::new(Stmt::Expr(None)))
254        } else { input.read_any() }
255    }
256}
257
258// ----------------------------------------------------------------------------
259
260#[cfg(test)]
261mod tests {
262    use super::*;
263    use crate::{parsers, EndOfFile, Characters};
264    use bracket::{Round};
265    use parsers::{Brackets};
266
267    /// Parse a [`Stream`] containing [`Brace`]s into [`Round`]s and [`Expr`]s.
268    fn round(input: impl Stream) -> impl Stream {
269        Parser.parse_stream(parsers::EXPR.parse_stream(Brackets::new('(', ')', |contents| {
270            let contents = parsers::EXPR.parse_stream(contents.into_iter()).read_all();
271            Round::new(contents)
272        }, input)))
273    }
274
275    /// Parse a [`Stream`] into [`Brace`]s, [`Round`]s and [`Expr`]s.
276    fn brace(input: impl Stream) -> impl Stream {
277        round(Brackets::new('{', '}', |contents| {
278            let contents = round(contents.into_iter()).read_all();
279            Brace::new(contents)
280        }, input))
281    }
282
283    /// Parse `source` into a [`Stream`] containing [`Stmt`]s.
284    fn parse(source: &'static str) -> impl Stream {
285        let stream = Characters::new(source, true);
286        let stream = parsers::LEXER.parse_stream(stream);
287        let mut word_parser = parsers::Word::default();
288        word_parser.add_keywords::<Keyword>();
289        word_parser.add_keywords::<AssignOp>();
290        let stream = word_parser.parse_stream(stream);
291        brace(stream)
292    }
293
294    /// Parse `source` into a single [`Stmt`].
295    fn parse_one(source: &'static str) -> Box<Stmt> {
296        let mut stream = parse(source);
297        let result = match stream.read().result() {
298            Ok(tree) => match tree.downcast::<Stmt>() {
299                Ok(tree) => tree,
300                Err(tree) => panic!("Got a non-Stmt: {:?}", tree),
301            },
302            Err(e) => panic!("Got error: {:?}", e),
303        };
304        assert_eq!(stream.read(), EndOfFile);
305        result
306    }
307
308    /// Check that `e` is of the form `Some(Expr::Name(expected))`.
309    fn check_name(e: impl Into<MaybeExpr>, expected: &'static str) {
310        match *e.into().expect("Missing Expr::Name") {
311            Expr::Name(observed) => assert_eq!(observed, expected),
312            e => panic!("Expected an Expr::Name but got {:?}", e),
313        }
314    }
315
316    /// Check that `b` is of the form `{ expected; }`.
317    fn check_brace(b: impl Into<Option<Brace>>, expected: &'static str) {
318        let mut contents = b.into().expect("Missing Brace").0.into_iter();
319        match contents.read().unwrap::<Stmt>() {
320            Stmt::Expr(e) => check_name(e, expected),
321            s => panic!("Expected a Stmt::Expr but got {:#?}", s),
322        }
323        assert_eq!(contents.read(), EndOfFile);
324    }
325
326    /// Check that `b` is of the form `{ expected; }`.
327    fn check_else(e: impl Into<Option<Else>>, expected: &'static str) {
328        check_brace(e.into().expect("Missing Else").1, expected);
329    }
330
331    #[test]
332    fn print() {
333        let tree = parse_one("print;");
334        match *tree {
335            Stmt::Expr(e) => check_name(e, "print"),
336            s => panic!("Expected a Stmt::Expr but got {:#?}", s),
337        }
338    }
339
340    #[test]
341    fn assign() {
342        let tree = parse_one("x += 1;");
343        match *tree {
344            Stmt::Assign(left, op, right) => {
345                check_name(left, "x");
346                assert_eq!(op, AssignOp::Op(Op::Add));
347                check_name(right, "1");
348            },
349            s => panic!("Expected a Stmt::Assign but got {:#?}", s),
350        }
351    }
352
353    #[test]
354    fn if_() {
355        let tree = parse_one("if b { foo; } else { bar; }");
356        match *tree {
357            Stmt::If(_, b, then, else_) => {
358                check_name(b, "b");
359                check_brace(then, "foo");
360                check_else(else_, "bar");
361            },
362            s => panic!("Expected a Stmt::If but got {:#?}", s),
363        }
364    }
365
366    #[test]
367    fn switch() {
368        let tree = parse_one("switch d case FOO { foo; } else { bar; }");
369        match *tree {
370            Stmt::Switch(_, d, cases, else_) => {
371                check_name(d, "d");
372                let mut cases = cases.into_iter();
373                match cases.next() {
374                    Some(Case(_, pattern, body)) => {
375                        check_name(pattern, "FOO");
376                        check_brace(body, "foo");
377                    },
378                    _ => panic!("Missing Case"),
379                }
380                assert!(cases.next().is_none());
381                check_else(else_, "bar");
382            },
383            s => panic!("Expected a Stmt::Switch but got {:#?}", s),
384        }
385    }
386
387    #[test]
388    fn break_() {
389        let tree = parse_one("break;");
390        match *tree {
391            Stmt::Verb(verb, None) => assert_eq!(verb, Verb::Break),
392            s => panic!("Expected a Stmt::Verb but got {:#?}", s),
393        }
394    }
395
396    #[test]
397    fn return_() {
398        let tree = parse_one("return 42;");
399        match *tree {
400            Stmt::Verb(verb, ans) => {
401                assert_eq!(verb, Verb::Return);
402                check_name(ans, "42");
403            },
404            s => panic!("Expected a Stmt::Verb but got {:#?}", s),
405        }
406    }
407}