mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +00:00
work on moving ident_etc over
This commit is contained in:
parent
64eed62b69
commit
75344ece40
5 changed files with 312 additions and 33 deletions
|
@ -337,11 +337,25 @@ fn loc_parse_expr_body_without_operators<'a>(
|
|||
loc!(unary_op(min_indent)),
|
||||
loc!(when::expr(min_indent)),
|
||||
loc!(if_expr(min_indent)),
|
||||
loc!(ident_etc(min_indent))
|
||||
loc!(ident_etc(min_indent)),
|
||||
fail_expr_start()
|
||||
)
|
||||
.parse(arena, state)
|
||||
}
|
||||
|
||||
fn fail_expr_start<'a, T>() -> impl Parser<'a, T, SyntaxError<'a>>
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
|_arena, state: State<'a>| {
|
||||
Err((
|
||||
NoProgress,
|
||||
SyntaxError::Expr(EExpr::Start(state.line, state.column)),
|
||||
state,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Unary (!) or (-)
|
||||
///
|
||||
/// e.g. `!x` or `-x`
|
||||
|
@ -790,6 +804,22 @@ fn spaces_then_comment_or_newline<'a>() -> impl Parser<'a, Option<&'a str>, Synt
|
|||
)
|
||||
}
|
||||
|
||||
fn spaces_then_comment_or_newline_help<'a>() -> impl Parser<'a, Option<&'a str>, EExpr<'a>> {
|
||||
specialize_ref(
|
||||
EExpr::Syntax,
|
||||
skip_first!(
|
||||
zero_or_more!(ascii_char(b' ')),
|
||||
map!(
|
||||
either!(newline_char(), line_comment()),
|
||||
|either_comment_or_newline| match either_comment_or_newline {
|
||||
Either::First(_) => None,
|
||||
Either::Second(comment) => Some(comment),
|
||||
}
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
type Body<'a> = (Located<Pattern<'a>>, Located<Expr<'a>>);
|
||||
|
||||
fn body_at_indent<'a>(indent_level: u16) -> impl Parser<'a, Body<'a>, SyntaxError<'a>> {
|
||||
|
@ -808,6 +838,10 @@ fn body_at_indent<'a>(indent_level: u16) -> impl Parser<'a, Body<'a>, SyntaxErro
|
|||
)
|
||||
}
|
||||
|
||||
fn body_at_indent_help<'a>(indent_level: u16) -> impl Parser<'a, Body<'a>, EExpr<'a>> {
|
||||
specialize_ref(EExpr::Syntax, body_at_indent(indent_level))
|
||||
}
|
||||
|
||||
fn annotation_or_alias<'a>(
|
||||
arena: &'a Bump,
|
||||
pattern: &Pattern<'a>,
|
||||
|
@ -1017,6 +1051,125 @@ fn parse_def_expr<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_def_signature_help<'a>(
|
||||
min_indent: u16,
|
||||
colon_indent: u16,
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
loc_first_pattern: Located<Pattern<'a>>,
|
||||
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
|
||||
let original_indent = state.indent_col;
|
||||
|
||||
if original_indent < min_indent {
|
||||
Err((
|
||||
NoProgress,
|
||||
EExpr::IndentDefBody(state.line, state.column),
|
||||
state,
|
||||
))
|
||||
// `<` because ':' should be same indent or greater
|
||||
} else if colon_indent < original_indent {
|
||||
Err((
|
||||
NoProgress,
|
||||
EExpr::IndentDefBody(state.line, state.column),
|
||||
state,
|
||||
))
|
||||
} else {
|
||||
// Indented more beyond the original indent.
|
||||
let indented_more = original_indent + 1;
|
||||
|
||||
and!(
|
||||
// Parse the first annotation. It doesn't need any spaces
|
||||
// around it parsed, because both the subsquent defs and the
|
||||
// final body will have space1_before on them.
|
||||
//
|
||||
// It should be indented more than the original, and it will
|
||||
// end when outdented again.
|
||||
and_then_with_indent_level(
|
||||
space0_before_e(
|
||||
specialize(EExpr::Type, type_annotation::located_help(indented_more)),
|
||||
min_indent,
|
||||
EExpr::Space,
|
||||
EExpr::IndentAnnotation
|
||||
),
|
||||
// The first annotation may be immediately (spaces_then_comment_or_newline())
|
||||
// followed by a body at the exact same indent_level
|
||||
// leading to an AnnotatedBody in this case
|
||||
|_progress, type_ann, indent_level| map(
|
||||
optional(and!(
|
||||
backtrackable(spaces_then_comment_or_newline_help()),
|
||||
body_at_indent_help(indent_level)
|
||||
)),
|
||||
move |opt_body| (type_ann.clone(), opt_body)
|
||||
)
|
||||
),
|
||||
debug!(and!(
|
||||
// Optionally parse additional defs.
|
||||
zero_or_more!(backtrackable(allocated(space0_before_e(
|
||||
loc!(specialize_ref(EExpr::Syntax, def(original_indent))),
|
||||
original_indent,
|
||||
EExpr::Space,
|
||||
EExpr::IndentStart,
|
||||
)))),
|
||||
// Parse the final expression that will be returned.
|
||||
// It should be indented the same amount as the original.
|
||||
space0_before_e(
|
||||
specialize_ref(
|
||||
EExpr::Syntax,
|
||||
loc!(|arena, state: State<'a>| parse_expr(original_indent, arena, state))
|
||||
),
|
||||
original_indent,
|
||||
EExpr::Space,
|
||||
EExpr::IndentEnd,
|
||||
)
|
||||
))
|
||||
)
|
||||
.parse(arena, state)
|
||||
.map(
|
||||
move |(progress, ((loc_first_annotation, opt_body), (mut defs, loc_ret)), state)| {
|
||||
let loc_first_def: Located<Def<'a>> = match opt_body {
|
||||
None => {
|
||||
let region = Region::span_across(
|
||||
&loc_first_pattern.region,
|
||||
&loc_first_annotation.region,
|
||||
);
|
||||
Located {
|
||||
value: annotation_or_alias(
|
||||
arena,
|
||||
&loc_first_pattern.value,
|
||||
loc_first_pattern.region,
|
||||
loc_first_annotation,
|
||||
),
|
||||
region,
|
||||
}
|
||||
}
|
||||
Some((opt_comment, (body_pattern, body_expr))) => {
|
||||
let region =
|
||||
Region::span_across(&loc_first_pattern.region, &body_expr.region);
|
||||
Located {
|
||||
value: Def::AnnotatedBody {
|
||||
ann_pattern: arena.alloc(loc_first_pattern),
|
||||
ann_type: arena.alloc(loc_first_annotation),
|
||||
comment: opt_comment,
|
||||
body_pattern: arena.alloc(body_pattern),
|
||||
body_expr: arena.alloc(body_expr),
|
||||
},
|
||||
region,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// contrary to defs with an expression body, we must ensure the annotation comes just before its
|
||||
// corresponding definition (the one with the body).
|
||||
defs.insert(0, &*arena.alloc(loc_first_def));
|
||||
|
||||
let defs = defs.into_bump_slice();
|
||||
|
||||
(progress, Expr::Defs(defs, arena.alloc(loc_ret)), state)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_def_signature<'a>(
|
||||
min_indent: u16,
|
||||
colon_indent: u16,
|
||||
|
@ -1127,10 +1280,6 @@ fn parse_def_signature<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
// fn to_expr<'a>(arena, state, ((loc_first_annotation, opt_body), (mut defs, loc_ret))-> ParseResult<'a, Expr<'a>, SyntaxError<'a>>{
|
||||
|
||||
// }
|
||||
|
||||
fn loc_function_arg<'a>(min_indent: u16) -> impl Parser<'a, Located<Expr<'a>>, SyntaxError<'a>> {
|
||||
skip_first!(
|
||||
// If this is a reserved keyword ("if", "then", "case, "when"),
|
||||
|
@ -1669,19 +1818,27 @@ fn loc_function_args<'a>(
|
|||
/// 4. The beginning of a type annotation (e.g. `foo :`)
|
||||
/// 5. A reserved keyword (e.g. `if ` or `case `), meaning we should do something else.
|
||||
fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
|
||||
specialize(|e, _, _| SyntaxError::Expr(e), ident_etc_help(min_indent))
|
||||
}
|
||||
|
||||
fn assign_or_destructure_identifier<'a>() -> impl Parser<'a, Ident<'a>, EExpr<'a>> {
|
||||
debug!(specialize(|_, r, c| EExpr::Ident(r, c), ident()))
|
||||
}
|
||||
|
||||
fn ident_etc_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||
then(
|
||||
and!(
|
||||
loc!(ident()),
|
||||
loc!(assign_or_destructure_identifier()),
|
||||
and!(
|
||||
// There may optionally be function args after this ident
|
||||
optional(loc_function_args(min_indent)),
|
||||
optional(loc_function_args_help(min_indent)),
|
||||
// There may also be a '=' or ':' after it.
|
||||
// The : might be because this is a type alias, e.g. (List a : ...`
|
||||
// The = might be because someone is trying to use Elm or Haskell
|
||||
// syntax for defining functions, e.g. `foo a b = ...` - so give a nice error!
|
||||
optional(and!(
|
||||
backtrackable(space0(min_indent)),
|
||||
either!(equals_with_indent(), colon_with_indent())
|
||||
backtrackable(space0_e(min_indent, EExpr::Space, EExpr::IndentEquals)),
|
||||
either!(equals_with_indent_help(), colon_with_indent_help())
|
||||
))
|
||||
)
|
||||
),
|
||||
|
@ -1693,7 +1850,7 @@ fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>>
|
|||
(Some(loc_args), Some((_spaces_before_equals, Either::First(_equals_indent)))) => {
|
||||
// We got args with an '=' after them, e.g. `foo a b = ...` This is a syntax error!
|
||||
let region = Region::across_all(loc_args.iter().map(|v| &v.region));
|
||||
let fail = SyntaxError::ArgumentsBeforeEquals(region);
|
||||
let fail = EExpr::ElmStyleFunction(region, state.line, state.column);
|
||||
Err((MadeProgress, fail, state))
|
||||
}
|
||||
(None, Some((spaces_before_equals, Either::First(equals_indent)))) => {
|
||||
|
@ -1708,8 +1865,11 @@ fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>>
|
|||
let def_start_col = state.indent_col;
|
||||
let loc_pattern = Located { region, value };
|
||||
// TODO use equals_indent below?
|
||||
let (_, spaces_after_equals, state) = space0(min_indent).parse(arena, state)?;
|
||||
let (_, parsed_expr, state) = parse_def_expr(
|
||||
let (_, spaces_after_equals, state) =
|
||||
space0_e(min_indent, EExpr::Space, EExpr::IndentDefBody)
|
||||
.parse(arena, state)?;
|
||||
|
||||
let (_, parsed_expr, state) = parse_def_expr_help(
|
||||
min_indent,
|
||||
def_start_col,
|
||||
equals_indent,
|
||||
|
@ -1745,6 +1905,7 @@ fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>>
|
|||
))
|
||||
}
|
||||
(opt_args, Some((spaces_before_colon, Either::Second(colon_indent)))) => {
|
||||
dbg!("parsed a colon");
|
||||
// We may have gotten args, but we definitely got a ':'
|
||||
// (meaning this is an annotation or alias;
|
||||
// parse_def_signature will translate it into one or the other.)
|
||||
|
@ -1765,13 +1926,10 @@ fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>>
|
|||
region: loc_arg.region,
|
||||
});
|
||||
}
|
||||
Err(malformed) => {
|
||||
Err(_malformed) => {
|
||||
return Err((
|
||||
MadeProgress,
|
||||
SyntaxError::NotYetImplemented(format!(
|
||||
"TODO early return malformed pattern {:?}",
|
||||
malformed
|
||||
)),
|
||||
EExpr::MalformedPattern(state.line, state.column),
|
||||
state,
|
||||
));
|
||||
}
|
||||
|
@ -1799,7 +1957,7 @@ fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>>
|
|||
let region = loc_ident.region;
|
||||
let loc_pattern = Located { region, value };
|
||||
|
||||
parse_def_signature(min_indent, colon_indent, arena, state, loc_pattern)
|
||||
parse_def_signature_help(min_indent, colon_indent, arena, state, loc_pattern)
|
||||
}
|
||||
(None, None) => {
|
||||
// We got nothin'
|
||||
|
@ -1870,7 +2028,7 @@ pub fn equals_with_indent<'a>() -> impl Parser<'a, u16, SyntaxError<'a>> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn colon_with_indent<'a>() -> impl Parser<'a, u16, SyntaxError<'a>> {
|
||||
fn colon_with_indent<'a>() -> impl Parser<'a, u16, SyntaxError<'a>> {
|
||||
move |arena, state: State<'a>| match state.bytes.first() {
|
||||
Some(&byte) if byte == b':' => Ok((
|
||||
MadeProgress,
|
||||
|
@ -1882,6 +2040,22 @@ pub fn colon_with_indent<'a>() -> impl Parser<'a, u16, SyntaxError<'a>> {
|
|||
}
|
||||
}
|
||||
|
||||
fn colon_with_indent_help<'a>() -> impl Parser<'a, u16, EExpr<'a>> {
|
||||
move |_arena, state: State<'a>| {
|
||||
let equals = EExpr::Colon(state.line, state.column);
|
||||
let indent_col = state.indent_col;
|
||||
|
||||
match state.bytes.first() {
|
||||
Some(b':') => match state.advance_without_indenting_e(1, EExpr::Space) {
|
||||
Err(bad) => Err(bad),
|
||||
Ok(good) => Ok((MadeProgress, indent_col, good)),
|
||||
},
|
||||
Some(_) => Err((NoProgress, equals, state)),
|
||||
None => Err((NoProgress, equals, state)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> {
|
||||
match src {
|
||||
Ident::GlobalTag(string) => Expr::GlobalTag(string),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue