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