Created
January 23, 2018 13:13
-
-
Save bryal/3bffd551f060df4f2ba2dd51ba081499 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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