From bfb377f0db4c1b83f1bcf4325a127c9dfb170fe2 Mon Sep 17 00:00:00 2001 From: Per Lindgren <per.lindgren@ltu.se> Date: Sun, 13 Sep 2020 14:53:52 +0200 Subject: [PATCH] fallible iterator, with and without errors --- src/ast/main.rs | 68 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/src/ast/main.rs b/src/ast/main.rs index a669a9b..08deadd 100644 --- a/src/ast/main.rs +++ b/src/ast/main.rs @@ -76,27 +76,45 @@ fn type_check2(stmts: &Stmts) -> Result<Id, Error> { // 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::<_, _, Result<Id, Error>>("".to_string(), |_, stmt| match stmt { - Stmt::Let(id, _) => { - println!("let {} ...", id); - id.to_string(); - Ok(id.to_string()) - } - Stmt::If(_, _, __) => { - println!("if has an error"); - Err(format!("error found in statement {:?}", stmt)) - } - }); + 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"); 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. +// 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() { @@ -108,5 +126,19 @@ fn test_stmts() { ]; println!("type_check {:?}", type_check(&stmts)); println!("type_check2 {:?}", type_check2(&stmts)); - println!("type_check3 {:?}", 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)); } -- GitLab