summaryrefslogtreecommitdiff
path: root/rust/src/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src/parser.rs')
-rw-r--r--rust/src/parser.rs34
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![