M fml/src/ast.rs +8 -0
@@ 95,6 95,10 @@ pub enum Expr {
StructCtor {
body: HashMap<String, ExprNode>,
},
+ TypeCtor {
+ name: String,
+ body: ExprNode,
+ },
}
impl Expr {
@@ 120,6 124,10 @@ pub enum Decl {
name: String,
tys: HashMap<String, Type>,
},
+ TypeDef {
+ name: String,
+ ty: Type,
+ },
}
/// A compilable chunk of AST.
M fml/src/parser.rs +24 -2
@@ 50,6 50,8 @@ pub enum TokenKind {
// Decl stuff
#[token("fn")]
Fn,
+ #[token("type")]
+ Type,
// Keywords
#[token("let")]
@@ 82,6 84,8 @@ pub enum TokenKind {
Equals,
#[token("@")]
At,
+ #[token("$")]
+ Dollar,
// We save comment strings so we can use this same
// parser as a reformatter or such.
@@ 360,11 364,20 @@ impl<'input> Parser<'input> {
fn parse_decl(&mut self) -> Option<ast::Decl> {
match self.next() {
Some(Token { kind: T::Fn, .. }) => Some(self.parse_fn()),
+ Some(Token { kind: T::Type, .. }) => Some(self.parse_typedef()),
Some(other) => self.error("start of decl", Some(other)),
None => None,
}
}
+ /// typedef = "type" ident "=" type
+ fn parse_typedef(&mut self) -> ast::Decl {
+ let name = self.expect_ident();
+ self.expect(T::Equals);
+ let ty = self.parse_type();
+ ast::Decl::TypeDef { name, ty }
+ }
+
fn parse_fn(&mut self) -> ast::Decl {
let name = self.expect_ident();
let signature = ast::Signature {
@@ 503,6 516,16 @@ impl<'input> Parser<'input> {
}
// Tuple literal
T::LBrace => self.parse_constructor(),
+ // Nominal type literal
+ // $Foo(3)
+ T::Dollar => {
+ self.drop();
+ let name = self.expect_ident();
+ self.expect(T::LParen);
+ let body = self.parse_expr(0)?;
+ self.expect(T::RParen);
+ ast::ExprNode::new(ast::Expr::TypeCtor { name, body })
+ }
// Something else not a valid expr
_x => return None,
@@ 627,8 650,7 @@ impl<'input> Parser<'input> {
if let Some(t) = Type::get_primitive_type(s) {
t.clone()
} else {
- //crate::INT.named_type(s)
- self.error("Unknown type", t.clone());
+ Type::Named(s.clone(), vec![])
}
}
Some(Token { kind: T::At, .. }) => {
M fml/src/typeck.rs +51 -5
@@ 149,6 149,14 @@ impl Tck {
}
}
+ fn print_types(&self) {
+ let mut vars_report: Vec<_> = self.vars.iter().collect();
+ vars_report.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
+ for (k, v) in vars_report.iter() {
+ print!(" ${} => {:?}\n", k.0, v);
+ }
+ }
+
/// Kinda the opposite of reconstruction; takes a concrete type
/// and generates a new type with unknown's (type variables) for the generic types (type
/// parameters)
@@ 206,6 214,7 @@ impl Tck {
#[derive(Clone)]
struct Symtbl {
symbols: Rc<RefCell<Vec<HashMap<String, TypeId>>>>,
+ types: Rc<RefCell<Vec<HashMap<String, Type>>>>,
}
impl Default for Symtbl {
@@ 213,6 222,7 @@ impl Default for Symtbl {
fn default() -> Self {
Self {
symbols: Rc::new(RefCell::new(vec![HashMap::new()])),
+ types: Rc::new(RefCell::new(vec![HashMap::new()])),
}
}
}
@@ 228,12 238,18 @@ impl Drop for ScopeGuard {
.borrow_mut()
.pop()
.expect("Scope stack underflow");
+ self.scope
+ .types
+ .borrow_mut()
+ .pop()
+ .expect("Scope stack underflow");
}
}
impl Symtbl {
fn push_scope(&self) -> ScopeGuard {
self.symbols.borrow_mut().push(HashMap::new());
+ self.types.borrow_mut().push(HashMap::new());
ScopeGuard {
scope: self.clone(),
}
@@ 257,6 273,24 @@ impl Symtbl {
}
return None;
}
+
+ fn add_type(&self, name: impl AsRef<str>, ty: &Type) {
+ self.types
+ .borrow_mut()
+ .last_mut()
+ .expect("Scope stack underflow")
+ .insert(name.as_ref().to_owned(), ty.to_owned());
+ }
+
+ fn get_type(&self, ty: impl AsRef<str>) -> Option<Type> {
+ for scope in self.types.borrow().iter().rev() {
+ let v = scope.get(ty.as_ref());
+ if v.is_some() {
+ return v.cloned();
+ }
+ }
+ return None;
+ }
}
fn infer_lit(lit: &ast::Literal) -> TypeInfo {
@@ 309,11 343,7 @@ fn typecheck_func_body(
"Typechecked function {}, types are",
name.unwrap_or("(lambda)")
);
- let mut vars_report: Vec<_> = tck.vars.iter().collect();
- vars_report.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
- for (k, v) in vars_report.iter() {
- print!(" ${} => {:?}\n", k.0, v);
- }
+ tck.print_types();
Ok(f)
}
@@ 420,6 450,20 @@ fn typecheck_expr(
}
StructCtor { body: _ } => todo!("Struct ctor"),
+ TypeCtor { name, body } => {
+ let named_type = symtbl.get_type(name).expect("Unknown type constructor");
+ println!("Got type named {}: is {:?}", name, named_type);
+ let tid = tck.insert_known(&named_type);
+ let body_type = typecheck_expr(tck, symtbl, body)?;
+ println!("Expected type is {:?}, body type is {:?}", tid, body_type);
+ tck.unify(symtbl, tid, body_type)?;
+ println!("Done unifying type ctor");
+ // The type the expression returns
+ // TODO: Generic params for type constructors
+ let constructed_type = tck.insert_known(&Type::Named(name.clone(), vec![]));
+ tck.set_expr_type(expr, constructed_type);
+ Ok(tid)
+ }
}
}
@@ 442,10 486,12 @@ pub fn typecheck(ast: &ast::Ast) {
} => {
let t = typecheck_func_body(Some(name), tck, symtbl, signature, body);
t.unwrap_or_else(|e| {
+ tck.print_types();
panic!("Error while typechecking function {}:\n{:?}", name, e)
});
}
Struct { name: _, tys: _ } => todo!("struct decl"),
+ TypeDef { name, ty } => symtbl.add_type(name, ty),
}
}
// Print out toplevel symbols
M fml/tests/main.rs +6 -0
@@ 75,3 75,9 @@ fn test_lambda5() {
let src = include_str!("test_lambda5.gt");
let _output = fml::compile("test_lambda5.gt", src);
}
+
+#[test]
+fn test_typedef1() {
+ let src = include_str!("test_typedef1.gt");
+ let _output = fml::compile("test_typedef1.gt", src);
+}