summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rust/src/ast.rs2
-rw-r--r--rust/src/parser.rs41
2 files changed, 39 insertions, 4 deletions
diff --git a/rust/src/ast.rs b/rust/src/ast.rs
index 722e9e0..8729fa2 100644
--- a/rust/src/ast.rs
+++ b/rust/src/ast.rs
@@ -7,6 +7,7 @@ pub enum Value {
Sym(String),
App(Box<Value>, Box<Value>),
Lam(String, Box<Value>),
+ Def(String, Box<Value>),
}
impl Display for Value {
@@ -17,6 +18,7 @@ impl Display for Value {
Value::Sym(s) => write!(f, "{}", s),
Value::App(l, r) => write!(f, "({} {})", l, r),
Value::Lam(var, body) => write!(f, "(lam {} {})", var, body),
+ Value::Def(var, value) => write!(f, "(def {} {})", var, value),
}
}
}
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()
}
}