From f5e61572b217c5445c3cd593d1cc94697fa7ec48 Mon Sep 17 00:00:00 2001 From: JJ Date: Wed, 19 Jul 2023 12:25:30 -0700 Subject: major cleanups: switch to dynamic Errors, impl Context, rename enums/records to unions/structs --- src/ast.rs | 181 ++++++++++++++++++++++----------------------- src/bidirectional.rs | 203 ++++++++++++++++++++++++++------------------------- src/classes.rs | 3 - src/main.rs | 8 +- src/parser.rs | 65 +++++++++++------ src/simple.rs | 53 +++++++------- src/util.rs | 4 +- 7 files changed, 266 insertions(+), 251 deletions(-) delete mode 100644 src/classes.rs (limited to 'src') diff --git a/src/ast.rs b/src/ast.rs index bd0d8b4..6bb7171 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,10 +1,10 @@ -// The abstract syntax tree. All supported types go here. - -use core::fmt; use std::collections::HashMap; +pub type Result = core::result::Result>; pub type Identifier = String; -pub type Context = HashMap; + +#[derive(Debug, Clone, PartialEq)] +pub struct Context(HashMap); // note: built-in functions do NOT go here! #[derive(Debug, Clone, PartialEq)] @@ -18,6 +18,7 @@ pub enum Expression { Conditional{if_cond: Box, if_then: Box, if_else: Box} } +/// All supported types. #[derive(Debug, Clone, PartialEq)] pub enum Type { Empty, @@ -28,11 +29,12 @@ pub enum Type { Integer, Float, String, - Enum(Vec), - Record(HashMap), + Union(Vec), + Struct(HashMap), Function{from: Box, to: Box}, } +/// Data associated with a type. #[derive(Debug, Clone, PartialEq)] pub enum Term { Unit(), @@ -41,13 +43,71 @@ pub enum Term { Integer(isize), Float(f32), String{len: usize, cap: usize, data: Vec}, - Enum{val: usize, data: Box}, // is this right? - Record(HashMap), // is this right? + Union{val: usize, data: Box}, // is this right? + Struct(HashMap), // is this right? Function(Box) // this should allow us to bind functions } -impl fmt::Display for Expression { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl Term { + /// Convert a term into its corresponding type. + pub fn convert(&self) -> Result { + match self { + Term::Unit() => Ok(Type::Unit), + Term::Boolean(_) => Ok(Type::Boolean), + Term::Natural(_) => Ok(Type::Natural), + Term::Integer(_) => Ok(Type::Integer), + Term::Float(_) => Ok(Type::Float), + Term::String { len, cap, data } => Ok(Type::String), + Term::Union { val, data } => data.convert(), + Term::Struct(data) => { + let mut result = HashMap::new(); + for (key, val) in data { + result.insert(key.clone(), val.convert()?); + } + return Ok(Type::Struct(result)); + }, + Term::Function(func) => match *func.clone() { + Expression::Annotation { expr, kind } => match kind { + Type::Function { from, to } => Ok(Type::Function { from, to }), + _ => Err("function term value not a function!".into()) + } + _ => Err("function term value does not have an annotation!".into()) + } + } + } +} + +impl Type { + /// Get the default value of a type. Throws an error if it doesn't exist. + pub fn default(&self) -> Result { + match self { + Type::Empty => Err("attempting to take the default term for empty".into()), + Type::Error => Err("attempting to take the default term for error".into()), + Type::Unit => Ok(Term::Unit()), + Type::Boolean => Ok(Term::Boolean(false)), + Type::Natural => Ok(Term::Natural(0)), + Type::Integer => Ok(Term::Integer(0)), + Type::Float => Ok(Term::Float(0.0)), + Type::String => Ok(Term::String { len: 0, cap: 0, data: vec!()}), + Type::Union(data) => match data.len() { + 0 => Err("attempting to get a default term of an enum with no variants!".into()), + _ => Ok(Term::Union { val: 0, data: Box::new(data.get(0).unwrap().default()?) }) + }, + Type::Struct(data) => { + let mut result = HashMap::new(); + for (key, val) in data { + result.insert(key.clone(), val.default()?); + } + return Ok(Term::Struct(result)); + }, + Type::Function { from, to } => + Err("attempting to take the default term of a function type".into()), + } + } +} + +impl core::fmt::Display for Expression { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Expression::Annotation { expr, kind } => write!(f, "({}: {})", expr, kind), Expression::Constant { term } => write!(f, "'{:?}", term), @@ -59,8 +119,8 @@ impl fmt::Display for Expression { } } -impl fmt::Display for Type { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl core::fmt::Display for Type { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Type::Empty => write!(f, "⊤"), Type::Error => write!(f, "⊥"), @@ -70,15 +130,15 @@ impl fmt::Display for Type { Type::Integer => write!(f, "int"), Type::Float => write!(f, "float"), Type::String => write!(f, "str"), - Type::Enum(data) => write!(f, "({:?})", data), - Type::Record(data) => write!(f, "{{{:?}}}", data), + Type::Union(data) => write!(f, "({:?})", data), + Type::Struct(data) => write!(f, "{{{:?}}}", data), Type::Function { from, to } => write!(f, "{}->{}", from, to), } } } -impl fmt::Display for Term { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl core::fmt::Display for Term { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Term::Unit() => write!(f, "∅"), Term::Boolean(term) => write!(f, "{}", term), @@ -86,90 +146,21 @@ impl fmt::Display for Term { Term::Integer(term) => write!(f, "{}", term), Term::Float(term) => write!(f, "{}", term), Term::String { len, cap, data } => write!(f, "\"{:?}\"", data), - Term::Enum { val, data } => write!(f, "{:?}", data), - Term::Record(term) => write!(f, "{:?}", term), + Term::Union { val, data } => write!(f, "{:?}", data), + Term::Struct(term) => write!(f, "{:?}", term), Term::Function(expr) => write!(f, "{}", *expr), } } } -// hatehatehate that you can't implement a trait for foreign types -// impl fmt::Display for Vec where T: fmt::Display { -// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// for (i, val) in self.enumerate() { -// if i == 0 { -// write!(f, "{}", val); -// } else { -// write!(f, ",{}", val); -// } -// } -// return Ok(()); -// } -// } - -// impl fmt::Display for HashMap where T: fmt::Display, U: fmt::Display { -// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// for (i, (key, val)) in self.enumerate() { -// if i == 0 { -// write!(f, "{}={}", key, val); -// } else { -// write!(f, ",{}={}", key, val); -// } -// } -// return Ok(()); -// } -// } - -/// Convert a term into its corresponding type. -pub fn convert(term: &Term) -> Result { - match term { - Term::Unit() => Ok(Type::Unit), - Term::Boolean(_) => Ok(Type::Boolean), - Term::Natural(_) => Ok(Type::Natural), - Term::Integer(_) => Ok(Type::Integer), - Term::Float(_) => Ok(Type::Float), - Term::String { len, cap, data } => Ok(Type::String), - Term::Enum { val, data } => convert(data), - Term::Record(data) => { - let mut result = HashMap::new(); - for (key, val) in data { - result.insert(key.clone(), convert(val)?); - } - return Ok(Type::Record(result)); - }, - Term::Function(func) => match *func.clone() { - Expression::Annotation { expr, kind } => match kind { - Type::Function { from, to } => Ok(Type::Function { from, to }), - _ => Err("function term value not a function!".to_string()) - } - _ => Err("function term value does not have an annotation!".to_string()) - } +impl Context { + pub fn new() -> Self { + Context(HashMap::new()) } -} - -/// Get the default value of a type. Throws an error if it doesn't exist. -pub fn default(kind: &Type) -> Result { - match kind { - Type::Empty => Err("attempting to take the default term for empty".to_string()), - Type::Error => Err("attempting to take the default term for error".to_string()), - Type::Unit => Ok(Term::Unit()), - Type::Boolean => Ok(Term::Boolean(false)), - Type::Natural => Ok(Term::Natural(0)), - Type::Integer => Ok(Term::Integer(0)), - Type::Float => Ok(Term::Float(0.0)), - Type::String => Ok(Term::String { len: 0, cap: 0, data: vec!()}), - Type::Enum(data) => match data.len() { - 0 => Err("attempting to get a default term of an enum with no variants!".to_string()), - _ => Ok(Term::Enum { val: 0, data: Box::new(default(data.get(0).unwrap())?) }) - }, - Type::Record(data) => { - let mut result = HashMap::new(); - for (key, val) in data { - result.insert(key.clone(), default(val)?); - } - return Ok(Term::Record(result)); - }, - Type::Function { from, to } => - Err("attempting to take the default term of a function type".to_string()), + pub fn get(&self, k: &Identifier) -> Option<&Term> { + self.0.get(k) + } + pub fn insert(&mut self, k: Identifier, v: Term) -> Option { + self.0.insert(k, v) } } diff --git a/src/bidirectional.rs b/src/bidirectional.rs index 493ae2f..d62267c 100644 --- a/src/bidirectional.rs +++ b/src/bidirectional.rs @@ -2,119 +2,122 @@ use crate::ast::*; -/// Checking judgement: takes an expression and a type to check against and calls out to `infer` as needed. -pub fn check(context: &Context, expression: Expression, target: &Type) -> Result<(), String> { - match expression { - // fall through to inference mode - Expression::Annotation { expr, kind } => { - let result = infer(context, Expression::Annotation { expr, kind })?; - return match subtype(&result, &target) { - true => Ok(()), - false => Err(format!("inferred type {result} does not match target {target}")) - } - }, - // Bt-CheckInfer - Expression::Constant { term } => match subtype(&convert(&term)?, &target) { - true => Ok(()), - false => Err(format!("constant is of wrong type, expected {target}")) - // false => Ok(()) // all our constants are Empty for now - }, - // Bt-CheckInfer - Expression::Variable { id } => match context.get(&id) { - Some(term) if subtype(&convert(term)?, &target) => Ok(()), - Some(_) => Err(format!("variable {id} is of wrong type")), - None => Err(format!("failed to find variable {id} in context")) - }, - // Bt-Abs - Expression::Abstraction { param, func } => match target { - Type::Function { from, to } => { - let mut context = context.clone(); - context.insert(param, default(from)?); - return check(&context, *func, &to); +impl Context { + /// Checking judgement: takes an expression and a type to check against and calls out to `infer` as needed. + pub fn check(&self, expression: Expression, target: &Type) -> Result<()> { + match expression { + // fall through to inference mode + Expression::Annotation { expr, kind } => { + let result = self.infer(Expression::Annotation { expr, kind })?; + return match result.subtype(&target) { + true => Ok(()), + false => Err(format!("inferred type {result} does not match target {target}").into()) + } }, - _ => Err(format!("attempting to check an abstraction with a non-function type {target}")) - }, - // fall through to inference mode - Expression::Application { func, arg } => { - let result = &infer(context, Expression::Application { func, arg })?; - return match subtype(&result, &target) { + // Bt-CheckInfer + Expression::Constant { term } => match &term.convert()?.subtype(&target) { true => Ok(()), - false => Err(format!("inferred type {result} does not match {target}")) + false => Err(format!("constant is of wrong type, expected {target}").into()) + // false => Ok(()) // all our constants are Empty for now + }, + // Bt-CheckInfer + Expression::Variable { id } => match self.get(&id) { + Some(term) if term.convert()?.subtype(&target) => Ok(()), + Some(_) => Err(format!("variable {id} is of wrong type").into()), + None => Err(format!("failed to find variable {id} in context").into()) + }, + // Bt-Abs + Expression::Abstraction { param, func } => match target { + Type::Function { from, to } => { + let mut context = self.clone(); + context.insert(param, from.default()?); + return context.check(*func, &to); + }, + _ => Err(format!("attempting to check an abstraction with a non-function type {target}").into()) + }, + // fall through to inference mode + Expression::Application { func, arg } => { + let result = &self.infer(Expression::Application { func, arg })?; + return match result.subtype(&target) { + true => Ok(()), + false => Err(format!("inferred type {result} does not match {target}").into()) + } + }, + // T-If + Expression::Conditional { if_cond, if_then, if_else } => { + self.check(*if_cond, &Type::Boolean)?; + self.check(*if_then, &target)?; + self.check(*if_else, &target)?; + return Ok(()); } - }, - // T-If - Expression::Conditional { if_cond, if_then, if_else } => { - check(context, *if_cond, &Type::Boolean)?; - check(context, *if_then, &target)?; - check(context, *if_else, &target)?; - return Ok(()); } } -} -/// Inference judgement: takes an expression and attempts to infer the associated type. -pub fn infer(context: &Context, expression: Expression) -> Result { - match expression { - // Bt-Ann - Expression::Annotation { expr, kind } => check(context, *expr, &kind).map(|x| kind), - // Bt-True / Bt-False / etc - Expression::Constant { term } => convert(&term), - // Bt-Var - Expression::Variable { id } => match context.get(&id) { - Some(term) => infer(&Context::new(), Expression::Constant { term: term.clone() }), - None => Err(format!("failed to find variable in context {context:?}")) - }, - // Bt-App - Expression::Application { func, arg } => match infer(context, *func)? { - Type::Function { from, to } => check(context, *arg, &*from).map(|x| *to), - _ => Err(format!("application abstraction is not a function type")) - }, - // inference from an abstraction is always an error - // we could try and infer the func without adding the parameter to scope: - // but this is overwhelmingly likely to be an error, so just report it now. - Expression::Abstraction { param, func } => - Err(format!("attempting to infer from an abstraction")), - // idk - Expression::Conditional { if_cond, if_then, if_else } => { - check(context, *if_cond, &Type::Boolean)?; - let if_then = infer(context, *if_then)?; - let if_else = infer(context, *if_else)?; - if subtype(&if_then, &if_else) && subtype(&if_else, &if_then) { - Ok(if_then) // fixme: should be the join - } else { - Err(format!("if clauses of different types: {if_then} and {if_else}")) + /// Inference judgement: takes an expression and attempts to infer the associated type. + pub fn infer(&self, expression: Expression) -> Result { + match expression { + // Bt-Ann + Expression::Annotation { expr, kind } => self.check(*expr, &kind).map(|x| kind), + // Bt-True / Bt-False / etc + Expression::Constant { term } => term.convert(), + // Bt-Var + Expression::Variable { id } => match self.get(&id) { + Some(term) => Context::new().infer(Expression::Constant { term: term.clone() }), + None => Err(format!("failed to find variable in context {self:?}").into()) + }, + // Bt-App + Expression::Application { func, arg } => match self.infer(*func)? { + Type::Function { from, to } => self.check(*arg, &*from).map(|x| *to), + _ => Err(format!("application abstraction is not a function type").into()) + }, + // inference from an abstraction is always an error + // we could try and infer the func without adding the parameter to scope: + // but this is overwhelmingly likely to be an error, so just report it now. + Expression::Abstraction { param, func } => + Err(format!("attempting to infer from an abstraction").into()), + // idk + Expression::Conditional { if_cond, if_then, if_else } => { + self.check(*if_cond, &Type::Boolean)?; + let if_then = self.infer(*if_then)?; + let if_else = self.infer(*if_else)?; + if if_then.subtype(&if_else) && if_else.subtype(&if_then) { + Ok(if_then) // fixme: should be the join + } else { + Err(format!("if clauses of different types: {if_then} and {if_else}").into()) + } } } } } -/// The subtyping relation between any two types. -pub fn subtype(is: &Type, of: &Type) -> bool { - match (is, of) { - (Type::Record(is_fields), Type::Record(of_fields)) => { - // width, depth, and permutation - for (key, of_value) in of_fields { - match is_fields.get(key) { - Some(is_value) => { - if !subtype(is_value, of_value) { - return false; +impl Type { + /// The subtyping relation between any two types. + pub fn subtype(&self, other: &Self) -> bool { + match (self, other) { + (Type::Struct(is_fields), Type::Struct(of_fields)) => { + // width, depth, and permutation + for (key, of_value) in of_fields { + match is_fields.get(key) { + Some(is_value) => { + if !is_value.subtype(of_value) { + return false; + } } + None => return false } - None => return false } - } - return true; - }, - (Type::Enum(is_variants), Type::Enum(of_variants)) => false, // fixme - (Type::Function { from: is_from, to: is_to }, - Type::Function { from: of_from, to: of_to }) => { - subtype(of_from, is_from) && subtype(is_to, of_to) - }, - (Type::Natural, Type::Integer) => true, // obviously not, but let's pretend - (_, Type::Empty) => true, - (Type::Error, _) => true, - (_, _) if is == of => true, - (_, _) => false + return true; + }, + (Type::Union(is_variants), Type::Union(of_variants)) => false, // fixme + (Type::Function { from: is_from, to: is_to }, + Type::Function { from: of_from, to: of_to }) => { + of_from.subtype(is_from) && is_to.subtype(of_to) + }, + (Type::Natural, Type::Integer) => true, // obviously not, but let's pretend + (_, Type::Empty) => true, + (Type::Error, _) => true, + (_, _) if self == other => true, + (_, _) => false + } } } - diff --git a/src/classes.rs b/src/classes.rs deleted file mode 100644 index 38a4847..0000000 --- a/src/classes.rs +++ /dev/null @@ -1,3 +0,0 @@ -// Typeclass pass: monomorphize based on usage, pretty much - - diff --git a/src/main.rs b/src/main.rs index a33e963..b93e778 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,7 +24,7 @@ fn main() { input.clear(); stdin().read_line(&mut input).unwrap(); - match infer(&empty_context, parser::parse_lambda(&input).unwrap()) { + match empty_context.infer(parser::parse_lambda(&input).unwrap()) { Ok(kind) => println!("infers! {}", kind), Err(e) => println!("{:?}", e), } @@ -36,10 +36,10 @@ fn main() { input.clear(); stdin().read_line(&mut input).unwrap(); - let kind = infer(&empty_context, parser::parse_lambda(&input).unwrap()); + let kind = empty_context.infer(parser::parse_lambda(&input).unwrap()); match kind { Ok(kind) => { - match check(&empty_context, parser::parse_lambda(&input).unwrap(), &kind) { + match empty_context.check(parser::parse_lambda(&input).unwrap(), &kind) { Ok(_) => println!("checks!"), Err(e) => println!("{:?}", e), } @@ -54,7 +54,7 @@ fn main() { input.clear(); stdin().read_line(&mut input).unwrap(); - match execute(&empty_context, parser::parse_lambda(&input).unwrap()) { + match empty_context.execute(parser::parse_lambda(&input).unwrap()) { Ok(term) => println!("{}", term), Err(e) => println!("{:?}", e) } diff --git a/src/parser.rs b/src/parser.rs index d3895a4..298e09d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,7 +2,7 @@ use crate::ast::*; use multipeek::multipeek; /// Parses a lambda-calculus-like language into an AST. -pub fn parse_lambda(input: &str) -> Result> { +pub fn parse_lambda(input: &str) -> Result { // this is kinda awful, i miss my simple nim pegs peg::parser! { grammar lambda() for str { @@ -98,7 +98,7 @@ pub fn parse_lambda(input: &str) -> Result Result, &'static str> { +pub fn lex(input: &str) -> Result> { enum State { Default, Char, @@ -142,6 +142,7 @@ pub fn lex(input: &str) -> Result, &'static str> { let mut buffer = String::new(); let mut result = Vec::new(); + // .next() advances the iterator, .peek() does not let mut input = multipeek(input.chars()); // multipeek my beloved while let Some(c) = input.next() { match state { @@ -151,9 +152,36 @@ pub fn lex(input: &str) -> Result, &'static str> { result.push(parse_token(&buffer)?); buffer.clear(); }, - ' ' => todo!(), - '\n' => todo!(), - '\t' => return Err("Tabs are not supported!"), + ' ' => { + // hmm + todo!() + }, + '\n' => { + if let Some(previous) = result.last() { + match previous { + // same scope, no seperator + Token::Operator(_) => (), + // do we have this tbh???? + Token::Keyword(_) => return Err("lines shouldn't end with a keyword i think".into()), + // i think uhh + Token::Identifier(_) | Token::Value(_) | Token::Char(_) | Token::String(_) => + result.push(Token::ExprEnd), + // always scope?? + Token::Separator(_) => result.push(Token::ScopeBegin), + // idk + Token::Comment(_) | Token::ScopeBegin | Token::ScopeEnd | Token::ExprEnd => + return Err("uhh idk always scope lol".into()), + } + } + todo!() + }, + '\t' => return Err("Tabs are not supported!".into()), + _ if indent.blank => { + indent.blank = false; + // indentation check + todo!(); + buffer.push(c); + }, '\'' => { result.push(parse_token(&buffer)?); buffer.clear(); @@ -187,12 +215,6 @@ pub fn lex(input: &str) -> Result, &'static str> { indent.blank = false; } } - _ if indent.blank => { - indent.blank = false; - // indentation check - todo!(); - buffer.push(c); - } _ => buffer.push(c) }, State::Char => match c { @@ -205,11 +227,11 @@ pub fn lex(input: &str) -> Result, &'static str> { Some('t') => result.push(Token::Char('\t')), Some('\"') => result.push(Token::Char('\"')), Some('\'') => result.push(Token::Char('\'')), - _ => return Err("Invalid string escape sequence!"), + _ => return Err("Invalid string escape sequence!".into()), } state = State::Default; if input.next() != Some('\'') { - return Err("Invalid character sequence!") + return Err("Invalid character sequence!".into()) } }, '\'' => { @@ -220,7 +242,7 @@ pub fn lex(input: &str) -> Result, &'static str> { result.push(Token::Char(c)); state = State::Default; if input.next() != Some('\'') { - return Err("Invalid character sequence!") + return Err("Invalid character sequence!".into()) } } }, @@ -233,7 +255,7 @@ pub fn lex(input: &str) -> Result, &'static str> { Some('t') => buffer.push('\t'), Some('\"') => buffer.push('\"'), Some('\'') => buffer.push('\''), - _ => return Err("Invalid string escape sequence!"), + _ => return Err("Invalid string escape sequence!".into()), }, '\"' => { state = State::Default; @@ -255,7 +277,8 @@ pub fn lex(input: &str) -> Result, &'static str> { State::Comment => match c { '\n' => { state = State::Default; - result.push(Token::Comment(buffer.to_string())); + // result.push(Token::Comment(buffer.to_string())); + buffer.clear(); }, _ => buffer.push(c) }, @@ -264,7 +287,7 @@ pub fn lex(input: &str) -> Result, &'static str> { return Ok(result); } -fn parse_token(token: &str) -> Result { +fn parse_token(token: &str) -> Result { if keywords.contains(&token) { Ok(Token::Keyword(token.to_string())) } else if is_operator(token) { @@ -274,7 +297,7 @@ fn parse_token(token: &str) -> Result { } else if is_identifier(token) { Ok(Token::Identifier(token.to_string())) } else { - Err("Could not parse token!") + Err("Could not parse token!".into()) } } diff --git a/src/simple.rs b/src/simple.rs index 8d87dbf..e763221 100644 --- a/src/simple.rs +++ b/src/simple.rs @@ -1,32 +1,33 @@ use crate::ast::*; -/// Evaluates an expression given a context (of variables) to a term, or fails. -pub fn execute(context: &Context, expression: Expression) -> Result { - match expression { - Expression::Annotation { expr, .. } => execute(context, *expr), - Expression::Constant { term } => Ok(term), - Expression::Variable { id } => match context.get(&id) { - Some(term) => Ok(term.clone()), - None => Err(format!("no such variable in context {context:?}")) - }, - Expression::Abstraction { param, func } => - Err(format!("attempting to execute an abstraction ({}){}", param, func)), - Expression::Application { func, arg } => match *func { - Expression::Abstraction { param, func } => { - let value = execute(context, *arg)?; - let mut context = context.clone(); - context.insert(param, value); - return execute(&context, *func); - } - _ => Err(format!("attempting to execute an application to non-abstraction {}", *func)) - }, - Expression::Conditional { if_cond, if_then, if_else } => { - match execute(context, *if_cond)? { - Term::Boolean(true) => execute(context, *if_then), - Term::Boolean(false) => execute(context, *if_else), - term => Err(format!("invalid type {} for a conditional", convert(&term)?)) +impl Context { + /// Evaluates an expression given a context (of variables) to a term, or fails. + pub fn execute(&self, expression: Expression) -> Result { + match expression { + Expression::Annotation { expr, .. } => self.execute(*expr), + Expression::Constant { term } => Ok(term), + Expression::Variable { id } => match self.get(&id) { + Some(term) => Ok(term.clone()), + None => Err(format!("no such variable in context {self:?}").into()) + }, + Expression::Abstraction { param, func } => + Err(format!("attempting to execute an abstraction ({}){}", param, func).into()), + Expression::Application { func, arg } => match *func { + Expression::Abstraction { param, func } => { + let value = self.execute(*arg)?; + let mut context = self.clone(); + context.insert(param, value); + return context.execute(*func); + } + _ => Err(format!("attempting to execute an application to non-abstraction {}", *func).into()) + }, + Expression::Conditional { if_cond, if_then, if_else } => { + match self.execute(*if_cond)? { + Term::Boolean(true) => self.execute(*if_then), + Term::Boolean(false) => self.execute(*if_else), + term => Err(format!("invalid type {} for a conditional", &term.convert()?).into()) + } } } } } - diff --git a/src/util.rs b/src/util.rs index a27f32c..39ac263 100644 --- a/src/util.rs +++ b/src/util.rs @@ -74,6 +74,6 @@ pub fn Str(len: usize, cap: usize, data: Vec) -> Term { return Term::String { len, cap, data } } -pub fn Enum(val: usize, data: Term) -> Term { - return Term::Enum { val, data: Box::new(data) } +pub fn Union(val: usize, data: Term) -> Term { + return Term::Union { val, data: Box::new(data) } } -- cgit v1.2.3-70-g09d2