diff --git a/examples/syntax.rs b/examples/syntax.rs index 7aa9378691b1b116117e3e864d8179a9cfd50f46..bccecfaff30cf00b7f82475963db79e3dc19eb76 100644 --- a/examples/syntax.rs +++ b/examples/syntax.rs @@ -1,16 +1,27 @@ fn main() { - let a = false; + let a = false; // trailing `;` + // extra `;` are allowed in between statements + + // (1) let a = { let b = 1 + 1; - // extra `;` are allowed + + // (2) if a {} // no trialing `;` - b // return value + b // no trialing `;`, return value }; + // (3) while false { // do something here + } // no trailing `;` + + // (4) + { + // local block/scope } + // (5) let _b = if a < 5 { 1 } else { 2 }; } diff --git a/src/ast/README.md b/src/ast/README.md index 0796d8699f1e75178b0dd9ee64d5c487dff2e5cc..c2504b0b370f514793b54af80cb74dce5a2c686b 100644 --- a/src/ast/README.md +++ b/src/ast/README.md @@ -6,29 +6,41 @@ Consider the following program (`examples/syntax.rs`): ``` Rust fn main() { - let a = false; + let a = false; // trailing `;` + // extra `;` are allowed in between statements + + // (1) let a = { let b = 1 + 1; - // extra `;` are allowed + + // (2) if a {} // no trialing `;` - b // return value + b // no trialing `;`, return value }; + // (3) while false { // do something here + } // no trailing `;` + + // (4) + { + // local block/scope } + + // (5) let _b = if a < 5 { 1 } else { 2 }; } ``` -The *body* of a function is a *block* (sequence of statements). We also see, that the `let` statement accepts a *block* of statements as part of an assignment. Notice, Rust allows allow assignment to refer to the result of an `if then else` construct. As shown in the at the end. +The *body* of a function is a *block* (sequence of statements). The `let` statement accepts a *block* of statements as part of an assignment (1). Rust allows *blocks* to introduce local scopes (4). Rust allows allow assignment to refer to the result of an `if then else` construct (5). Inside a *block*, statements are typically separated by `;`, with the following exceptions. -- `if` statements, and -- `while` statements may omit the trailing `;`, and -- `{ ... }` inner blocks. +- `if` statements (2), +- `while` statements (3), and +- `{ ... }` inner blocks (4). Additionally Rust allows for additional `;` in between statements (but extra `;` are considered non-idiomatic and thus removed by `rustfmt`). @@ -40,7 +52,31 @@ The example grammar in `ast/parser.lalrpop` covers a minimal subset of Rust, suf Some interesting design decisions: -- A *block* of statements is sequence of `;` separated statements followed by an optional trailing statement. +- A *block* of statements is sequence of `;` separated statements followed by an optional trailing statement. `Block` accepts a sequence of statements `StmtSeq*` followed by an optional trailing `Stmt`. `StmtSeq` is either a `Stmt` `;`, or a `StmtBlock`, where the latter cover the case of `while`, `if` and `Block` (nesting/scopes) (without requiring `;` delimiting). We also see that `Stmt` accepts additional `;`. `Stmt` also accepts `ExprNoBlock`. + +``` Rust +Block: () = { + "{" StmtSeq* Stmt? "}", +} + +StmtSeq: () = { + Stmt ";", + StmtBlock, +} + +StmtBlock: () = { + "while" Expr Block, + "if" Expr Block ("else" Block)?, + Block, +} + +Stmt: () = { + ";", + "let" "mut"? Id (":" Type)? "=" Expr, + ExprNoBlock "=" Expr, + ExprNoBlock, +} +``` - We treat statements that may be considered as expressions by a special rule `ExprBlock`, where we accept either `if then else` or a `block` (statments). (This is where we likely add `match` and similar statements later.)