mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
add AnnotatedBody in AST enum type
This commit is contained in:
parent
b0c169bc5a
commit
efe3497cc9
3 changed files with 100 additions and 31 deletions
|
@ -277,6 +277,14 @@ pub enum Def<'a> {
|
|||
// No need to track that relationship in any data structure.
|
||||
Body(&'a Loc<Pattern<'a>>, &'a Loc<Expr<'a>>),
|
||||
|
||||
AnnotatedBody {
|
||||
ann_pattern: Loc<Pattern<'a>>,
|
||||
ann_type: Loc<TypeAnnotation<'a>>,
|
||||
comment: Option<&'a str>,
|
||||
body_pattern: Loc<Pattern<'a>>,
|
||||
body_expr: Loc<Expr<'a>>,
|
||||
},
|
||||
|
||||
// Blank Space (e.g. comments, spaces, newlines) before or after a def.
|
||||
// We preserve this for the formatter; canonicalization ignores it.
|
||||
SpaceBefore(&'a Def<'a>, &'a [CommentOrNewline<'a>]),
|
||||
|
@ -668,6 +676,7 @@ impl<'a> Spaceable<'a> for Def<'a> {
|
|||
/// "currently attempting to parse a list." This helps error messages!
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Attempting {
|
||||
LineComment,
|
||||
List,
|
||||
Keyword,
|
||||
StrLiteral,
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::ast::CommentOrNewline::{self, *};
|
||||
use crate::ast::Spaceable;
|
||||
use crate::ast::{Attempting, Spaceable};
|
||||
use crate::parser::{
|
||||
self, and, peek_utf8_char, unexpected, unexpected_eof, FailReason, Parser, State,
|
||||
self, and, ascii_char, ascii_string, optional, parse_utf8, peek_utf8_char, then, unexpected,
|
||||
unexpected_eof, FailReason, Parser, State,
|
||||
};
|
||||
use bumpalo::collections::string::String;
|
||||
use bumpalo::collections::vec::Vec;
|
||||
|
@ -211,6 +212,33 @@ enum LineState {
|
|||
DocComment,
|
||||
}
|
||||
|
||||
pub fn line_comment<'a>() -> impl Parser<'a, &'a str> {
|
||||
then(
|
||||
and!(ascii_char('#'), optional(ascii_string("# "))),
|
||||
|_arena: &'a Bump, state: State<'a>, (_, opt_doc)| {
|
||||
if opt_doc != None {
|
||||
return Err(unexpected(3, state, Attempting::LineComment));
|
||||
}
|
||||
let mut length = 0;
|
||||
|
||||
for &byte in state.bytes.iter() {
|
||||
if byte != b'\n' {
|
||||
length += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let comment = &state.bytes[..length];
|
||||
let state = state.advance_without_indenting(length + 1)?;
|
||||
match parse_utf8(comment) {
|
||||
Ok(comment_str) => Ok((comment_str, state)),
|
||||
Err(reason) => state.fail(reason),
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn spaces<'a>(
|
||||
require_at_least_one: bool,
|
||||
|
|
|
@ -2,7 +2,8 @@ use crate::ast::{
|
|||
AssignedField, Attempting, CommentOrNewline, Def, Expr, Pattern, Spaceable, TypeAnnotation,
|
||||
};
|
||||
use crate::blankspace::{
|
||||
space0, space0_after, space0_around, space0_before, space1, space1_around, space1_before,
|
||||
line_comment, space0, space0_after, space0_around, space0_before, space1, space1_around,
|
||||
space1_before,
|
||||
};
|
||||
use crate::ident::{global_tag_or_ident, ident, lowercase_ident, Ident};
|
||||
use crate::keyword;
|
||||
|
@ -497,35 +498,66 @@ pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> {
|
|||
// Indented more beyond the original indent.
|
||||
let indented_more = min_indent + 1;
|
||||
|
||||
// Constant or annotation
|
||||
map_with_arena!(
|
||||
and!(
|
||||
// A pattern followed by '=' or ':'
|
||||
space0_after(loc_closure_param(min_indent), min_indent),
|
||||
either!(
|
||||
// Constant
|
||||
skip_first!(
|
||||
equals_for_def(),
|
||||
// Spaces after the '=' (at a normal indentation level) and then the expr.
|
||||
// The expr itself must be indented more than the pattern and '='
|
||||
space0_before(
|
||||
loc!(move |arena, state| parse_expr(indented_more, arena, state)),
|
||||
min_indent,
|
||||
)
|
||||
),
|
||||
// Annotation
|
||||
skip_first!(
|
||||
ascii_char(b':'),
|
||||
// Spaces after the ':' (at a normal indentation level) and then the type.
|
||||
// The type itself must be indented more than the pattern and ':'
|
||||
space0_before(type_annotation::located(indented_more), indented_more)
|
||||
)
|
||||
let pattern = space0_after(loc_closure_param(min_indent), min_indent);
|
||||
|
||||
let annotation = and!(
|
||||
pattern,
|
||||
skip_first!(
|
||||
ascii_char(b':'),
|
||||
// Spaces after the ':' (at a normal indentation level) and then the type.
|
||||
// The type itself must be indented more than the pattern and ':'
|
||||
space0_before(type_annotation::located(indented_more), indented_more)
|
||||
)
|
||||
);
|
||||
|
||||
let body = and!(
|
||||
pattern,
|
||||
skip_first!(
|
||||
equals_for_def(),
|
||||
// Spaces after the '=' (at a normal indentation level) and then the expr.
|
||||
// The expr itself must be indented more than the pattern and '='
|
||||
space0_before(
|
||||
loc!(move |arena, state| parse_expr(indented_more, arena, state)),
|
||||
min_indent,
|
||||
)
|
||||
),
|
||||
|arena: &'a Bump, (loc_pattern, expr_or_ann)| match expr_or_ann {
|
||||
Either::First(loc_expr) => Def::Body(arena.alloc(loc_pattern), arena.alloc(loc_expr)),
|
||||
Either::Second(loc_ann) =>
|
||||
annotation_or_alias(arena, &loc_pattern.value, loc_pattern.region, loc_ann),
|
||||
)
|
||||
);
|
||||
|
||||
let comment_or_newline = map!(
|
||||
either!(ascii_char('\n'), line_comment()),
|
||||
|either_comment_or_newline| match either_comment_or_newline {
|
||||
Either::First(_) => None,
|
||||
Either::Second(comment) => Some(comment),
|
||||
}
|
||||
);
|
||||
let spaces_then_comment_or_newline: dyn Parser<'a, Option<&'a str>> =
|
||||
skip_first!(zero_or_more!(ascii_char(' ')), comment_or_newline);
|
||||
let annotated_body = and!(
|
||||
annotation,
|
||||
optional(and!(spaces_then_comment_or_newline, body))
|
||||
);
|
||||
|
||||
map_with_arena!(
|
||||
either!(annotated_body, body),
|
||||
|arena: &'a Bump, ann_body_or_body| match ann_body_or_body {
|
||||
Either::First((body_pattern, body_expr)) =>
|
||||
Def::Body(arena.alloc(body_pattern), arena.alloc(body_expr)),
|
||||
Either::Second(((ann_pattern, ann_type), None)) => annotation_or_alias(
|
||||
arena,
|
||||
&(ann_pattern as Located<Pattern>).value,
|
||||
(ann_pattern as Located<Pattern>).region,
|
||||
ann_type
|
||||
),
|
||||
Either::Second((
|
||||
(ann_pattern, ann_type),
|
||||
Some((opt_comment, (body_pattern, body_expr))),
|
||||
)) => Def::AnnotatedBody {
|
||||
ann_pattern: ann_pattern,
|
||||
ann_type: ann_type,
|
||||
comment: opt_comment,
|
||||
body_pattern: body_pattern,
|
||||
body_expr: body_expr,
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue