aboutsummaryrefslogtreecommitdiff
path: root/src/parse
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse')
-rw-r--r--src/parse/parsetree.rs140
1 files changed, 139 insertions, 1 deletions
diff --git a/src/parse/parsetree.rs b/src/parse/parsetree.rs
index 560ebe7..6d59cf1 100644
--- a/src/parse/parsetree.rs
+++ b/src/parse/parsetree.rs
@@ -4,11 +4,12 @@ use nom::{
Parser,
branch::alt,
multi::many0,
- combinator::all_consuming,
bytes::complete::{tag, take_while1},
character::complete::multispace1,
};
+use crate::sexp::{SExp, SExp::*, SLeaf::*, util::*};
+
#[derive(Debug,PartialEq)]
pub enum Token {
@@ -40,6 +41,12 @@ fn tokenize(s: &str) -> Result<Vec<Token>, String> {
}
}
+
+fn tokens_to_ast(tokens: Vec<Token>) -> Result<SExp, String> {
+ todo!()
+}
+
+
#[cfg(test)]
mod private_parsing_tests {
use super::{*, parse_token};
@@ -76,4 +83,135 @@ mod private_parsing_tests {
);
}
+ #[test]
+ fn test_tokens_to_ast() {
+ // Syms are parsed to vars,
+ // and everything is wrapped in an extra layer of scons
+ // so that multi-expression programs can be returned
+ // as one single SExp.
+ assert_eq!(
+ tokens_to_ast(vec![sym("a")]),
+ Ok(scons(var("a"), Nil))
+ );
+
+ // Lists are pased to scons linked lists
+ assert_eq!(
+ tokens_to_ast(vec![
+ ParOpen,
+ sym("a"), whitespace(" "),
+ sym("b"), whitespace(" "),
+ sym("c"), whitespace(" "),
+ ParClose,
+ ]),
+ Ok(scons(scons(var("a"), scons(var("b"), scons(var("c"), Nil))), Nil))
+ );
+
+ // Nesting should work.
+ assert_eq!(
+ tokens_to_ast(vec![
+ ParOpen,
+ sym("a"), whitespace(" "),
+ ParOpen,
+ sym("b"), whitespace(" "),
+ sym("c"), whitespace(" "),
+ ParClose, whitespace(" "),
+ sym("d"),
+ ParClose
+ ]),
+ Ok(
+ scons(scons(var("a"), scons(
+ scons(var("b"), scons(var("c"), Nil))
+ , scons(var("d"), Nil))), Nil)
+ )
+ );
+
+ // Multiple expressions should be parseable
+ assert_eq!(
+ tokens_to_ast(vec![
+ ParOpen,
+ sym("a"),
+ ParClose,
+ sym("b"),
+ ParOpen,
+ sym("c"),
+ ParClose,
+ ]),
+ Ok(scons(
+ scons(var("a"), Nil),
+ scons(var("b"),
+ scons(scons(var("c"), Nil), Nil))))
+ );
+
+ // Operators are parsed correctly
+ assert_eq!(
+ tokens_to_ast(vec![
+ ParOpen,
+ sym("+"), whitespace(" "),
+ sym("-"), whitespace(" "),
+ sym("*"), whitespace(" "),
+ sym("/"),
+ ParClose
+ ]),
+ Ok(scons(
+ scons(Add,
+ scons(Sub,
+ scons(Mul,
+ scons(Div,
+ Nil)))), Nil))
+ );
+
+ // Integers are parsed correctly
+ assert_eq!(
+ tokens_to_ast(vec![Num(5)]),
+ Ok(scons(Int(5), Nil))
+ );
+
+ // Nil can be parsed
+ assert_eq!(
+ tokens_to_ast(vec![ParOpen,ParClose]),
+ Ok(scons(Nil, Nil))
+ );
+
+ // Quote can be parsed
+ assert_eq!(
+ tokens_to_ast(vec![
+ ParOpen,
+ sym("quote"), whitespace(" "),
+ sym("a"), whitespace(" "),
+ sym("b"), whitespace(" ")
+ ]),
+ Ok(scons(Quote, scons(var("a"), scons(var("b"), Nil))))
+ );
+ }
+
+ #[test]
+ fn test_tokens_to_ast_failing() {
+ assert!(
+ tokens_to_ast(vec![ParClose]).is_err(),
+ "Invalid parentheses should fail"
+ );
+ assert!(
+ tokens_to_ast(vec![ParOpen]).is_err(),
+ "Invalid parentheses should fail"
+ );
+ assert!(
+ tokens_to_ast(vec![ParClose, ParOpen]).is_err(),
+ "Invalid parentheses should fail"
+ );
+ assert!(
+ tokens_to_ast(vec![ParOpen, ParOpen, ParClose]).is_err(),
+ "Invalid parentheses should fail"
+ );
+
+ assert!(
+ tokens_to_ast(vec![Num(1), sym("a")]).is_err(),
+ "Having a symbol starting with a number should fail."
+ );
+
+ assert!(
+ tokens_to_ast(vec![sym("quote"), sym("a")]).is_err(),
+ "There should be whitespace between quote and other symbols"
+ );
+ }
+
}