Skip to content
Snippets Groups Projects
Commit 7ed8e17f authored by Per Lindgren's avatar Per Lindgren
Browse files

passes syntax

parent 93adf16b
No related branches found
No related tags found
No related merge requests found
fn main() {
let a = {
let b = 1;
b
};
}
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 };
}
# Rust Syntax
As it turns out Rust syntax is a bit tricky to parse.
Consider the following program (`examples/syntax.rs`):
``` Rust
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 };
}
```
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.
- `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.
## An example grammar
The example grammar in `ast/parser.lalrpop` covers a minimal subset of Rust, sufficient to parse the given `syntax.rs` example. Each action merely produces a unit result (no AST is built).
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.)
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
- `;` is treated as a `stmt`, hence we allow *blocks* like `{; let a=5; let b=6;;;;;}`
- "let" Id "=" Expr ";"
......@@ -19,23 +19,12 @@ pub fn read(file_name: &str) -> std::io::Result<String> {
Ok(contents)
}
// pub fn parse(file_name: &str) -> Program {
// let p = read(file_name).expect("File not found");
// ProgramParser::new().parse(&p).unwrap()
// }
pub fn parse(file_name: &str) {
let p = read(file_name).expect("File not found");
FunctionParser::new().parse(&p).unwrap()
}
#[test]
fn t1() {
let s = "
{
let a = {
let b = 1 + 1;
;
if a { }
b
}
}
";
StmtsParser::new().parse(s).unwrap();
fn syntax() {
parse("examples/syntax3.rs");
}
......@@ -14,15 +14,60 @@ match {
_
}
//pub Expr: ()
pub Function: () = {
"fn" Id Params ("->" Type)? Stmts => (),
}
pub Params: () = {
"()" => (), // seems like a haxx
"(" ((Param ",")* Param)? ")" => (),
}
pub Param:() = {
Id ":" Type,
}
pub Type:() = {
"i32" => (),
"bool" => (),
"()" => (),
}
pub Stmts: () = {
"{" Stmt* "}" => (),
}
pub ExprStmt: () = {
"if" Expr Stmts "else" Stmts => (),
Stmts => (),
}
pub Stmt: () = {
";" => (),
"let" Id "=" Expr ";" => (),
ExprNoBlock "=" Expr => (),
"if" Expr Stmts ("else" Stmts)? => (),
ExprNoBlock => (),
Stmts => (),
}
pub Expr: () = {
ExprStmt => (),
ExprNoBlock => (),
}
pub ExprNoBlock: () = {
Expr AddSub Factor => (),
Factor => (),
ExprNoBlock Cmp Expr1 => (),
Expr1 => (),
}
pub Cmp: () = {
"<" => ()
}
pub Expr1: () = {
Expr1 AddSub Expr2 => (),
Expr2 => (),
}
pub AddSub: () = {
......@@ -30,8 +75,8 @@ pub AddSub: () = {
"-" => (),
}
pub Factor: () = {
Factor MulDiv Term => (),
pub Expr2: () = {
Expr2 MulDiv Term => (),
Term => (),
}
......@@ -43,33 +88,16 @@ pub MulDiv: () = {
pub Term: () = {
Id => (),
Num => (),
"(" Expr ")" => (),
}
pub ExprStmt: () = {
"if" Expr Stmts "else" Stmts => (),
Stmts => (),
}
pub Stmts: () = {
"{" Stmt* "}" => (),
}
pub Stmt: () = {
";" => (),
"let" Id "=" Expr => (),
"if" Expr Stmts ("else" Stmts)? => (),
ExprNoBlock => (),
Stmts => (),
}
pub Num: i32 = {
r"[0-9]+" => i32::from_str(<>).unwrap(),
};
pub Id: String = {
r"([a-z]|[A-Z])([a-z]|[A-Z]|[0-9]|_)*" => String::from_str(<>).unwrap(),
r"(_|[a-z]|[A-Z])([a-z]|[A-Z]|[0-9]|_)*" => String::from_str(<>).unwrap(),
};
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment