aboutsummaryrefslogtreecommitdiff
path: root/src/ast.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast.rs')
-rw-r--r--src/ast.rs181
1 files changed, 86 insertions, 95 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)
}
}