Skip to content

Instantly share code, notes, and snippets.

@bryal
Created January 23, 2018 13:13
Show Gist options
  • Save bryal/3bffd551f060df4f2ba2dd51ba081499 to your computer and use it in GitHub Desktop.
Save bryal/3bffd551f060df4f2ba2dd51ba081499 to your computer and use it in GitHub Desktop.
match *tree {
// Type application, e.g. `(Vec Int32)`; or type variable with constraints,
// e.g. `(: t Num)`
CST::SExpr(ref app, ref pos) if !app.is_empty() => match app[0] {
CST::Ident(":", _) if app.len() > 2 => {
let tv = self.parse_constraints_spec(&app[1..]);
let name = tv.explicit.unwrap();
if tvars.contains_key(name) {
let first_pos = &tvars.get(name).unwrap().1;
pos.error("Type variable has already been defined in this scope");
first_pos.note(
"A type variable is implicitly defined the first time it is used \
in a scope.\nTry removing the constraints of this instance of \
the type variable, \nand add them to the first instance instead.\n\
The first instance of the type variable is here:",
);
exit()
} else {
tvars.insert(tv.explicit.unwrap(), (tv.clone(), pos.clone()));
Type::Var(tv)
}
}
CST::Ident(":", _) => pos.error_exit(
"Constraint specification requires at least two arguments: \
the type variable to constrain, and one/multiple constraint(s)",
),
CST::Ident("->", _) if app.len() < 3 => pos.error_exit(
"Function type constructor requires at least two arguments: \
one/multiple input type(s) and an output type",
),
CST::Ident("->", _) if app.len() == 3 => Type::new_func(
self.parse_type_with_tvars(tvars, &app[1]),
self.parse_type_with_tvars(tvars, &app[2]),
),
CST::Ident("->", _) => {
let last_fn = Type::new_func(
self.parse_type_with_tvars(tvars, &app[app.len() - 2]),
self.parse_type_with_tvars(tvars, &app[app.len() - 1]),
);
app[1..app.len() - 2].iter().rev().fold(last_fn, |acc, t| {
Type::new_func(self.parse_type_with_tvars(tvars, t), acc)
})
}
CST::Ident("Cons", _) if app.len() == 3 => Type::new_cons(
self.parse_type_with_tvars(tvars, &app[1]),
self.parse_type_with_tvars(tvars, &app[2]),
),
CST::Ident("Cons", _) => pos.error_exit(ArityMis(2, app.len() - 1)),
CST::Ident("Ptr", _) if app.len() == 2 => {
Type::new_ptr(self.parse_type_with_tvars(tvars, &app[1]))
}
CST::Ident("Ptr", _) => pos.error_exit(ArityMis(1, app.len() - 1)),
CST::Ident(c, ref c_pos) => {
c_pos.error_exit(format!("Undefined type constructor `{}`", c))
}
_ => app[0].pos().error_exit(Invalid("type constructor")),
},
CST::SExpr(_, ref pos) => pos.error_exit("Empty type application"),
CST::Ident("_", _) => self.gen_type_var(),
CST::Ident("Nil", _) => TYPE_NIL.clone(),
// The type identifier starts with a lowercase letter => Is a type variable
CST::Ident(s, ref pos) if s.starts_with(char::is_lowercase) => {
let tv = tvars
.entry(s)
.or_insert((
TVar {
id: self.type_var_gen.gen(),
constrs: BTreeSet::new(),
explicit: Some(s),
},
pos.clone(),
))
.0
.clone();
Type::Var(tv)
}
// Doesn't start with lowercase => Is a type constant e.g. Int32
CST::Ident(s, ref pos) => Type::Const(s, Some(pos.clone())),
CST::Num(_, ref pos) => pos.error_exit(Mismatch("type", "numeric literal")),
CST::Str(_, ref pos) => pos.error_exit(Mismatch("type", "string literal")),
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment