mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Merge remote-tracking branch 'origin/trunk' into builtins-in-roc
This commit is contained in:
commit
1d0f9e9192
178 changed files with 5342 additions and 3304 deletions
|
@ -273,17 +273,13 @@ pub enum Has<'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 struct AbilityMember<'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
|
||||
// are allowed in annotations.
|
||||
Annotation(Loc<Pattern<'a>>, Loc<TypeAnnotation<'a>>),
|
||||
|
||||
pub enum TypeDef<'a> {
|
||||
/// A type alias. This is like a standalone annotation, except the pattern
|
||||
/// must be a capitalized Identifier, e.g.
|
||||
///
|
||||
|
@ -305,8 +301,15 @@ pub enum Def<'a> {
|
|||
Ability {
|
||||
header: TypeHeader<'a>,
|
||||
loc_has: Loc<Has<'a>>,
|
||||
demands: &'a [AbilityDemand<'a>],
|
||||
members: &'a [AbilityMember<'a>],
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum ValueDef<'a> {
|
||||
// TODO in canonicalization, validate the pattern; only certain patterns
|
||||
// are allowed in annotations.
|
||||
Annotation(Loc<Pattern<'a>>, Loc<TypeAnnotation<'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
|
||||
|
@ -323,6 +326,12 @@ pub enum Def<'a> {
|
|||
},
|
||||
|
||||
Expect(&'a Loc<Expr<'a>>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Def<'a> {
|
||||
Type(TypeDef<'a>),
|
||||
Value(ValueDef<'a>),
|
||||
|
||||
// Blank Space (e.g. comments, spaces, newlines) before or after a def.
|
||||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
|
@ -341,6 +350,30 @@ impl<'a> Def<'a> {
|
|||
debug_assert!(!matches!(def, Def::SpaceBefore(_, _)));
|
||||
(spaces, def)
|
||||
}
|
||||
|
||||
pub fn unroll_def(&self) -> Result<&TypeDef<'a>, &ValueDef<'a>> {
|
||||
let mut def = self;
|
||||
loop {
|
||||
match def {
|
||||
Def::Type(type_def) => return Ok(type_def),
|
||||
Def::Value(value_def) => return Err(value_def),
|
||||
Def::SpaceBefore(def1, _) | Def::SpaceAfter(def1, _) => def = def1,
|
||||
Def::NotYetImplemented(s) => todo!("{}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<TypeDef<'a>> for Def<'a> {
|
||||
fn from(def: TypeDef<'a>) -> Self {
|
||||
Self::Type(def)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<ValueDef<'a>> for Def<'a> {
|
||||
fn from(def: ValueDef<'a>) -> Self {
|
||||
Self::Value(def)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ast::{
|
||||
AssignedField, Collection, CommentOrNewline, Def, Expr, ExtractSpaces, Has, Pattern, Spaceable,
|
||||
TypeAnnotation, TypeHeader,
|
||||
TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||
};
|
||||
use crate::blankspace::{space0_after_e, space0_around_ee, space0_before_e, space0_e};
|
||||
use crate::ident::{lowercase_ident, parse_ident, Ident};
|
||||
|
@ -10,7 +10,7 @@ use crate::parser::{
|
|||
trailing_sep_by0, word1, word2, EExpect, EExpr, EIf, EInParens, ELambda, EList, ENumber,
|
||||
EPattern, ERecord, EString, EType, EWhen, Either, ParseResult, Parser,
|
||||
};
|
||||
use crate::pattern::loc_closure_param;
|
||||
use crate::pattern::{loc_closure_param, loc_has_parser};
|
||||
use crate::state::State;
|
||||
use crate::type_annotation;
|
||||
use bumpalo::collections::Vec;
|
||||
|
@ -576,7 +576,7 @@ fn append_body_definition<'a>(
|
|||
if spaces.len() <= 1 {
|
||||
let last = defs.pop();
|
||||
match last.map(|d| d.value.unroll_spaces_before()) {
|
||||
Some((before_ann_spaces, Def::Annotation(ann_pattern, ann_type))) => {
|
||||
Some((before_ann_spaces, Def::Value(ValueDef::Annotation(ann_pattern, ann_type)))) => {
|
||||
return append_body_definition_help(
|
||||
arena,
|
||||
defs,
|
||||
|
@ -591,10 +591,10 @@ fn append_body_definition<'a>(
|
|||
}
|
||||
Some((
|
||||
before_ann_spaces,
|
||||
Def::Alias {
|
||||
Def::Type(TypeDef::Alias {
|
||||
header,
|
||||
ann: ann_type,
|
||||
},
|
||||
}),
|
||||
)) => {
|
||||
// This is a case like
|
||||
// UserId x : [ UserId Int ]
|
||||
|
@ -628,7 +628,10 @@ fn append_body_definition<'a>(
|
|||
// the previous and current def can't be joined up
|
||||
let mut loc_def = Loc::at(
|
||||
region,
|
||||
Def::Body(arena.alloc(loc_pattern), &*arena.alloc(loc_def_body)),
|
||||
Def::Value(ValueDef::Body(
|
||||
arena.alloc(loc_pattern),
|
||||
&*arena.alloc(loc_def_body),
|
||||
)),
|
||||
);
|
||||
|
||||
if !spaces.is_empty() {
|
||||
|
@ -660,13 +663,13 @@ fn append_body_definition_help<'a>(
|
|||
|
||||
let mut loc_def = Loc::at(
|
||||
region,
|
||||
Def::AnnotatedBody {
|
||||
Def::Value(ValueDef::AnnotatedBody {
|
||||
ann_pattern: loc_pattern_ann,
|
||||
ann_type: loc_ann,
|
||||
comment,
|
||||
body_pattern: arena.alloc(loc_pattern_body),
|
||||
body_expr: &*arena.alloc(loc_def_body),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
if !before_ann_spaces.is_empty() {
|
||||
|
@ -717,7 +720,10 @@ fn append_annotation_definition<'a>(
|
|||
kind,
|
||||
),
|
||||
_ => {
|
||||
let mut loc_def = Loc::at(region, Def::Annotation(loc_pattern, loc_ann));
|
||||
let mut loc_def = Loc::at(
|
||||
region,
|
||||
Def::Value(ValueDef::Annotation(loc_pattern, loc_ann)),
|
||||
);
|
||||
if !spaces.is_empty() {
|
||||
loc_def = arena
|
||||
.alloc(loc_def.value)
|
||||
|
@ -736,7 +742,7 @@ fn append_expect_definition<'a>(
|
|||
spaces: &'a [CommentOrNewline<'a>],
|
||||
loc_expect_body: Loc<Expr<'a>>,
|
||||
) {
|
||||
let def = Def::Expect(arena.alloc(loc_expect_body));
|
||||
let def: Def = ValueDef::Expect(arena.alloc(loc_expect_body)).into();
|
||||
|
||||
let end = loc_expect_body.region.end();
|
||||
let region = Region::new(start, end);
|
||||
|
@ -768,16 +774,16 @@ fn append_type_definition<'a>(
|
|||
vars: pattern_arguments,
|
||||
};
|
||||
let def = match kind {
|
||||
TypeKind::Alias => Def::Alias {
|
||||
TypeKind::Alias => TypeDef::Alias {
|
||||
header,
|
||||
ann: loc_ann,
|
||||
},
|
||||
TypeKind::Opaque => Def::Opaque {
|
||||
TypeKind::Opaque => TypeDef::Opaque {
|
||||
header,
|
||||
typ: loc_ann,
|
||||
},
|
||||
};
|
||||
let mut loc_def = Loc::at(region, def);
|
||||
let mut loc_def = Loc::at(region, Def::Type(def));
|
||||
|
||||
if !spaces.is_empty() {
|
||||
loc_def = arena
|
||||
|
@ -858,55 +864,89 @@ fn parse_defs_end<'a>(
|
|||
// a hacky way to get expression-based error messages. TODO fix this
|
||||
Ok((NoProgress, def_state, initial))
|
||||
}
|
||||
Ok((_, loc_pattern, state)) => match operator().parse(arena, state) {
|
||||
Ok((_, BinOp::Assignment, state)) => {
|
||||
let parse_def_expr = space0_before_e(
|
||||
move |a, s| parse_loc_expr(min_indent + 1, a, s),
|
||||
min_indent,
|
||||
EExpr::IndentEnd,
|
||||
);
|
||||
|
||||
let (_, loc_def_expr, state) = parse_def_expr.parse(arena, state)?;
|
||||
|
||||
append_body_definition(
|
||||
arena,
|
||||
&mut def_state.defs,
|
||||
def_state.spaces_after,
|
||||
loc_pattern,
|
||||
loc_def_expr,
|
||||
);
|
||||
|
||||
parse_defs_end(options, column, def_state, arena, state)
|
||||
}
|
||||
Ok((_, op @ (BinOp::IsAliasType | BinOp::IsOpaqueType), state)) => {
|
||||
let (_, ann_type, state) = specialize(
|
||||
EExpr::Type,
|
||||
space0_before_e(
|
||||
type_annotation::located_help(min_indent + 1, false),
|
||||
min_indent + 1,
|
||||
EType::TIndentStart,
|
||||
Ok((_, loc_pattern, state)) => {
|
||||
// First let's check whether this is an ability definition.
|
||||
if let Loc {
|
||||
value:
|
||||
Pattern::Apply(
|
||||
loc_name @ Loc {
|
||||
value: Pattern::GlobalTag(name),
|
||||
..
|
||||
},
|
||||
args,
|
||||
),
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
..
|
||||
} = loc_pattern
|
||||
{
|
||||
if let Ok((_, loc_has, state)) =
|
||||
loc_has_parser(min_indent).parse(arena, state.clone())
|
||||
{
|
||||
let (_, loc_def, state) = finish_parsing_ability_def(
|
||||
start_column,
|
||||
Loc::at(loc_name.region, name),
|
||||
args,
|
||||
loc_has,
|
||||
arena,
|
||||
state,
|
||||
)?;
|
||||
|
||||
append_annotation_definition(
|
||||
arena,
|
||||
&mut def_state.defs,
|
||||
def_state.spaces_after,
|
||||
loc_pattern,
|
||||
ann_type,
|
||||
match op {
|
||||
BinOp::IsAliasType => TypeKind::Alias,
|
||||
BinOp::IsOpaqueType => TypeKind::Opaque,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
def_state.defs.push(loc_def);
|
||||
|
||||
parse_defs_end(options, column, def_state, arena, state)
|
||||
return parse_defs_end(options, column, def_state, arena, state);
|
||||
}
|
||||
}
|
||||
|
||||
_ => Ok((MadeProgress, def_state, initial)),
|
||||
},
|
||||
// Otherwise, this is a def or alias.
|
||||
match operator().parse(arena, state) {
|
||||
Ok((_, BinOp::Assignment, state)) => {
|
||||
let parse_def_expr = space0_before_e(
|
||||
move |a, s| parse_loc_expr(min_indent + 1, a, s),
|
||||
min_indent,
|
||||
EExpr::IndentEnd,
|
||||
);
|
||||
|
||||
let (_, loc_def_expr, state) = parse_def_expr.parse(arena, state)?;
|
||||
|
||||
append_body_definition(
|
||||
arena,
|
||||
&mut def_state.defs,
|
||||
def_state.spaces_after,
|
||||
loc_pattern,
|
||||
loc_def_expr,
|
||||
);
|
||||
|
||||
parse_defs_end(options, column, def_state, arena, state)
|
||||
}
|
||||
Ok((_, op @ (BinOp::IsAliasType | BinOp::IsOpaqueType), state)) => {
|
||||
let (_, ann_type, state) = specialize(
|
||||
EExpr::Type,
|
||||
space0_before_e(
|
||||
type_annotation::located_help(min_indent + 1, false),
|
||||
min_indent + 1,
|
||||
EType::TIndentStart,
|
||||
),
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
|
||||
append_annotation_definition(
|
||||
arena,
|
||||
&mut def_state.defs,
|
||||
def_state.spaces_after,
|
||||
loc_pattern,
|
||||
ann_type,
|
||||
match op {
|
||||
BinOp::IsAliasType => TypeKind::Alias,
|
||||
BinOp::IsOpaqueType => TypeKind::Opaque,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
|
||||
parse_defs_end(options, column, def_state, arena, state)
|
||||
}
|
||||
|
||||
_ => Ok((MadeProgress, def_state, initial)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1004,17 +1044,17 @@ fn finish_parsing_alias_or_opaque<'a>(
|
|||
vars: type_arguments.into_bump_slice(),
|
||||
};
|
||||
let type_def = match kind {
|
||||
TypeKind::Alias => Def::Alias {
|
||||
TypeKind::Alias => TypeDef::Alias {
|
||||
header,
|
||||
ann: ann_type,
|
||||
},
|
||||
TypeKind::Opaque => Def::Opaque {
|
||||
TypeKind::Opaque => TypeDef::Opaque {
|
||||
header,
|
||||
typ: ann_type,
|
||||
},
|
||||
};
|
||||
|
||||
(&*arena.alloc(Loc::at(def_region, type_def)), state)
|
||||
(&*arena.alloc(Loc::at(def_region, type_def.into())), state)
|
||||
}
|
||||
|
||||
_ => {
|
||||
|
@ -1043,9 +1083,9 @@ fn finish_parsing_alias_or_opaque<'a>(
|
|||
|
||||
let def_region = Region::span_across(&call.region, &ann_type.region);
|
||||
|
||||
let alias = Def::Annotation(Loc::at(expr_region, good), ann_type);
|
||||
let alias = ValueDef::Annotation(Loc::at(expr_region, good), ann_type);
|
||||
|
||||
(&*arena.alloc(Loc::at(def_region, alias)), state)
|
||||
(&*arena.alloc(Loc::at(def_region, alias.into())), state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1074,14 +1114,14 @@ fn finish_parsing_alias_or_opaque<'a>(
|
|||
mod ability {
|
||||
use super::*;
|
||||
use crate::{
|
||||
ast::{AbilityDemand, Spaceable, Spaced},
|
||||
ast::{AbilityMember, Spaceable, Spaced},
|
||||
parser::EAbility,
|
||||
};
|
||||
|
||||
/// Parses a single ability demand line; see `parse_demand`.
|
||||
fn parse_demand_help<'a>(
|
||||
start_column: u32,
|
||||
) -> impl Parser<'a, AbilityDemand<'a>, EAbility<'a>> {
|
||||
) -> impl Parser<'a, AbilityMember<'a>, EAbility<'a>> {
|
||||
map!(
|
||||
and!(
|
||||
specialize(|_, pos| EAbility::DemandName(pos), loc!(lowercase_ident())),
|
||||
|
@ -1099,7 +1139,7 @@ mod ability {
|
|||
)
|
||||
),
|
||||
|(name, typ): (Loc<&'a str>, Loc<TypeAnnotation<'a>>)| {
|
||||
AbilityDemand {
|
||||
AbilityMember {
|
||||
name: name.map_owned(Spaced::Item),
|
||||
typ,
|
||||
}
|
||||
|
@ -1117,7 +1157,7 @@ mod ability {
|
|||
/// This is basically the same as parsing a free-floating annotation, but with stricter rules.
|
||||
pub fn parse_demand<'a>(
|
||||
indent: IndentLevel,
|
||||
) -> impl Parser<'a, (u32, AbilityDemand<'a>), EAbility<'a>> {
|
||||
) -> impl Parser<'a, (u32, AbilityMember<'a>), EAbility<'a>> {
|
||||
move |arena, state: State<'a>| {
|
||||
let initial = state.clone();
|
||||
|
||||
|
@ -1190,15 +1230,14 @@ mod ability {
|
|||
}
|
||||
}
|
||||
|
||||
fn finish_parsing_ability<'a>(
|
||||
fn finish_parsing_ability_def<'a>(
|
||||
start_column: u32,
|
||||
options: ExprParseOptions,
|
||||
name: Loc<&'a str>,
|
||||
args: &'a [Loc<Pattern<'a>>],
|
||||
loc_has: Loc<Has<'a>>,
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
||||
) -> ParseResult<'a, &'a Loc<Def<'a>>, EExpr<'a>> {
|
||||
let mut demands = Vec::with_capacity_in(2, arena);
|
||||
|
||||
let min_indent_for_demand = start_column + 1;
|
||||
|
@ -1237,13 +1276,29 @@ fn finish_parsing_ability<'a>(
|
|||
}
|
||||
|
||||
let def_region = Region::span_across(&name.region, &demands.last().unwrap().typ.region);
|
||||
let def = Def::Ability {
|
||||
let def = TypeDef::Ability {
|
||||
header: TypeHeader { name, vars: args },
|
||||
loc_has,
|
||||
demands: demands.into_bump_slice(),
|
||||
};
|
||||
members: demands.into_bump_slice(),
|
||||
}
|
||||
.into();
|
||||
let loc_def = &*(arena.alloc(Loc::at(def_region, def)));
|
||||
|
||||
Ok((MadeProgress, loc_def, state))
|
||||
}
|
||||
|
||||
fn finish_parsing_ability<'a>(
|
||||
start_column: u32,
|
||||
options: ExprParseOptions,
|
||||
name: Loc<&'a str>,
|
||||
args: &'a [Loc<Pattern<'a>>],
|
||||
loc_has: Loc<Has<'a>>,
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
||||
let (_, loc_def, state) =
|
||||
finish_parsing_ability_def(start_column, name, args, loc_has, arena, state)?;
|
||||
|
||||
let def_state = DefState {
|
||||
defs: bumpalo::vec![in arena; loc_def],
|
||||
spaces_after: &[],
|
||||
|
@ -1309,23 +1364,24 @@ fn parse_expr_operator<'a>(
|
|||
let (loc_def, state) = {
|
||||
match expr_to_pattern_help(arena, &call.value) {
|
||||
Ok(good) => {
|
||||
let (_, mut ann_type, state) = parse_loc_expr(indented_more, arena, state)?;
|
||||
let (_, mut body, state) = parse_loc_expr(indented_more, arena, state)?;
|
||||
|
||||
// put the spaces from after the operator in front of the call
|
||||
if !spaces_after_operator.is_empty() {
|
||||
ann_type = arena
|
||||
.alloc(ann_type.value)
|
||||
.with_spaces_before(spaces_after_operator, ann_type.region);
|
||||
body = arena
|
||||
.alloc(body.value)
|
||||
.with_spaces_before(spaces_after_operator, body.region);
|
||||
}
|
||||
|
||||
let alias_region = Region::span_across(&call.region, &ann_type.region);
|
||||
let body_region = Region::span_across(&call.region, &body.region);
|
||||
|
||||
let alias = Def::Body(
|
||||
let alias = ValueDef::Body(
|
||||
arena.alloc(Loc::at(expr_region, good)),
|
||||
arena.alloc(ann_type),
|
||||
);
|
||||
arena.alloc(body),
|
||||
)
|
||||
.into();
|
||||
|
||||
(&*arena.alloc(Loc::at(alias_region, alias)), state)
|
||||
(&*arena.alloc(Loc::at(body_region, alias)), state)
|
||||
}
|
||||
Err(_) => {
|
||||
// this `=` likely occurred inline; treat it as an invalid operator
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::ast::Pattern;
|
||||
use crate::ast::{Has, Pattern};
|
||||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||
use crate::ident::{lowercase_ident, parse_ident, Ident};
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
backtrackable, optional, specialize, specialize_ref, word1, EPattern, PInParens, PRecord,
|
||||
backtrackable, optional, specialize, specialize_ref, then, word1, EPattern, PInParens, PRecord,
|
||||
ParseResult, Parser,
|
||||
};
|
||||
use crate::state::State;
|
||||
|
@ -68,32 +68,63 @@ pub fn loc_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>
|
|||
fn loc_tag_pattern_args_help<'a>(
|
||||
min_indent: u32,
|
||||
) -> impl Parser<'a, Vec<'a, Loc<Pattern<'a>>>, EPattern<'a>> {
|
||||
zero_or_more!(loc_tag_pattern_arg(min_indent))
|
||||
zero_or_more!(loc_tag_pattern_arg(min_indent, false))
|
||||
}
|
||||
|
||||
fn loc_tag_pattern_arg<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
/// Like `loc_tag_pattern_args_help`, but stops if a "has" keyword is seen (indicating an ability).
|
||||
fn loc_type_def_tag_pattern_args_help<'a>(
|
||||
min_indent: u32,
|
||||
) -> impl Parser<'a, Vec<'a, Loc<Pattern<'a>>>, EPattern<'a>> {
|
||||
zero_or_more!(loc_tag_pattern_arg(min_indent, true))
|
||||
}
|
||||
|
||||
fn loc_tag_pattern_arg<'a>(
|
||||
min_indent: u32,
|
||||
stop_on_has_kw: bool,
|
||||
) -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
// Don't parse operators, because they have a higher precedence than function application.
|
||||
// If we encounter one, we're done parsing function args!
|
||||
move |arena, state| {
|
||||
let (_, spaces, state) =
|
||||
backtrackable(space0_e(min_indent, EPattern::IndentStart)).parse(arena, state)?;
|
||||
move |arena, original_state: State<'a>| {
|
||||
let (_, spaces, state) = backtrackable(space0_e(min_indent, EPattern::IndentStart))
|
||||
.parse(arena, original_state.clone())?;
|
||||
|
||||
let (_, loc_pat, state) = loc_parse_tag_pattern_arg(min_indent, arena, state)?;
|
||||
|
||||
let Loc { region, value } = loc_pat;
|
||||
|
||||
Ok((
|
||||
MadeProgress,
|
||||
if spaces.is_empty() {
|
||||
Loc::at(region, value)
|
||||
} else {
|
||||
Loc::at(region, Pattern::SpaceBefore(arena.alloc(value), spaces))
|
||||
},
|
||||
state,
|
||||
))
|
||||
if stop_on_has_kw && matches!(value, Pattern::Identifier("has")) {
|
||||
Err((
|
||||
NoProgress,
|
||||
EPattern::End(original_state.pos()),
|
||||
original_state,
|
||||
))
|
||||
} else {
|
||||
Ok((
|
||||
MadeProgress,
|
||||
if spaces.is_empty() {
|
||||
Loc::at(region, value)
|
||||
} else {
|
||||
Loc::at(region, Pattern::SpaceBefore(arena.alloc(value), spaces))
|
||||
},
|
||||
state,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loc_has_parser<'a>(min_indent: u32) -> impl Parser<'a, Loc<Has<'a>>, EPattern<'a>> {
|
||||
then(
|
||||
loc_tag_pattern_arg(min_indent, false),
|
||||
|_arena, state, progress, pattern| {
|
||||
if matches!(pattern.value, Pattern::Identifier("has")) {
|
||||
Ok((progress, Loc::at(pattern.region, Has::Has), state))
|
||||
} else {
|
||||
Err((progress, EPattern::End(state.pos()), state))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn loc_parse_tag_pattern_arg<'a>(
|
||||
min_indent: u32,
|
||||
arena: &'a Bump,
|
||||
|
@ -191,7 +222,7 @@ fn loc_ident_pattern_help<'a>(
|
|||
// Make sure `Foo Bar 1` is parsed as `Foo (Bar) 1`, and not `Foo (Bar 1)`
|
||||
if can_have_arguments {
|
||||
let (_, loc_args, state) =
|
||||
loc_tag_pattern_args_help(min_indent).parse(arena, state)?;
|
||||
loc_type_def_tag_pattern_args_help(min_indent).parse(arena, state)?;
|
||||
|
||||
if loc_args.is_empty() {
|
||||
Ok((MadeProgress, loc_tag, state))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue