mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +00:00
Parse abilities
This commit is contained in:
parent
1b0ff9c163
commit
d7abc3897b
30 changed files with 1018 additions and 13 deletions
|
@ -23,6 +23,20 @@ pub enum Spaced<'a, T> {
|
|||
SpaceAfter(&'a Spaced<'a, T>, &'a [CommentOrNewline<'a>]),
|
||||
}
|
||||
|
||||
impl<'a, T> Spaced<'a, T> {
|
||||
/// A `Spaced` is multiline if it has newlines or comments before or after the item, since
|
||||
/// comments induce newlines!
|
||||
pub fn is_multiline(&self) -> bool {
|
||||
match self {
|
||||
Spaced::Item(_) => false,
|
||||
Spaced::SpaceBefore(_, spaces) | Spaced::SpaceAfter(_, spaces) => {
|
||||
debug_assert!(!spaces.is_empty());
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Debug> Debug for Spaced<'a, T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
|
@ -248,6 +262,22 @@ impl<'a> TypeHeader<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The `has` keyword associated with ability definitions.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Has<'a> {
|
||||
Has,
|
||||
SpaceBefore(&'a Has<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a Has<'a>, &'a [CommentOrNewline<'a>]),
|
||||
}
|
||||
|
||||
/// An ability demand is a value defining the ability; for example `hash : a -> U64 | a has Hash`
|
||||
/// for a `Hash` ability.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct AbilityDemand<'a> {
|
||||
pub name: Loc<Spaced<'a, &'a str>>,
|
||||
pub typ: Loc<TypeAnnotation<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Def<'a> {
|
||||
// TODO in canonicalization, validate the pattern; only certain patterns
|
||||
|
@ -269,6 +299,15 @@ pub enum Def<'a> {
|
|||
typ: Loc<TypeAnnotation<'a>>,
|
||||
},
|
||||
|
||||
/// An ability definition. E.g.
|
||||
/// Hash has
|
||||
/// hash : a -> U64 | a has Hash
|
||||
Ability {
|
||||
header: TypeHeader<'a>,
|
||||
loc_has: Loc<Has<'a>>,
|
||||
demands: &'a [AbilityDemand<'a>],
|
||||
},
|
||||
|
||||
// TODO in canonicalization, check to see if there are any newlines after the
|
||||
// annotation; if not, and if it's followed by a Body, then the annotation
|
||||
// applies to that expr! (TODO: verify that the pattern for both annotation and body match.)
|
||||
|
@ -304,6 +343,13 @@ impl<'a> Def<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct HasClause<'a> {
|
||||
pub var: Loc<Spaced<'a, &'a str>>,
|
||||
// Should always be a zero-argument `Apply`; we'll check this in canonicalization
|
||||
pub ability: Loc<TypeAnnotation<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum TypeAnnotation<'a> {
|
||||
/// A function. The types of its arguments, then the type of its return value.
|
||||
|
@ -343,6 +389,9 @@ pub enum TypeAnnotation<'a> {
|
|||
/// The `*` type variable, e.g. in (List *)
|
||||
Wildcard,
|
||||
|
||||
/// A "where" clause demanding abilities designated by a `|`, e.g. `a -> U64 | a has Hash`
|
||||
Where(&'a Loc<TypeAnnotation<'a>>, &'a [Loc<HasClause<'a>>]),
|
||||
|
||||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
SpaceBefore(&'a TypeAnnotation<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a TypeAnnotation<'a>, &'a [CommentOrNewline<'a>]),
|
||||
|
@ -814,6 +863,15 @@ impl<'a> Spaceable<'a> for Def<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Spaceable<'a> for Has<'a> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
Has::SpaceBefore(self, spaces)
|
||||
}
|
||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
Has::SpaceAfter(self, spaces)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Expr<'a> {
|
||||
pub fn loc_ref(&'a self, region: Region) -> Loc<&'a Self> {
|
||||
Loc {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue