aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJJ2023-07-19 19:25:30 +0000
committerJJ2023-07-20 02:08:36 +0000
commitf5e61572b217c5445c3cd593d1cc94697fa7ec48 (patch)
tree5ae7c5a95cac5c2a23c27ae10f48ebf4c0e4e684 /src
parent99769e9ebb94d1dcc12f2d1f6a6d899f7a229676 (diff)
major cleanups: switch to dynamic Errors, impl Context, rename enums/records to unions/structs
Diffstat (limited to 'src')
-rw-r--r--src/ast.rs181
-rw-r--r--src/bidirectional.rs203
-rw-r--r--src/classes.rs3
-rw-r--r--src/main.rs8
-rw-r--r--src/parser.rs65
-rw-r--r--src/simple.rs53
-rw-r--r--src/util.rs4
7 files changed, 266 insertions, 251 deletions
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<T> = core::result::Result<T, Box<dyn std::error::Error>>;
pub type Identifier = String;
-pub type Context = HashMap<Identifier, Term>;
+
+#[derive(Debug, Clone, PartialEq)]
+pub struct Context(HashMap<Identifier, Term>);
// note: built-in functions do NOT go here!
#[derive(Debug, Clone, PartialEq)]
@@ -18,6 +18,7 @@ pub enum Expression {
Conditional{if_cond: Box<Expression>, if_then: Box<Expression>, if_else: Box<Expression>}
}
+/// All supported types.
#[derive(Debug, Clone, PartialEq)]
pub enum Type {
Empty,
@@ -28,11 +29,12 @@ pub enum Type {
Integer,
Float,
String,
- Enum(Vec<Type>),
- Record(HashMap<Identifier, Type>),
+ Union(Vec<Type>),
+ Struct(HashMap<Identifier, Type>),
Function{from: Box<Type>, to: Box<Type>},
}
+/// 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<usize>},
- Enum{val: usize, data: Box<Term>}, // is this right?
- Record(HashMap<Identifier, Term>), // is this right?
+ Union{val: usize, data: Box<Term>}, // is this right?
+ Struct(HashMap<Identifier, Term>), // is this right?
Function(Box<Expression>) // 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<Type> {
+ 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<Term> {
+ 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<T> fmt::Display for Vec<T> 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<T, U> fmt::Display for HashMap<T, U> 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<Type, String> {
- 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<Term, String> {
- 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<Term> {
+ 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<Type, String> {
- 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<Type> {
+ 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<Expression, peg::error::ParseError<peg::str::LineCol>> {
+pub fn parse_lambda(input: &str) -> Result<Expression> {
// 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<Expression, peg::error::ParseError<pe
}
}
}
- return lambda::expr(input.trim());
+ return Ok(lambda::expr(input.trim())?);
}
const operators: [char; 17] =
@@ -115,15 +115,15 @@ pub enum Token {
Value(String),
Char(char),
String(String),
- Comment(String),
- Token(String), // catch-all
+ Comment(String), // unused tbh
+ // Token(String), // catch-all
ScopeBegin, // {
ScopeEnd, // }
ExprEnd, // ;
}
/// Properly lexes a whitespace-oriented language into a series of tokens.
-pub fn lex(input: &str) -> Result<Vec<Token>, &'static str> {
+pub fn lex(input: &str) -> Result<Vec<Token>> {
enum State {
Default,
Char,
@@ -142,6 +142,7 @@ pub fn lex(input: &str) -> Result<Vec<Token>, &'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<Vec<Token>, &'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<Vec<Token>, &'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<Vec<Token>, &'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<Vec<Token>, &'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<Vec<Token>, &'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<Vec<Token>, &'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<Vec<Token>, &'static str> {
return Ok(result);
}
-fn parse_token(token: &str) -> Result<Token, &'static str> {
+fn parse_token(token: &str) -> Result<Token> {
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<Token, &'static str> {
} 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<Term, String> {
- 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<Term> {
+ 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<usize>) -> 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) }
}