aboutsummaryrefslogtreecommitdiff
path: root/src/ast.rs
diff options
context:
space:
mode:
authorJJ2023-04-13 07:20:06 +0000
committerJJ2023-04-13 07:21:28 +0000
commit5ae010fef48cc2bf83a0d366d2a1cfa74ecce278 (patch)
tree2241dcec8d38d16e2314e94b4dec0ed61e20d922 /src/ast.rs
parent188631f3bb263700c34d578af5968ab80e699485 (diff)
major cleanups: extend Type, refactor Term, and switch to String errs
Diffstat (limited to 'src/ast.rs')
-rw-r--r--src/ast.rs105
1 files changed, 84 insertions, 21 deletions
diff --git a/src/ast.rs b/src/ast.rs
index bf34d19..0a0c042 100644
--- a/src/ast.rs
+++ b/src/ast.rs
@@ -1,4 +1,4 @@
-// Bidirectional type checking, simple types for effects (or perhaps subtyping?) and typeclasses
+// Bidirectional type checking, subtyping, and typeclasses
use core::fmt;
use std::collections::HashMap;
@@ -6,8 +6,8 @@ use std::collections::HashMap;
pub type Identifier = String;
pub type Context = HashMap<Identifier, Term>;
-// note: when comes the time, we'll put effects in here (i think)
-#[derive(Clone, PartialEq, Eq)]
+// note: built-in functions do NOT go here!
+#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
Annotation{expr: Box<Expression>, kind: Type},
Constant{term: Term},
@@ -18,11 +18,7 @@ pub enum Expression {
Conditional{if_cond: Box<Expression>, if_then: Box<Expression>, if_else: Box<Expression>}
}
-// _every_ type in our language is represented as this and interpreted as a type.
-// how to store more data than fits... hmm... a problem for later
-pub type Value = u64;
-
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq)]
pub enum Type {
Empty,
Error,
@@ -30,29 +26,96 @@ pub enum Type {
Boolean,
Natural,
Integer,
- // Float,
- // String,
+ Float,
+ String,
Enum(Vec<Type>),
Record(HashMap<Identifier, Type>),
Function{from: Box<Type>, to: Box<Type>},
}
-// this means that functions cannot have types? unless we put them as empty values ig
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Term {
- pub val: Value,
- pub kind: Type, // currently useless / redundant: will be useful for casting
+#[derive(Debug, Clone, PartialEq)]
+pub enum Term {
+ Unit(),
+ Boolean(bool),
+ Natural(usize),
+ Integer(isize),
+ Float(f32),
+ String{len: usize, cap: usize, data: Vec<usize>},
+ Enum{val: usize, data: Vec<Type>}, // is this right?
+ Record(HashMap<Identifier, Term>), // is this right?
+ Function(Box<Expression>) // this should allow us to bind functions
}
-impl fmt::Debug for Expression {
+impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- Expression::Annotation { expr, kind } => write!(f, "({:?}: {:?})", expr, kind),
- Expression::Constant { term } => write!(f, "'{}", term.val),
+ Expression::Annotation { expr, kind } => write!(f, "({}: {})", expr, kind),
+ Expression::Constant { term } => write!(f, "'{:?}", term),
Expression::Variable { id } => write!(f, "{}", id),
- Expression::Abstraction { param, func } => write!(f, "(λ{}.{:?})", param, func),
- Expression::Application { func, arg } => write!(f, "({:?} {:?})", func, arg),
- Expression::Conditional { if_cond, if_then, if_else } => write!(f, "(if {:?} then {:?} else {:?})", if_cond, if_then, if_else),
+ Expression::Abstraction { param, func } => write!(f, "(λ{}.{})", param, func),
+ Expression::Application { func, arg } => write!(f, "({} {})", func, arg),
+ Expression::Conditional { if_cond, if_then, if_else } => write!(f, "(if {} then {} else {})", if_cond, if_then, if_else),
+ }
+ }
+}
+
+impl fmt::Display for Type {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Type::Empty => write!(f, "⊤"),
+ Type::Error => write!(f, "⊥"),
+ Type::Unit => write!(f, "unit"),
+ Type::Boolean => write!(f, "bool"),
+ Type::Natural => write!(f, "nat"),
+ 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::Function { from, to } => write!(f, "{}->{}", from, to),
}
}
}
+
+impl fmt::Display for Term {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Term::Unit() => write!(f, "∅"),
+ Term::Boolean(term) => write!(f, "{}", term),
+ Term::Natural(term) => write!(f, "{}", 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.get(*val)),
+ Term::Record(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(());
+// }
+// }