M fml/src/ast.rs +0 -5
@@ 119,11 119,6 @@ pub enum Decl {
signature: Signature,
body: Vec<ExprNode>,
},
-
- Struct {
- name: String,
- tys: HashMap<String, Type>,
- },
TypeDef {
name: String,
ty: Type,
M fml/src/lib.rs +6 -1
@@ 1,5 1,7 @@
//! Garnet compiler guts.
+use std::collections::HashMap;
+
pub mod ast;
pub mod parser;
pub mod typeck;
@@ 9,6 11,7 @@ pub mod typeck;
pub enum Type {
Named(String, Vec<Type>),
Func(Vec<Type>, Box<Type>),
+ Struct(HashMap<String, Type>),
/// A generic type parameter
Generic(String),
}
@@ 29,7 32,7 @@ impl Type {
pub struct TypeId(usize);
/// Information about a type term
-#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TypeInfo {
/// No information about the type of this type term
Unknown,
@@ 42,6 45,8 @@ pub enum TypeInfo {
Named(String, Vec<TypeId>),
/// This type term is definitely a function
Func(Vec<TypeId>, TypeId),
+ /// This is definitely some kind of struct
+ Struct(HashMap<String, TypeId>),
/// This is some generic type that has a name like @A
/// AKA a type parameter.
TypeParam(String),
M fml/src/parser.rs +60 -7
@@ 58,6 58,8 @@ pub enum TokenKind {
Let,
#[token("end")]
End,
+ #[token("struct")]
+ Struct,
// Punctuation
#[token("(")]
@@ 497,14 499,8 @@ impl<'input> Parser<'input> {
T::Ident(_) => {
let ident = self.expect_ident();
ast::ExprNode::new(ast::Expr::Var { name: ident })
- /*
- if self.peek_is(TokenKind::LBrace.discr()) {
- self.parse_struct_literal(ident)
- } else {
- ast::Expr::Var { name: ident }
- }
- */
}
+ T::Struct => self.parse_struct_literal(),
T::Let => self.parse_let(),
T::Fn => self.parse_lambda(),
// Parenthesized expr's
@@ 640,6 636,37 @@ impl<'input> Parser<'input> {
ast::ExprNode::new(ast::Expr::TupleCtor { body })
}
+ /// struct literal = "struct" "{" ... "}"
+ fn parse_struct_literal(&mut self) -> ast::ExprNode {
+ self.expect(T::Struct);
+ self.expect(T::LBrace);
+ let body = self.parse_struct_lit_fields();
+ self.expect(T::RBrace);
+ ast::ExprNode::new(ast::Expr::StructCtor { body })
+ }
+
+ fn parse_struct_lit_fields(&mut self) -> HashMap<String, ast::ExprNode> {
+ let mut fields = HashMap::new();
+
+ loop {
+ match self.lex.peek() {
+ Some((T::Ident(_i), _span)) => {
+ let name = self.expect_ident();
+ self.expect(T::Equals);
+ let vl = self.parse_expr(0).unwrap();
+ fields.insert(name, vl);
+ }
+ _ => break,
+ }
+
+ if self.peek_expect(T::Comma.discr()) {
+ } else {
+ break;
+ }
+ }
+ fields
+ }
+
fn parse_type(&mut self) -> Type {
let t = self.next();
match t {
@@ 667,9 694,35 @@ impl<'input> Parser<'input> {
let fntype = self.parse_fn_type();
fntype
}
+ Some(Token {
+ kind: T::Struct, ..
+ }) => self.parse_struct_type(),
other => self.error("type", other),
}
}
+
+ fn parse_struct_type(&mut self) -> Type {
+ let mut fields = HashMap::new();
+
+ loop {
+ match self.lex.peek() {
+ Some((T::Ident(_i), _span)) => {
+ let name = self.expect_ident();
+ self.expect(T::Colon);
+ let vl = self.parse_type();
+ fields.insert(name, vl);
+ }
+ _ => break,
+ }
+
+ if self.peek_expect(T::Comma.discr()) {
+ } else {
+ break;
+ }
+ }
+ self.expect(T::End);
+ Type::Struct(fields)
+ }
}
/// Specifies binding power of postfix operators.
M fml/src/typeck.rs +10 -1
@@ 45,6 45,7 @@ impl Tck {
b == rettype || args.iter().any(|arg| self._contains_type(*arg, b))
}
TypeParam(_) => false,
+ Struct(_) => todo!(),
}
}
@@ 72,6 73,13 @@ impl Tck {
TypeInfo::Func(new_args, new_rettype)
}
Type::Generic(s) => TypeInfo::TypeParam(s.to_string()),
+ Type::Struct(body) => {
+ let new_body = body
+ .iter()
+ .map(|(nm, t)| (nm.clone(), self.insert_known(t)))
+ .collect();
+ TypeInfo::Struct(new_body)
+ }
};
self.insert(tinfo)
}
@@ 146,6 154,7 @@ impl Tck {
))
}
TypeParam(name) => Ok(Type::Generic(name.to_owned())),
+ Struct(_body) => todo!(),
}
}
@@ 203,6 212,7 @@ impl Tck {
let inst_ret = self.instantiate(named_types, rettype);
TypeInfo::Func(inst_args, inst_ret)
}
+ Type::Struct(_body) => todo!(),
};
self.insert(typeinfo)
}
@@ 490,7 500,6 @@ pub fn typecheck(ast: &ast::Ast) {
panic!("Error while typechecking function {}:\n{:?}", name, e)
});
}
- Struct { name: _, tys: _ } => todo!("struct decl"),
TypeDef { name, ty } => symtbl.add_type(name, ty),
}
}
M fml/tests/main.rs +6 -0
@@ 93,3 93,9 @@ fn test_typedef2() {
let src = include_str!("test_typedef2.gt");
let _output = fml::compile("test_typedef2.gt", src);
}
+
+#[test]
+fn test_struct1() {
+ let src = include_str!("test_struct1.gt");
+ let _output = fml::compile("test_struct1.gt", src);
+}