diff options
| author | Arnaud Bailly <arnaud.bailly@iohk.io> | 2024-09-25 13:30:24 +0200 |
|---|---|---|
| committer | Arnaud Bailly <arnaud.bailly@iohk.io> | 2024-09-25 13:30:24 +0200 |
| commit | 90dfe422f9c7058bebde0abf7eb3c7675c8fbf66 (patch) | |
| tree | fd55e6f04cf89da5f924154124eaf8c0a763f832 /rust/src/parser.rs | |
| parent | 7263237a7e2a3dcfb19978e3ebae022a8f2cb0b8 (diff) | |
| download | lambda-nantes-90dfe422f9c7058bebde0abf7eb3c7675c8fbf66.tar.gz | |
Introduce let-expressions
Diffstat (limited to 'rust/src/parser.rs')
| -rw-r--r-- | rust/src/parser.rs | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/rust/src/parser.rs b/rust/src/parser.rs index d733008..b065ec3 100644 --- a/rust/src/parser.rs +++ b/rust/src/parser.rs @@ -7,6 +7,7 @@ enum Token { Lambda, Word(String), Define, + Let, } #[derive(Debug)] @@ -84,6 +85,7 @@ fn parse_definition(parser: &mut Parser) -> Result<Value, String> { fn parse_expression(parser: &mut Parser) -> Result<Value, String> { parse_abstraction(parser) + .or_else(|_| parse_let(parser)) .or_else(|_| parse_application(parser)) .or_else(|_| parse_value(parser)) } @@ -105,6 +107,21 @@ fn parse_variable(parser: &mut Parser) -> Result<String, String> { Ok(var) } +fn parse_let(parser: &mut Parser) -> Result<Value, String> { + parser.expect(Token::LParen)?; + parser.expect(Token::Let).map_err(|e| { + parser.backtrack(); + e.to_string() + })?; + parser.expect(Token::LParen)?; + let var = parse_variable(parser)?; + let body = parse_expression(parser)?; + parser.expect(Token::RParen)?; + let expr = parse_expression(parser)?; + parser.expect(Token::RParen)?; + Ok(Value::Let(var, Box::new(body), Box::new(expr))) +} + fn parse_application(parser: &mut Parser) -> Result<Value, String> { parser.expect(Token::LParen)?; let left = parse_expression(parser)?; @@ -151,6 +168,8 @@ fn terminate(result: &mut Vec<Token>, word: &mut String) { result.push(Token::Lambda); } else if w == "def" { result.push(Token::Define); + } else if w == "let" { + result.push(Token::Let); } else { result.push(Token::Word(w)); } @@ -284,6 +303,18 @@ mod tests { assert_eq!(vec![Sym("foo".to_string()), Num(42)], parse("foo 42")); } + #[test] + fn parse_let_expressions() { + assert_eq!( + vec![Value::Let( + "x".to_string(), + Box::new(Num(12)), + Box::new(Sym("x".to_string())) + )], + parse("(let (x 12) x)") + ); + } + impl Arbitrary for Value { type Parameters = (); type Strategy = BoxedStrategy<Self>; @@ -300,6 +331,9 @@ mod tests { prop_oneof![ (inner.clone(), inner.clone()).prop_map(|(l, r)| App(Box::new(l), Box::new(r))), (identifier, inner.clone()).prop_map(|(var, body)| Lam(var, Box::new(body))), + (identifier, inner.clone(), inner.clone()).prop_map(|(var, body, expr)| { + Value::Let(var, Box::new(body), Box::new(expr)) + }), ] }); prop_oneof