diff --git a/examples/syntax.rs b/examples/syntax.rs index f328e4d9d04c31d0d70d16d21a07d1613be9d577..7aa9378691b1b116117e3e864d8179a9cfd50f46 100644 --- a/examples/syntax.rs +++ b/examples/syntax.rs @@ -1 +1,16 @@ -fn main() {} +fn main() { + let a = false; + + let a = { + let b = 1 + 1; + // extra `;` are allowed + if a {} // no trialing `;` + b // return value + }; + + while false { + // do something here + } + + let _b = if a < 5 { 1 } else { 2 }; +} diff --git a/examples/syntax4.rs b/examples/syntax4.rs new file mode 100644 index 0000000000000000000000000000000000000000..938345d9d2d9263c0c5135e95a6431c2aa671f25 --- /dev/null +++ b/examples/syntax4.rs @@ -0,0 +1,7 @@ +fn a(a: i32, mut b: bool) { + let a = 5; + + while b {} +} + +fn main() {} diff --git a/src/ast/README.md b/src/ast/README.md index 7820fae9047656124704656bad5a75db52706623..0796d8699f1e75178b0dd9ee64d5c487dff2e5cc 100644 --- a/src/ast/README.md +++ b/src/ast/README.md @@ -22,12 +22,13 @@ fn main() { } ``` -At the top level, we have 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. +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. Inside a *block*, statements are typically separated by `;`, with the following exceptions. - `if` statements, and -- `while` statements may omit the trailing `;`. +- `while` statements may omit the trailing `;`, and +- `{ ... }` inner blocks. Additionally Rust allows for additional `;` in between statements (but extra `;` are considered non-idiomatic and thus removed by `rustfmt`). @@ -39,6 +40,8 @@ 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. + - 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.) Recall that a statement can be a return value, thus must somehow accept an expression. Now, here is the crux, since we want `if then else` and `blocks` (statements) to be treated as expression for assignments, it would cause ambiguities between statements as part of an expression or inside a *block*. We can resolve this by the adopting `ExprNoBlock`, inside of `stmt`. `ExprNoBlock` accepts expression besides those that are matched by `ExprBlock` (`if then else` and `block`). diff --git a/src/ast/main.rs b/src/ast/main.rs index c5c7a4a6934e7366e980eeeba329719a3bedec1f..cd28e1165e3ed5ac7af077be6798307777e33664 100644 --- a/src/ast/main.rs +++ b/src/ast/main.rs @@ -37,3 +37,8 @@ fn syntax2() { fn syntax3() { parse("examples/syntax3.rs"); } + +#[test] +fn syntax4() { + parse("examples/syntax4.rs"); +} diff --git a/src/ast/parser.lalrpop b/src/ast/parser.lalrpop index d011793644df38ba18ac8e48353c849371014fff..cdbf819db1dedbe03093f203b5c485ce214699e0 100644 --- a/src/ast/parser.lalrpop +++ b/src/ast/parser.lalrpop @@ -54,8 +54,7 @@ Type:() = { } Block: () = { - "{" StmtSeq* "}", - "{" StmtSeq* Stmt "}", + "{" StmtSeq* Stmt? "}", } StmtSeq: () = { @@ -131,8 +130,6 @@ UnaryOp: () = { "&" "mut", } - - Num: i32 = { r"[0-9]+" => i32::from_str(<>).unwrap(), };