summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ast.rs2
-rw-r--r--src/parser.rs2
-rw-r--r--src/simple.rs32
-rw-r--r--tests/test_execution.rs21
4 files changed, 42 insertions, 15 deletions
diff --git a/src/ast.rs b/src/ast.rs
index 4bbc7ed..68522ce 100644
--- a/src/ast.rs
+++ b/src/ast.rs
@@ -25,7 +25,7 @@ pub type Value = u64;
pub enum Type {
Empty,
Unit,
- Bool,
+ Boolean,
Natural,
Integer,
// Float,
diff --git a/src/parser.rs b/src/parser.rs
index 2f918a8..719ee3f 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -34,7 +34,7 @@ pub fn parse_str(input: &str) -> Result<Expression, peg::error::ParseError<peg::
match k.as_str() {
"empty" => Type::Empty,
"unit" => Type::Unit,
- "bool" => Type::Bool,
+ "bool" => Type::Boolean,
"nat" => Type::Natural,
"int" => Type::Integer,
_ => panic!("invalid type"), // fixme: raise an error
diff --git a/src/simple.rs b/src/simple.rs
index 9393c00..b7ef94a 100644
--- a/src/simple.rs
+++ b/src/simple.rs
@@ -12,27 +12,33 @@ pub fn check(context: Context, expression: Expression) {
/// Evaluates an expression given a context (of variables) to a term.
/// Panics on non-evaluatable code.
-pub fn execute(context: Context, expression: Expression) -> Term {
+pub fn execute(context: Context, expression: Expression) -> Result<Term, &'static str> {
match expression {
- Expression::Annotation { expr, .. } => return execute(context, *expr),
- Expression::Constant { term } => return term,
- Expression::Variable { id } => return context[&id],
- Expression::Abstraction { .. } => panic!("attempting to execute an abstraction"),
+ Expression::Annotation { expr, .. } => execute(context, *expr),
+ Expression::Constant { term } => Ok(term),
+ Expression::Variable { id } => context.get(&id).ok_or("no such variable in context").map(|x| *x),
+ Expression::Abstraction { .. } => Err("attempting to execute an abstraction"),
Expression::Application { func, arg } => {
match *func {
Expression::Abstraction { param, func } => {
- let mut context = context;
- context.insert(param, execute(context.clone(), *arg));
- return execute(context, *func);
+ let result = execute(context.clone(), *arg);
+ match result {
+ Ok(value) => {
+ let mut context = context;
+ context.insert(param, value);
+ return execute(context, *func);
+ },
+ Err(e) => Err(e)
+ }
},
- _ => panic!("attempting to execute an application to nothing")
+ _ => Err("attempting to execute an application to nothing")
}
},
Expression::Conditional { if_cond, if_then, if_else } => {
- match execute(context.clone(), *if_cond).val {
- 1 => execute(context, *if_then),
- 0 => execute(context, *if_else),
- _ => panic!("invalid type for a conditional")
+ match execute(context.clone(), *if_cond) {
+ Ok(Term { val: 1, .. }) => execute(context, *if_then),
+ Ok(Term { val: 0, .. }) => execute(context, *if_else),
+ _ => Err("invalid type for a conditional")
}
},
}
diff --git a/tests/test_execution.rs b/tests/test_execution.rs
new file mode 100644
index 0000000..dd1b038
--- /dev/null
+++ b/tests/test_execution.rs
@@ -0,0 +1,21 @@
+use chrysanthemum::ast::*;
+use chrysanthemum::simple::*;
+use chrysanthemum::util::*;
+
+#[test]
+fn test_simple() {
+ assert_eq!(execute(Context::new(), Const(0, Type::Boolean)), Ok(Term(0, Type::Boolean)));
+ assert_eq!(execute(Context::new(), Const(123, Type::Natural)), Ok(Term(123, Type::Natural)));
+ assert_eq!(execute(Context::new(), Const(123, Type::Integer)), Ok(Term(123, Type::Integer)));
+ assert!(execute(Context::new(), Var("x")).is_err());
+}
+
+#[test]
+fn test_complex() {
+ let mut context = Context::new();
+ context.insert(String::from("x"), Term(413, Type::Natural));
+ context.insert(String::from("y"), Term(1, Type::Boolean));
+ assert_eq!(execute(context.clone(), Var("x")), Ok(Term(413, Type::Natural)));
+ assert_eq!(execute(context.clone(), Cond(Var("y"), Const(612, Type::Integer), Var("x"))), Ok(Term(612, Type::Integer)));
+ assert_eq!(execute(context.clone(), App(Abs("z", Cond(Const(0, Type::Boolean), Var("x"), Var("z"))), Const(1025, Type::Integer))), Ok(Term(1025, Type::Integer)));
+}