aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/parser.rs14
-rw-r--r--src/util.rs12
-rw-r--r--tests/test_checking.rs51
-rw-r--r--tests/test_execution.rs20
-rw-r--r--tests/test_parser.rs18
5 files changed, 69 insertions, 46 deletions
diff --git a/src/parser.rs b/src/parser.rs
index 8eac52d..d6eb69d 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -29,12 +29,17 @@ pub fn parse_lambda(input: &str) -> Result<Expression, peg::error::ParseError<pe
// this is kinda awful, i miss my simple nim pegs
peg::parser! {
grammar lambda() for str {
- rule ident() -> String
- = i:['a'..='z' | 'A'..='Z' | '0'..='9']+ {
+ rule ident() -> String = i:['a'..='z' | 'A'..='Z' | '0'..='9']+ {
i.iter().collect::<String>()
}
- rule cons() -> Expression
- = p:"-"? c:['0'..='9']+ {
+ rule bool() -> Expression = b:$("true" / "false") {
+ match b {
+ "true" => Expression::Constant { term: Term::Boolean(true) },
+ "false" => Expression::Constant { term: Term::Boolean(false) },
+ _ => Expression::Constant { term: Term::Unit() }
+ }
+ }
+ rule num() -> Expression = p:"-"? c:['0'..='9']+ {
let value = c.iter().collect::<String>().parse::<usize>().unwrap();
Expression::Constant {
term: if let Some(_) = p {
@@ -44,6 +49,7 @@ pub fn parse_lambda(input: &str) -> Result<Expression, peg::error::ParseError<pe
}
}
}
+ rule cons() -> Expression = c:(bool() / num())
rule primitive() -> Type
= k:$("empty" / "unit" / "bool" / "nat" / "int") {
match k {
diff --git a/src/util.rs b/src/util.rs
index 70bd8e4..4b47afc 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -65,3 +65,15 @@ pub const Unit: Type = Type::Unit;
pub const Bool: Type = Type::Boolean;
pub const Nat: Type = Type::Natural;
pub const Int: Type = Type::Integer;
+
+pub fn Float(term: f32) -> Term {
+ return Term::Float(term)
+}
+
+pub fn Str(len: usize, cap: usize, data: Vec<usize>) -> Term {
+ return Term::String { len, cap, data }
+}
+
+pub fn Enum(val: usize, data: Vec<Type>) -> Term {
+ return Term::Enum { val, data }
+}
diff --git a/tests/test_checking.rs b/tests/test_checking.rs
index a4b5fd3..286283b 100644
--- a/tests/test_checking.rs
+++ b/tests/test_checking.rs
@@ -7,14 +7,14 @@ use chrysanthemum::util::*;
// rust you KNOW these are &'static strs
const sanity_check: &'static str = "413: int";
-const negate: &'static str = "(λx. if x then 0 else 1): (bool -> bool)";
+const negate: &'static str = "(λx. if x then false else true): (bool -> bool)";
const basic_abstraction: &'static str = "(λx. x): (int -> int)";
const basic_application: &'static str = "((λx. x): (int -> int)) 413";
const correct_cond_abs: &'static str = "(λx. if x then 1 else 0): (bool -> int)";
-const correct_cond: &'static str = "if 0 then 1: nat else 0: nat";
+const correct_cond: &'static str = "if false then 1: nat else 0: nat";
const not_inferrable: &'static str = "(λx. (λy. (λz. if x then y else z)))";
-const incorrect_branches: &'static str = "if 0: bool then 1: bool else 2: int";
-const incorrect_cond_abs: &'static str = "(λx. if x then 1: bool else 0: bool): (int -> bool)";
+const incorrect_branches: &'static str = "if false: bool then true: bool else 2: int";
+const incorrect_cond_abs: &'static str = "(λx. if x then true: bool else false: bool): (int -> bool)";
#[test]
fn test_parsing_succeeds() {
@@ -31,31 +31,34 @@ fn test_parsing_succeeds() {
#[test]
fn test_inference() {
- assert_eq!(infer(Context::new(), parse_lambda(sanity_check).unwrap()), Ok(Int));
- assert_eq!(infer(Context::new(), parse_lambda(negate).unwrap()), Ok(Func(Bool, Bool)));
- assert_eq!(infer(Context::new(), parse_lambda(basic_abstraction).unwrap()), Ok(Func(Int, Int)));
- assert_eq!(infer(Context::new(), parse_lambda(basic_application).unwrap()), Ok(Int));
- assert_eq!(infer(Context::new(), parse_lambda(correct_cond_abs).unwrap()), Ok(Func(Bool, Int)));
- assert_eq!(infer(Context::new(), parse_lambda(correct_cond).unwrap()), Ok(Nat));
- assert!(infer(Context::new(), parse_lambda(not_inferrable).unwrap()).is_err());
- assert!(infer(Context::new(), parse_lambda(incorrect_branches).unwrap()).is_err());
- assert!(infer(Context::new(), parse_lambda(incorrect_cond_abs).unwrap()).is_err());
+ let context = Context::new();
+ assert_eq!(infer(&context, parse_lambda(sanity_check).unwrap()), Ok(Int));
+ assert_eq!(infer(&context, parse_lambda(negate).unwrap()), Ok(Func(Bool, Bool)));
+ assert_eq!(infer(&context, parse_lambda(basic_abstraction).unwrap()), Ok(Func(Int, Int)));
+ assert_eq!(infer(&context, parse_lambda(basic_application).unwrap()), Ok(Int));
+ assert_eq!(infer(&context, parse_lambda(correct_cond_abs).unwrap()), Ok(Func(Bool, Int)));
+ assert_eq!(infer(&context, parse_lambda(correct_cond).unwrap()), Ok(Nat));
+ assert!(infer(&context, parse_lambda(not_inferrable).unwrap()).is_err());
+ assert!(infer(&context, parse_lambda(incorrect_branches).unwrap()).is_err());
+ assert!(infer(&context, parse_lambda(incorrect_cond_abs).unwrap()).is_err());
}
#[test]
fn test_checking() {
+ let context = Context::new();
+
// uninteresting
- assert!(check(Context::new(), parse_lambda(sanity_check).unwrap(), Int).is_ok());
- assert!(check(Context::new(), parse_lambda(negate).unwrap(), Func(Bool, Bool)).is_ok());
- assert!(check(Context::new(), parse_lambda(basic_abstraction).unwrap(), Func(Int, Int)).is_ok());
- assert!(check(Context::new(), parse_lambda(basic_application).unwrap(), Int).is_ok());
- assert!(check(Context::new(), parse_lambda(correct_cond_abs).unwrap(), Func(Bool, Int)).is_ok());
- assert!(check(Context::new(), parse_lambda(correct_cond).unwrap(), Nat).is_ok());
- assert!(check(Context::new(), parse_lambda(incorrect_branches).unwrap(), Unit).is_err());
- assert!(check(Context::new(), parse_lambda(incorrect_cond_abs).unwrap(), Error).is_err());
+ assert!(check(&context, parse_lambda(sanity_check).unwrap(), &Int).is_ok());
+ assert!(check(&context, parse_lambda(negate).unwrap(), &Func(Bool, Bool)).is_ok());
+ assert!(check(&context, parse_lambda(basic_abstraction).unwrap(), &Func(Int, Int)).is_ok());
+ assert!(check(&context, parse_lambda(basic_application).unwrap(), &Int).is_ok());
+ assert!(check(&context, parse_lambda(correct_cond_abs).unwrap(), &Func(Bool, Int)).is_ok());
+ assert!(check(&context, parse_lambda(correct_cond).unwrap(), &Nat).is_ok());
+ assert!(check(&context, parse_lambda(incorrect_branches).unwrap(), &Unit).is_err());
+ assert!(check(&context, parse_lambda(incorrect_cond_abs).unwrap(), &Error).is_err());
// more fun
- assert!(check(Context::new(), parse_lambda(not_inferrable).unwrap(), Func(Bool, Func(Int, Func(Int, Int)))).is_ok());
- assert!(check(Context::new(), parse_lambda(not_inferrable).unwrap(), Func(Bool, Func(Nat, Func(Nat, Nat)))).is_ok());
- assert!(check(Context::new(), parse_lambda(not_inferrable).unwrap(), Func(Bool, Func(Unit, Func(Unit, Unit)))).is_ok());
+ assert!(check(&context, parse_lambda(not_inferrable).unwrap(), &Func(Bool, Func(Int, Func(Int, Int)))).is_ok());
+ assert!(check(&context, parse_lambda(not_inferrable).unwrap(), &Func(Bool, Func(Nat, Func(Nat, Nat)))).is_ok());
+ assert!(check(&context, parse_lambda(not_inferrable).unwrap(), &Func(Bool, Func(Unit, Func(Unit, Unit)))).is_ok());
}
diff --git a/tests/test_execution.rs b/tests/test_execution.rs
index 5aeac19..d9b1c5e 100644
--- a/tests/test_execution.rs
+++ b/tests/test_execution.rs
@@ -4,18 +4,20 @@ use chrysanthemum::util::*;
#[test]
fn test_simple() {
- assert_eq!(execute(Context::new(), Const(0)), Ok(Term(0, Empty)));
- assert_eq!(execute(Context::new(), Const(123)), Ok(Term(123, Empty)));
- assert_eq!(execute(Context::new(), Const(123)), Ok(Term(123, Empty)));
- assert!(execute(Context::new(), Var("x")).is_err());
+ let context = Context::new();
+ assert_eq!(execute(&context, Const(Term::Boolean(false))), Ok(Term::Boolean(false)));
+ assert_eq!(execute(&context, Const(Term::Natural(123))), Ok(Term::Natural(123)));
+ assert_eq!(execute(&context, Const(Term::Integer(123))), Ok(Term::Integer(123)));
+ assert!(execute(&context, Var("x")).is_err());
}
#[test]
fn test_complex() {
let mut context = Context::new();
- context.insert(String::from("x"), Term(413, Empty));
- context.insert(String::from("y"), Term(1, Empty));
- assert_eq!(execute(context.clone(), Var("x")), Ok(Term(413, Empty)));
- assert_eq!(execute(context.clone(), Cond(Var("y"), Const(612), Var("x"))), Ok(Term(612, Empty)));
- assert_eq!(execute(context.clone(), App(Abs("z", Cond(Const(0), Var("x"), Var("z"))), Const(1025))), Ok(Term(1025, Empty)));
+ context.insert(String::from("x"), Term::Natural(413));
+ context.insert(String::from("y"), Term::Boolean(true));
+ assert_eq!(execute(&context, Var("x")), Ok(Term::Natural(413)));
+ assert_eq!(execute(&context, Cond(Var("y"), Const(Term::Integer(612)), Var("x"))), Ok(Term::Integer(612)));
+ assert_eq!(execute(&context,
+ App(Abs("z", Cond(Const(Term::Boolean(false)), Var("x"), Var("z"))), Const(Term::Integer(1025)))), Ok(Term::Integer(1025)));
}
diff --git a/tests/test_parser.rs b/tests/test_parser.rs
index a7d15f8..f305483 100644
--- a/tests/test_parser.rs
+++ b/tests/test_parser.rs
@@ -6,7 +6,7 @@ use chrysanthemum::util::*;
#[test]
fn test_simple_phrases() {
- assert_eq!(parse_lambda("123"), Ok(Const(123)));
+ assert_eq!(parse_lambda("-123"), Ok(Const(Term::Integer(-123))));
assert_eq!(parse_lambda("x12"), Ok(Var("x12")));
assert_eq!(parse_lambda("x12x2"), Ok(Var("x12x2")));
// so i _don't_ want these to be valid identifiers:
@@ -18,7 +18,7 @@ fn test_simple_phrases() {
#[test]
fn test_simple_annotations() {
assert_eq!(parse_lambda("t: int"), Ok(Ann(Var("t"), Int)));
- assert_eq!(parse_lambda("12: nat"), Ok(Ann(Const(12), Nat)));
+ assert_eq!(parse_lambda("12: nat"), Ok(Ann(Const(Term::Natural(12)), Nat)));
assert!(parse_lambda("t: fake").is_err());
}
@@ -33,22 +33,22 @@ fn test_simple_expressions() {
assert_eq!(parse_lambda("(λx.y) x"), Ok(App(Abs("x", Var("y")), Var("x"))));
assert_eq!(parse_lambda("if x then y else z"), Ok(Cond(Var("x"), Var("y"), Var("z"))));
assert_eq!(parse_lambda("if xeme then yak else zebra"), Ok(Cond(Var("xeme"), Var("yak"), Var("zebra"))));
- assert_eq!(parse_lambda("if 413 then 612 else 1025"), Ok(Cond(Const(413), Const(612), Const(1025)))); // invalid, but should parse
+ assert_eq!(parse_lambda("if 413 then 612 else 1025"), Ok(Cond(Const(Term::Natural(413)), Const(Term::Natural(612)), Const(Term::Natural(1025))))); // invalid, but should parse
}
#[test]
fn test_complex_expressions() {
- assert_eq!(parse_lambda("(λy.if y then 0 else 1) z"), Ok(App(Abs("y", Cond(Var("y"), Const(0), Const(1))), Var("z"))));
+ assert_eq!(parse_lambda("(λy.if y then false else true) z"), Ok(App(Abs("y", Cond(Var("y"), Const(Term::Boolean(false)), Const(Term::Boolean(true)))), Var("z"))));
}
#[test]
fn test_complex_annotations() {
assert_eq!(parse_lambda("(lambda x . y) : int"), Ok(Ann(Abs("x", Var("y")), Int)));
- assert_eq!(parse_lambda("((lambda x. y): (int -> int)) 413: int"), Ok(App(Ann(Abs("x", Var("y")), Func(Int, Int) ), Ann(Const(413), Int))));
- assert_eq!(parse_lambda("if 0: bool then 1: bool else 2: int"), Ok(Cond(Ann(Const(0), Bool), Ann(Const(1), Bool), Ann(Const(2), Int))));
- assert_eq!(parse_lambda("(lambda x. if x then 1: bool else 0: bool): (int -> bool)"), Ok(Ann(Abs("x", Cond(Var("x"), Ann(Const(1), Bool), Ann(Const(0), Bool))), Func(Int, Bool))));
- assert_eq!(parse_lambda("(lambda x. if x then 1: int else 0: int): (bool -> int)"), Ok(Ann(Abs("x", Cond(Var("x"), Ann(Const(1), Int), Ann(Const(0), Int))), Func(Bool, Int))));
- assert_eq!(parse_lambda("(lambda x. if x then 0 else 1): (bool -> bool)"), Ok(Ann(Abs("x", Cond(Var("x"), Const(0), Const(1))), Func(Bool, Bool))));
+ assert_eq!(parse_lambda("((lambda x. y): (int -> int)) -413: int"), Ok(App(Ann(Abs("x", Var("y")), Func(Int, Int) ), Ann(Const(Term::Integer(-413)), Int))));
+ assert_eq!(parse_lambda("if false: bool then true: bool else 2: int"), Ok(Cond(Ann(Const(Term::Boolean(false)), Bool), Ann(Const(Term::Boolean(true)), Bool), Ann(Const(Term::Natural(2)), Int))));
+ assert_eq!(parse_lambda("(lambda x. if x then true: bool else false: bool): (int -> bool)"), Ok(Ann(Abs("x", Cond(Var("x"), Ann(Const(Term::Boolean(true)), Bool), Ann(Const(Term::Boolean(false)), Bool))), Func(Int, Bool))));
+ assert_eq!(parse_lambda("(lambda x. if x then 1: int else 0: int): (bool -> int)"), Ok(Ann(Abs("x", Cond(Var("x"), Ann(Const(Term::Natural(1)), Int), Ann(Const(Term::Natural(0)), Int))), Func(Bool, Int))));
+ assert_eq!(parse_lambda("(lambda x. if x then false else true): (bool -> bool)"), Ok(Ann(Abs("x", Cond(Var("x"), Const(Term::Boolean(false)), Const(Term::Boolean(true)))), Func(Bool, Bool))));
}
const program: &'static str =