diff options
Diffstat (limited to 'rust/src/parser.rs')
| -rw-r--r-- | rust/src/parser.rs | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/rust/src/parser.rs b/rust/src/parser.rs index 23a512b..874b893 100644 --- a/rust/src/parser.rs +++ b/rust/src/parser.rs @@ -95,10 +95,30 @@ fn parse_abstraction(parser: &mut Parser) -> Result<Value, String> { parser.backtrack(); e.to_string() })?; - let var = parse_variable(parser)?; + let vars = parse_variables(parser)?; let body = parse_expression(parser)?; parser.expect(Token::RParen)?; - Ok(Value::Lam(var, Box::new(body))) + let result = vars + .iter() + .rev() + .fold(body, |acc, var| Value::Lam(var.clone(), Box::new(acc))); + Ok(result) +} + +fn parse_variables(parser: &mut Parser) -> Result<Vec<String>, String> { + parse_variable(parser) + .map(|s| vec![s]) + .or_else(|_| parse_variables_list(parser)) +} + +fn parse_variables_list(parser: &mut Parser) -> Result<Vec<String>, String> { + let mut vars = Vec::new(); + parser.expect(Token::LParen)?; + while let Ok(var) = parse_variable(parser) { + vars.push(var); + } + parser.expect(Token::RParen)?; + Ok(vars) } fn parse_variable(parser: &mut Parser) -> Result<String, String> { @@ -290,6 +310,17 @@ mod tests { } #[test] + fn desugar_abstraction_with_several_variables_into_nested_lambdas() { + assert_eq!( + vec![Lam( + "x".to_string(), + Box::new(Lam("y".to_string(), Box::new(Sym("y".to_string())))) + )], + parse("(lam (x y) y)") + ); + } + + #[test] fn parse_definition() { assert_eq!( vec![Def("x".to_string(), Box::new(Num(12)))], |
