summaryrefslogtreecommitdiff
path: root/rust/src
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/ast.rs2
-rw-r--r--rust/src/parser.rs30
2 files changed, 30 insertions, 2 deletions
diff --git a/rust/src/ast.rs b/rust/src/ast.rs
index b179704..0493f59 100644
--- a/rust/src/ast.rs
+++ b/rust/src/ast.rs
@@ -5,6 +5,7 @@ pub enum Value {
Num(i32),
Bool(bool),
Sym(String),
+ App(Box<Value>, Box<Value>),
}
impl Display for Value {
@@ -13,6 +14,7 @@ impl Display for Value {
Value::Num(i) => write!(f, "{}", i),
Value::Bool(b) => write!(f, "{}", b),
Value::Sym(s) => write!(f, "{}", s),
+ Value::App(l, r) => write!(f, "({} {})", l, r),
}
}
}
diff --git a/rust/src/parser.rs b/rust/src/parser.rs
index 50cf918..8f95ca9 100644
--- a/rust/src/parser.rs
+++ b/rust/src/parser.rs
@@ -8,8 +8,27 @@ enum Token {
}
pub fn parse(arg: &str) -> Value {
- let tokens = tokenize(arg);
- parse_value(&tokens[0]).unwrap()
+ let mut tokens = tokenize(arg);
+ let mut state = Vec::new();
+ parse_tokens(&mut tokens, &mut state).unwrap()
+}
+
+fn parse_tokens(tokens: &mut [Token], state: &mut Vec<Value>) -> Result<Value, String> {
+ match tokens {
+ [] => state.pop().ok_or("Empty expression".to_string()),
+ [Token::LParen, rest @ ..] => parse_tokens(rest, state),
+ [Token::RParen, rest @ ..] => {
+ let right = state.pop().ok_or("Unbalanced parentheses".to_string())?;
+ let left = state.pop().ok_or("Unbalanced parentheses".to_string())?;
+ state.push(Value::App(Box::new(left), Box::new(right)));
+ parse_tokens(rest, state)
+ }
+ [Token::Word(s), rest @ ..] => {
+ let value = parse_value(&Token::Word(s.clone()))?;
+ state.push(value);
+ parse_tokens(rest, state)
+ }
+ }
}
fn parse_value(token: &Token) -> Result<Value, String> {
@@ -133,6 +152,13 @@ mod tests {
tokenize("( \r() 42) \ntrue( ")
);
}
+
+ #[test]
+ fn parse_application_of_two_values() {
+ assert_eq!(
+ App(Box::new(Sym("foo".to_string())), Box::new(Num(42))),
+ parse("(foo 42)")
+ );
}
impl Arbitrary for Value {