From eabfc31bfbb7ce761909c7815a087b5fc10bfc99 Mon Sep 17 00:00:00 2001 From: Per Lindgren <per.lindgren@ltu.se> Date: Tue, 15 Sep 2020 00:22:45 +0200 Subject: [PATCH] epic fail --- src/ast/ast.rs | 26 -------- src/ast/main.rs | 137 ++--------------------------------------- src/ast/parser.lalrpop | 39 ++++++++++-- 3 files changed, 40 insertions(+), 162 deletions(-) diff --git a/src/ast/ast.rs b/src/ast/ast.rs index 9daa62a..b750a43 100644 --- a/src/ast/ast.rs +++ b/src/ast/ast.rs @@ -3,29 +3,3 @@ use std::fmt; // ast pub type Id = String; - -// println!("{:?}", ..) -#[derive(Debug, Clone)] -pub enum NumOrId { - Num(i32), - Id(Id), -} - -// println!("{}", ..) -impl fmt::Display for NumOrId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - NumOrId::Num(i) => write!(f, "{}", i)?, - NumOrId::Id(s) => write!(f, "{}", s)?, - }; - Ok(()) - } -} - -pub type Stmts = Vec<Stmt>; - -#[derive(Debug, Clone)] -pub enum Stmt { - Let(Id, NumOrId), - If(Id, Stmts, Option<Stmts>), -} diff --git a/src/ast/main.rs b/src/ast/main.rs index 08deadd..0eb05e3 100644 --- a/src/ast/main.rs +++ b/src/ast/main.rs @@ -8,137 +8,12 @@ pub mod ast; use ast::*; fn main() { - println!("minimal"); - println!("{:?}", NumOrIdParser::new().parse("123")); - println!("{:?}", NumOrIdParser::new().parse("a1_a")); - - println!("{}", NumOrIdParser::new().parse("123").unwrap()); - println!("{}", NumOrIdParser::new().parse("a1_a").unwrap()); -} - -#[test] -fn parse_num_or_id() { - assert_eq!( - format!("{}", NumOrIdParser::new().parse("123").unwrap()), - "123" - ); - assert_eq!( - format!("{}", NumOrIdParser::new().parse("a1_a").unwrap()), - "a1_a" - ); -} - -type Error = String; - -fn type_check(stmts: &Stmts) -> Result<Id, Error> { - let mut last_id = "".to_string(); - let mut err: Option<Stmt> = None; - stmts.iter().for_each(|stmt| match stmt { - Stmt::Let(id, _) => { - println!("let {} ...", id); - last_id = id.to_string(); - } - Stmt::If(_, _, __) => { - println!("if has an error"); - err = Some(stmt.clone()); - } - }); - println!("here we can do something before returning"); - match err { - Some(stmt) => Err(format!("error found in statement {:?}", stmt)), - None => Ok(last_id), - } -} -// the above is not ideal, since we have to do a lot of book keeping, -// also we cannot easily "abort", and thus we cont. even after spotting the error we want to return - -fn type_check2(stmts: &Stmts) -> Result<Id, Error> { - let mut last_id = "".to_string(); - let res: Result<Id, Error> = stmts - .iter() - .try_for_each(|stmt| match stmt { - Stmt::Let(id, _) => { - println!("let {} ...", id); - last_id = id.to_string(); - Ok(()) - } - Stmt::If(_, _, __) => { - println!("if has an error"); - Err(format!("error found in statement {:?}", stmt)) - } - }) - .map(|_| Ok(last_id))?; - println!("here we can do something before returning"); - res -} -// this is quite good, we can get rid of some book keeping, and we iterate only up to the point where an error occurs. -// we have to convert the Ok(()) into the last Id (using Result::map) -// IMHO Result::map should have been named map_ok, since that is what is does, and symmetric to map_err. - -fn type_check3(stmts: &Stmts) -> Result<Id, Error> { - let res = stmts.iter().try_fold("".to_string(), |_, stmt| match stmt { - Stmt::Let(id, _) => { - println!("let {} ...", id); - Ok(id.to_string()) - } - Stmt::If(_, _, __) => { - println!("if has an error"); - Err(format!("error found in statement {:?}", stmt)) + let s = " + { + let ; + ; } - }); - - println!("here we can do something before returning"); - res -} -// this is likely as good as it gets using Rust. -// the `try_fold`, aborts on an error directly. -// we need to give an initial value for the accumulator ("".to_string()) -// in this case we don't accumulate, so the first closure parameter is discarded (`_`) -// instead we just overwrite the accumatore with the latest seen identifier. - -fn type_check4(stmts: &Stmts) -> Result<Id, Error> { - let res = stmts - .iter() - .try_fold("".to_string(), |_, stmt| match stmt { - Stmt::Let(id, _) => { - println!("let {} ...", id); - Ok(id.to_string()) - } - Stmt::If(_, _, __) => { - println!("if has an error"); - Err(format!("error found in statement {:?}", stmt)) - } - })?; - - println!("here we can do something before returning"); - Ok(res) -} -// A slight alternation av type_check3, here we make an early return -// Notice that the type of `res` has changed. - -#[test] -fn test_stmts() { - let stmts = vec![ - Stmt::Let("a".to_string(), NumOrId::Num(1)), - Stmt::Let("b".to_string(), NumOrId::Num(2)), - Stmt::If("b".to_string(), Stmts::new(), None), - Stmt::Let("c".to_string(), NumOrId::Num(3)), - ]; - println!("type_check {:?}", type_check(&stmts)); - println!("type_check2 {:?}", type_check2(&stmts)); - println!("type_check3 {:?}", type_check3(&stmts)); - println!("type_check4 {:?}", type_check4(&stmts)); -} + "; -#[test] -fn test_stmts_without_error() { - let stmts = vec![ - Stmt::Let("a".to_string(), NumOrId::Num(1)), - Stmt::Let("b".to_string(), NumOrId::Num(2)), - Stmt::Let("c".to_string(), NumOrId::Num(3)), - ]; - println!("type_check {:?}", type_check(&stmts)); - println!("type_check2 {:?}", type_check2(&stmts)); - println!("type_check3 {:?}", type_check3(&stmts)); - println!("type_check4 {:?}", type_check4(&stmts)); + println!("{:?}", BlockExpressionParser::new().parse(s)); } diff --git a/src/ast/parser.lalrpop b/src/ast/parser.lalrpop index 3405c21..95085a6 100644 --- a/src/ast/parser.lalrpop +++ b/src/ast/parser.lalrpop @@ -4,15 +4,44 @@ use crate::ast::*; grammar; -pub NumOrId: NumOrId = { - Num => NumOrId::Num(<>), - Id => NumOrId::Id(<>), +pub ExpressionWithoutBlock: () = { + LiteralExpression => () } - + +pub LiteralExpression = { + Num + Id +} + +ExpressionWithBlock: () = { + BlockExpression => () +} + +pub BlockExpression: ()= { + "{" Statements? "}" => () +} + +pub Statements: () = { + Statement+ => (), + Statement+ ExpressionWithoutBlock => (), + ExpressionWithBlock => () +} + +pub Statement: () = { + ";" => (), + "let" ";" => (), + ExpressionStatement => () +} + +pub ExpressionStatement: () = { + ExpressionWithoutBlock ";" => (), + ExpressionWithBlock ";"? => () +} + 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(), -}; +}; \ No newline at end of file -- GitLab