From 4596e47a0c760ff96b551bd4ff55b0d83ff240fd Mon Sep 17 00:00:00 2001
From: Per Lindgren <per.lindgren@ltu.se>
Date: Sat, 19 Sep 2020 22:36:24 +0200
Subject: [PATCH] added mut and updated text

---
 src/ast/README.md      | 16 ++++++++++------
 src/ast/parser.lalrpop | 26 ++++++++++++--------------
 2 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/src/ast/README.md b/src/ast/README.md
index 5416404..7820fae 100644
--- a/src/ast/README.md
+++ b/src/ast/README.md
@@ -22,14 +22,16 @@ 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. Inside a *block*, statements are typically separated by `;`, with the following exceptions.
+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.
+
+Inside a *block*, statements are typically separated by `;`, with the following exceptions. 
 
 - `if` statements, and
 - `while` statements may omit the trailing `;`.
 
 Additionally Rust allows for additional `;` in between statements (but extra `;` are considered non-idiomatic and thus removed by `rustfmt`).
 
-Omitting trailing `;` for the last statement in a block renders an implicit return. This is allowed by the Rust compiler in case the statement can be interpreted as an expression.
+Omitting trailing `;` for the last statement in a *block* renders an implicit return. This is allowed by the Rust compiler in case the statement can be interpreted as an expression.
 
 ## An example grammar
 
@@ -37,12 +39,14 @@ The example grammar in `ast/parser.lalrpop` covers a minimal subset of Rust, suf
 
 Some interesting design decisions:
 
-- We treat statements that may be considered as expressions by a special rule `ExprStmt`, where we accept either `if then else` or a `block`. (This is where we likely add `match` and similar statements later.)
+- 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. A `if then else` statement is one such possible expression. Now, here is the crux, without the  
+  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`).
 
+- `;` is treated as a `stmt`, hence we accept *blocks* like `{; let a = 5;;;;; let b = 6;;; c}`. Notice, `;` carries no meaning besides for the optional trailing `;` of a *block* (determining the return type).
+- `"let" ExprNoBlock "=" Expr ";"`, forces a trailing `;` to each assignment (along the lines of the behavior of the Rust compiler).
 
+## Reflection
 
-- `;` is treated as a `stmt`, hence we allow *blocks* like `{; let a=5; let b=6;;;;;}` 
--  "let" Id "=" Expr ";" 
+The Rust syntax seems somewhat arbitrarily chosen. The requirement that `let` statements must be trailed by `;`, is to my best understanding not required for soundness (the `let` could have been given a `Unit` type, similar to an assignment). This leads me to believe that the trailing `;` is rather an enforcement of style.
 
diff --git a/src/ast/parser.lalrpop b/src/ast/parser.lalrpop
index 4d5db9b..575c6a9 100644
--- a/src/ast/parser.lalrpop
+++ b/src/ast/parser.lalrpop
@@ -15,7 +15,7 @@ match {
 }
 
 pub Function: () = {
-    "fn" Id Params ("->" Type)? Stmts => (),
+    "fn" Id Params ("->" Type)? Block => (),
 }
 
 pub Params: () = {
@@ -33,29 +33,30 @@ pub Type:() = {
     "()" => (),
 }
 
-pub Stmts: () = {
+pub Block: () = {
     "{" Stmt* "}" => (),
 }
 
-pub ExprStmt: () = {
-    "if" Expr Stmts "else" Stmts => (),
-    Stmts => (),
-}
-
 pub Stmt: () = {
     ";" => (),
-    "let" Id "=" Expr ";" => (),
+    "let" "mut"? Id "=" Expr ";" => (),
     ExprNoBlock "=" Expr => (),
-    "if" Expr Stmts ("else" Stmts)? => (),
+    "while" Expr Block => (),
+    "if" Expr Block ("else" Block)? => (),
     ExprNoBlock => (),
-    Stmts => (),
+    Block => (),
 }
 
 pub Expr: () = {
-    ExprStmt => (),
+    ExprBlock => (),
     ExprNoBlock => (),    
 }
 
+pub ExprBlock: () = {
+    "if" Expr Block "else" Block => (),
+    Block => (),
+}
+
 pub ExprNoBlock: () = {
     ExprNoBlock Cmp Expr1 => (),
     Expr1 => (),
@@ -91,9 +92,6 @@ pub Term: () = {
     "(" Expr ")" => (),
 }
 
-
-
-
 pub Num: i32 = {
     r"[0-9]+" => i32::from_str(<>).unwrap(),
 };
-- 
GitLab