@@ 102,8 102,6 @@ fn eat_block_comment(lex: &mut Lexer<Tok
pub enum TokenKind {
#[regex("[a-zA-Z_][a-zA-Z0-9_]*", |lex| lex.slice().to_owned())]
Ident(String),
- //#[regex("@[a-zA-Z_][a-zA-Z0-9_]*", |lex| lex.slice().to_owned())]
- //TypeIdent(String),
#[regex("true|false", |lex| lex.slice().parse())]
Bool(bool),
#[regex("[0-9][0-9_]*I8", |lex| make_int(lex, 1, true))]
@@ 670,7 668,6 @@ impl<'input> Parser<'input> {
if self.peek_is(T::RParen.discr()) {
break;
} else {
- self.expect(T::At);
let name = self.expect_ident();
params.push(name);
}
@@ 1387,10 1384,12 @@ impl<'input> Parser<'input> {
Type::Named(Sym::new(s), type_params)
}
}
- T::At => {
- let s = self.expect_ident();
- Type::Generic(s)
- }
+ /*
+ T::At => {
+ let s = self.expect_ident();
+ Type::Generic(s)
+ }
+ */
T::LBrace => self.try_parse_tuple_type()?,
T::Fn => self.parse_fn_type(),
T::Struct => self.try_parse_struct_type()?,
@@ 1576,9 1575,9 @@ mod tests {
#[test]
fn test_typedef_generics() {
- test_decl_is("type bop(@T) = @T", || ast::Decl::TypeDef {
+ test_decl_is("type bop(T) = T", || ast::Decl::TypeDef {
name: Sym::new("bop"),
- typedecl: Type::Generic(Sym::new("T")),
+ typedecl: Type::Named(Sym::new("T"), vec![]),
doc_comment: vec![],
params: vec![Sym::new("T")],
});
@@ 1648,7 1647,7 @@ type blar = I8
"(x Bool)",
"(x Bool,)",
"(x I32, y Bool)",
- "(x @X, y @Y)",
+ "(x X, y Y)",
"(x I32, y Bool,)",
];
test_parse_with(|p| p.parse_fn_args(), &valid_args)
@@ 1666,7 1665,7 @@ type blar = I8
"(f fn(I32) I64, x I32) Bool",
"(f fn(|| I32) I64, x I32) Bool",
"(f fn(||) I64, x I32) Bool",
- "(f fn(|@T| I32) I64, x I32) Bool",
+ "(f fn(|T| I32) I64, x I32) Bool",
// now without explicit return types
"()",
"(x Bool)",
@@ 1678,7 1677,7 @@ type blar = I8
"(f fn(I32), x I32)",
"(f fn(|| I32), x I32)",
"(f fn(||), x I32)",
- "(f fn(|@T| I32), x I32)",
+ "(f fn(|T| I32), x I32)",
];
test_parse_with(|p| p.parse_fn_signature(), &valid_args)
}
@@ 1778,12 1777,12 @@ type blar = I8
fn parse_fn_decls() {
let valid_args = vec![
"fn foo1(f I32) I32 = f end",
- "fn foo2(|@T| f I32 ) I32 = f end",
- "fn foo3(|@T|) {} = f end",
+ "fn foo2(|T| f I32 ) I32 = f end",
+ "fn foo3(|T|) {} = f end",
"fn foo4(||) {} = f end",
"fn foo5() {} = f end",
- "fn foo6(f @T) @T = f end",
- "fn foo7(|@T1, @T2, | f I32, g Bool, ) I32 = f end",
+ "fn foo6(f T) T = f end",
+ "fn foo7(|T1, T2, | f I32, g Bool, ) I32 = f end",
];
test_parse_with(|p| p.parse_decl().unwrap(), &valid_args);
}
@@ 105,6 105,7 @@ fn expr_map(
expr: ExprNode,
f_pre: &mut dyn FnMut(ExprNode) -> ExprNode,
f_post: &mut dyn FnMut(ExprNode) -> ExprNode,
+ ft: &mut dyn FnMut(Type) -> Type,
) -> ExprNode {
let thing = f_pre(expr);
let exprfn = &mut |e| match e {
@@ 117,12 118,12 @@ fn expr_map(
E::Break => e,
E::EnumCtor { .. } => e,
E::TupleCtor { body } => E::TupleCtor {
- body: exprs_map(body, f_pre, f_post),
+ body: exprs_map(body, f_pre, f_post, ft),
},
E::StructCtor { body } => {
let new_body = body
.into_iter()
- .map(|(sym, vl)| (sym, expr_map(vl, f_pre, f_post)))
+ .map(|(sym, vl)| (sym, expr_map(vl, f_pre, f_post, ft)))
.collect();
E::StructCtor { body: new_body }
}
@@ 132,8 133,8 @@ fn expr_map(
body,
} => E::TypeCtor {
name,
- type_params,
- body: expr_map(body, f_pre, f_post),
+ type_params: types_map(type_params, ft),
+ body: expr_map(body, f_pre, f_post, ft),
},
E::SumCtor {
name,
@@ 142,41 143,41 @@ fn expr_map(
} => E::SumCtor {
name,
variant,
- body: expr_map(body, f_pre, f_post),
+ body: expr_map(body, f_pre, f_post, ft),
},
E::ArrayCtor { body } => E::ArrayCtor {
- body: exprs_map(body, f_pre, f_post),
+ body: exprs_map(body, f_pre, f_post, ft),
},
E::TypeUnwrap { expr } => E::TypeUnwrap {
- expr: expr_map(expr, f_pre, f_post),
+ expr: expr_map(expr, f_pre, f_post, ft),
},
E::TupleRef { expr, elt } => E::TupleRef {
- expr: expr_map(expr, f_pre, f_post),
+ expr: expr_map(expr, f_pre, f_post, ft),
elt,
},
E::StructRef { expr, elt } => E::StructRef {
- expr: expr_map(expr, f_pre, f_post),
+ expr: expr_map(expr, f_pre, f_post, ft),
elt,
},
E::ArrayRef { expr, idx } => E::ArrayRef {
- expr: expr_map(expr, f_pre, f_post),
+ expr: expr_map(expr, f_pre, f_post, ft),
idx,
},
E::Assign { lhs, rhs } => E::Assign {
- lhs: expr_map(lhs, f_pre, f_post), // TODO: Think real hard about lvalues
- rhs: expr_map(rhs, f_pre, f_post),
+ lhs: expr_map(lhs, f_pre, f_post, ft), // TODO: Think real hard about lvalues
+ rhs: expr_map(rhs, f_pre, f_post, ft),
},
E::BinOp { op, lhs, rhs } => E::BinOp {
op,
- lhs: expr_map(lhs, f_pre, f_post),
- rhs: expr_map(rhs, f_pre, f_post),
+ lhs: expr_map(lhs, f_pre, f_post, ft),
+ rhs: expr_map(rhs, f_pre, f_post, ft),
},
E::UniOp { op, rhs } => E::UniOp {
op,
- rhs: expr_map(rhs, f_pre, f_post),
+ rhs: expr_map(rhs, f_pre, f_post, ft),
},
E::Block { body } => E::Block {
- body: exprs_map(body, f_pre, f_post),
+ body: exprs_map(body, f_pre, f_post, ft),
},
E::Let {
varname,
@@ 185,53 186,54 @@ fn expr_map(
mutable,
} => E::Let {
varname,
- typename,
- init: expr_map(init, f_pre, f_post),
+ typename: typename.map(|t| type_map(t, ft)),
+ init: expr_map(init, f_pre, f_post, ft),
mutable,
},
E::If { cases } => {
let new_cases = cases
.into_iter()
.map(|(test, case)| {
- let new_test = expr_map(test, f_pre, f_post);
- let new_cases = exprs_map(case, f_pre, f_post);
+ let new_test = expr_map(test, f_pre, f_post, ft);
+ let new_cases = exprs_map(case, f_pre, f_post, ft);
(new_test, new_cases)
})
.collect();
E::If { cases: new_cases }
}
E::Loop { body } => E::Loop {
- body: exprs_map(body, f_pre, f_post),
+ body: exprs_map(body, f_pre, f_post, ft),
},
E::Return { retval } => E::Return {
- retval: expr_map(retval, f_pre, f_post),
+ retval: expr_map(retval, f_pre, f_post, ft),
},
E::Funcall {
func,
params,
type_params,
} => {
- let new_func = expr_map(func, f_pre, f_post);
- let new_params = exprs_map(params, f_pre, f_post);
+ let new_func = expr_map(func, f_pre, f_post, ft);
+ let new_params = exprs_map(params, f_pre, f_post, ft);
+ let new_type_params = types_map(type_params, ft);
E::Funcall {
func: new_func,
params: new_params,
- type_params,
+ type_params: new_type_params,
}
}
E::Lambda { signature, body } => E::Lambda {
signature,
- body: exprs_map(body, f_pre, f_post),
+ body: exprs_map(body, f_pre, f_post, ft),
},
E::Typecast { e, to } => E::Typecast {
- e: expr_map(e, f_pre, f_post),
- to,
+ e: expr_map(e, f_pre, f_post, ft),
+ to: type_map(to, ft),
},
E::Ref { expr } => E::Ref {
- expr: expr_map(expr, f_pre, f_post),
+ expr: expr_map(expr, f_pre, f_post, ft),
},
E::Deref { expr } => E::Deref {
- expr: expr_map(expr, f_pre, f_post),
+ expr: expr_map(expr, f_pre, f_post, ft),
},
};
let post_thing = thing.map(exprfn);
@@ 239,11 241,11 @@ fn expr_map(
}
pub fn expr_map_pre(expr: ExprNode, f: &mut dyn FnMut(ExprNode) -> ExprNode) -> ExprNode {
- expr_map(expr, f, &mut id)
+ expr_map(expr, f, &mut id, &mut id)
}
pub fn expr_map_post(expr: ExprNode, f: &mut dyn FnMut(ExprNode) -> ExprNode) -> ExprNode {
- expr_map(expr, &mut id, f)
+ expr_map(expr, &mut id, f, &mut id)
}
/// Map functions over a list of exprs.
@@ 251,19 253,20 @@ fn exprs_map(
exprs: Vec<ExprNode>,
f_pre: &mut dyn FnMut(ExprNode) -> ExprNode,
f_post: &mut dyn FnMut(ExprNode) -> ExprNode,
+ ft: &mut dyn FnMut(Type) -> Type,
) -> Vec<ExprNode> {
exprs
.into_iter()
- .map(|e| expr_map(e, f_pre, f_post))
+ .map(|e| expr_map(e, f_pre, f_post, ft))
.collect()
}
fn exprs_map_pre(exprs: Vec<ExprNode>, f: &mut dyn FnMut(ExprNode) -> ExprNode) -> Vec<ExprNode> {
- exprs_map(exprs, f, &mut id)
+ exprs_map(exprs, f, &mut id, &mut id)
}
fn _exprs_map_post(exprs: Vec<ExprNode>, f: &mut dyn FnMut(ExprNode) -> ExprNode) -> Vec<ExprNode> {
- exprs_map(exprs, &mut id, f)
+ exprs_map(exprs, &mut id, f, &mut id)
}
fn decl_map_pre(
@@ 301,12 304,12 @@ fn decl_map(
} => D::Function {
name,
signature: signature_map(signature, ft),
- body: exprs_map(body, fe_pre, fe_post),
+ body: exprs_map(body, fe_pre, fe_post, ft),
},
D::Const { name, typ, init } => D::Const {
name,
typ: type_map(typ, ft),
- init: expr_map(init, fe_pre, fe_post),
+ init: expr_map(init, fe_pre, fe_post, ft),
},
D::TypeDef {
name,
@@ 2,24 2,208 @@
//! if they are not declared.
//! We could do this in the typechecker but I think it will be simpler as a preprocessing pass.
-use crate::hir::Ir;
+use crate::hir::{Decl as D, Expr as E, Ir, Signature};
use crate::passes::*;
+// This is slightly bonkers and a big dependency inversion but it also does
+// *exactly* what we want. :thonk:
+use crate::typeck::Symtbl;
-fn generic_infer_expr(expr: ExprNode) -> ExprNode {
+fn generic_infer_type(symtbl: &Symtbl, ty: Type) -> Type {
+ match ty {
+ Type::Named(nm, ref _tys) => {
+ if let Some(t) = symtbl.get_type(nm) {
+ // TODO: Do we have to recurse down the type params?
+ // or will type_map() do that for us?
+ // t should just be a Generic(nm), so we just replace this type with it.
+ t
+ } else {
+ // Not declared, just carry on
+ ty
+ }
+ }
+ _ => ty,
+ }
+}
+
+/*
+/// signature_map() doesn't do the correct thing here 'cause we have to
+/// shuffle around generic param
+fn generic_infer_sig(symtbl: &Symtbl, sig: Signature) -> Signature {
+ sig
+}
+ */
+
+/// Basically, if we see a Named type mentioned, we check to see if it's
+/// in the symtbl. If it is, we replace it with a Generic. Otherwise
+/// we leave it as is and let typeck decide whether or not it exists.
+fn generic_infer_expr(_symtbl: &Symtbl, expr: ExprNode) -> ExprNode {
expr
}
pub(super) fn generic_infer(ir: Ir) -> Ir {
- let generic_infer_expr = &mut generic_infer_expr;
- let generic_infer_ty = &mut |ty| ty;
- let new_decls: Vec<D> = ir
- .decls
- .into_iter()
- .map(|decl| decl_map_pre(decl, generic_infer_expr, generic_infer_ty))
- .collect();
+ let symtbl = Symtbl::default();
+ let generic_infer_expr = &mut |e| generic_infer_expr(&symtbl, e);
+ let generic_infer_ty = &mut |ty| generic_infer_type(&symtbl, ty);
+ // Fuck decl_map, it's not made for this. So we'll just
+ // do it by hand.
+ let mut new_decls = vec![];
+ for decl in ir.decls {
+ let d = match decl {
+ D::Function {
+ name,
+ signature,
+ body,
+ } => {
+ let _guard = symtbl.push_scope();
+ for typeparam in &signature.typeparams {
+ match typeparam {
+ Type::Named(sym, _) if *sym == Sym::new("Tuple") => (),
+ Type::Named(nm, _v) => {
+ symtbl.add_type(*nm, &Type::Generic(*nm));
+ }
+ _ => (),
+ }
+ }
+ let new_sig = signature_map(signature, generic_infer_ty);
+ D::Function {
+ name,
+ signature: new_sig,
+ body: exprs_map(body, &mut id, generic_infer_expr, generic_infer_ty),
+ }
+ }
+ D::Const { name, typ, init } => {
+ let _guard = symtbl.push_scope();
+ for name in typ.get_type_params() {
+ symtbl.add_type(name, &Type::Generic(name));
+ }
+ D::Const {
+ name,
+ typ: type_map(typ, generic_infer_ty),
+ init: expr_map(init, &mut id, generic_infer_expr, generic_infer_ty),
+ }
+ }
+ D::TypeDef {
+ name,
+ params,
+ typedecl,
+ } => {
+ let _guard = symtbl.push_scope();
+ for name in ¶ms {
+ symtbl.add_type(*name, &Type::Generic(*name));
+ }
+ D::TypeDef {
+ name,
+ params,
+ typedecl: type_map(typedecl, generic_infer_ty),
+ }
+ }
+ D::Import { .. } => decl,
+ };
+ new_decls.push(d);
+ }
Ir {
decls: new_decls,
..ir
}
}
+
+#[cfg(test)]
+mod tests {
+ use crate::hir::{Decl as D, Ir};
+ use crate::*;
+
+ #[test]
+ fn heckin_heck() {
+ let typedef = D::TypeDef {
+ name: Sym::new("thing"),
+ params: vec![Sym::new("T")],
+ typedecl: Type::Named(Sym::new("T"), vec![]),
+ };
+ let ir = Ir {
+ decls: vec![typedef],
+ filename: String::from("test"),
+ modulename: String::from("test"),
+ };
+ let res = super::generic_infer(ir);
+
+ let wanted_typedef = D::TypeDef {
+ name: Sym::new("thing"),
+ params: vec![Sym::new("T")],
+ typedecl: Type::generic("T"),
+ };
+
+ assert_eq!(res.decls[0], wanted_typedef);
+ }
+
+ #[test]
+ fn heckin_heck2() {
+ let structbody = [
+ (Sym::new("a"), Type::i32()),
+ (Sym::new("b"), Type::Named(Sym::new("T"), vec![])),
+ ];
+ let typedef = D::TypeDef {
+ name: Sym::new("thing"),
+ params: vec![Sym::new("T")],
+ typedecl: Type::Struct(BTreeMap::from(structbody), vec![]),
+ };
+ let ir = Ir {
+ decls: vec![typedef],
+ filename: String::from("test"),
+ modulename: String::from("test"),
+ };
+ let res = super::generic_infer(ir);
+
+ let wanted_structbody = [
+ (Sym::new("a"), Type::i32()),
+ (Sym::new("b"), Type::generic("T")),
+ ];
+ let wanted_typedef = D::TypeDef {
+ name: Sym::new("thing"),
+ params: vec![Sym::new("T")],
+ typedecl: Type::Struct(BTreeMap::from(wanted_structbody), vec![]),
+ };
+
+ assert_eq!(res.decls[0], wanted_typedef);
+ }
+
+ /// Todo: maybe check out nested functions?
+ #[test]
+ fn heckin_heck3() {
+ let sig1 = hir::Signature {
+ params: vec![
+ (Sym::new("a"), Type::named0("T")),
+ (Sym::new("b"), Type::named0("Something")),
+ ],
+ rettype: Type::Named(Sym::new("T"), vec![]),
+ typeparams: vec![Type::Named(Sym::new("T"), vec![])],
+ };
+ let f1 = D::Function {
+ name: Sym::new("foo"),
+ signature: sig1,
+ body: vec![],
+ };
+ let ir = Ir {
+ decls: vec![f1],
+ filename: String::from("test"),
+ modulename: String::from("test"),
+ };
+ let res = super::generic_infer(ir);
+
+ let wanted_sig = hir::Signature {
+ params: vec![
+ (Sym::new("a"), Type::generic("T")),
+ (Sym::new("b"), Type::named0("Something")),
+ ],
+ rettype: Type::generic("T"),
+ typeparams: vec![Type::generic("T")],
+ };
+ let wanted_f = D::Function {
+ name: Sym::new("foo"),
+ signature: wanted_sig,
+ body: vec![],
+ };
+
+ assert_eq!(res.decls[0], wanted_f);
+ }
+}