diff options
Diffstat (limited to 'rust/src/parser.rs')
| -rw-r--r-- | rust/src/parser.rs | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/rust/src/parser.rs b/rust/src/parser.rs index 48ef2e0..d733008 100644 --- a/rust/src/parser.rs +++ b/rust/src/parser.rs @@ -6,8 +6,10 @@ enum Token { RParen, Lambda, Word(String), + Define, } +#[derive(Debug)] struct Parser { tokens: Vec<Token>, index: usize, @@ -55,7 +57,7 @@ pub fn parse(arg: &str) -> Vec<Value> { let mut parser = Parser { tokens, index: 0 }; let mut result = Vec::new(); while parser.index < parser.tokens.len() { - let expr = parse_expression(&mut parser) + let expr = parse_toplevel(&mut parser) .map_err(|e| panic!("Syntax error: {}", e)) .unwrap(); result.push(expr); @@ -63,6 +65,23 @@ pub fn parse(arg: &str) -> Vec<Value> { result } +fn parse_toplevel(parser: &mut Parser) -> Result<Value, String> { + parse_definition(parser).or_else(|_| parse_expression(parser)) +} + +fn parse_definition(parser: &mut Parser) -> Result<Value, String> { + parser.expect(Token::LParen)?; + parser.expect(Token::Define).map_err(|e| { + parser.backtrack(); + e.to_string() + })?; + println!("parser {:?}", parser); + let var = parse_variable(parser)?; + let body = parse_expression(parser)?; + parser.expect(Token::RParen)?; + Ok(Value::Def(var, Box::new(body))) +} + fn parse_expression(parser: &mut Parser) -> Result<Value, String> { parse_abstraction(parser) .or_else(|_| parse_application(parser)) @@ -130,6 +149,8 @@ fn terminate(result: &mut Vec<Token>, word: &mut String) { let w = word.clone(); if w == "lam" { result.push(Token::Lambda); + } else if w == "def" { + result.push(Token::Define); } else { result.push(Token::Word(w)); } @@ -251,6 +272,14 @@ mod tests { } #[test] + fn parse_definition() { + assert_eq!( + vec![Def("x".to_string(), Box::new(Num(12)))], + parse("(def x 12)") + ); + } + + #[test] fn parse_multiple_values() { assert_eq!(vec![Sym("foo".to_string()), Num(42)], parse("foo 42")); } @@ -267,12 +296,16 @@ mod tests { // see https://unicode.org/reports/tr18/#General_Category_Property for one letter unicode categories identifier.prop_map(Sym), ]; - leaf.prop_recursive(4, 128, 5, move |inner| { + let expr = leaf.prop_recursive(4, 128, 5, move |inner| { prop_oneof![ (inner.clone(), inner.clone()).prop_map(|(l, r)| App(Box::new(l), Box::new(r))), - (identifier, inner).prop_map(|(var, body)| Lam(var, Box::new(body))), + (identifier, inner.clone()).prop_map(|(var, body)| Lam(var, Box::new(body))), ] - }) + }); + prop_oneof![ + expr.clone(), + (identifier, expr).prop_map(|(var, body)| Def(var, Box::new(body))) + ] .boxed() } } |
