def parsing cleanup

This commit is contained in:
Folkert 2021-03-17 17:36:00 +01:00
parent 38d925fea6
commit ec8dd5c3d3

View file

@ -296,23 +296,6 @@ fn expr_in_parens_then_arguments<'a>(
} }
} }
fn parse_loc_term<'a>(
min_indent: u16,
arena: &'a Bump,
state: State<'a>,
) -> ParseResult<'a, Located<Expr<'a>>, EExpr<'a>> {
one_of!(
loc_expr_in_parens_etc_help(min_indent),
loc!(specialize(EExpr::Str, string_literal_help())),
loc!(specialize(EExpr::Number, number_literal_help())),
loc!(specialize(EExpr::Lambda, closure_help(min_indent))),
loc!(record_literal_help(min_indent)),
loc!(specialize(EExpr::List, list_literal_help(min_indent))),
loc!(ident_etc_help(min_indent))
)
.parse(arena, state)
}
fn parse_loc_term_better<'a>( fn parse_loc_term_better<'a>(
min_indent: u16, min_indent: u16,
arena: &'a Bump, arena: &'a Bump,
@ -341,7 +324,7 @@ fn loc_possibly_negative_or_negated_term<'a>(
loc!(map_with_arena!( loc!(map_with_arena!(
// slight complication; a unary minus must be part of the number literal for overflow // slight complication; a unary minus must be part of the number literal for overflow
// reasons // reasons
and!(loc!(unary_negate()), |a, s| parse_loc_term( and!(loc!(unary_negate()), |a, s| parse_loc_term_better(
min_indent, a, s min_indent, a, s
)), )),
|arena: &'a Bump, (loc_op, loc_expr): (Located<_>, _)| { |arena: &'a Bump, (loc_op, loc_expr): (Located<_>, _)| {
@ -354,9 +337,9 @@ fn loc_possibly_negative_or_negated_term<'a>(
// this will parse negative numbers, which the unary negate thing up top doesn't (for now) // this will parse negative numbers, which the unary negate thing up top doesn't (for now)
loc!(specialize(EExpr::Number, number_literal_help())), loc!(specialize(EExpr::Number, number_literal_help())),
loc!(map_with_arena!( loc!(map_with_arena!(
and!(loc!(word1(b'!', EExpr::Start)), |a, s| parse_loc_term( and!(loc!(word1(b'!', EExpr::Start)), |a, s| {
min_indent, a, s parse_loc_term_better(min_indent, a, s)
)), }),
|arena: &'a Bump, (loc_op, loc_expr): (Located<_>, _)| { |arena: &'a Bump, (loc_op, loc_expr): (Located<_>, _)| {
Expr::UnaryOp( Expr::UnaryOp(
arena.alloc(loc_expr), arena.alloc(loc_expr),
@ -979,7 +962,7 @@ fn parse_expr_operator<'a>(
BinOp::Minus if expr_state.end != op_start && op_end == new_start => { BinOp::Minus if expr_state.end != op_start && op_end == new_start => {
// negative terms // negative terms
let (_, negated_expr, state) = parse_loc_term(min_indent, arena, state)?; let (_, negated_expr, state) = parse_loc_term_better(min_indent, arena, state)?;
let new_end = state.get_position(); let new_end = state.get_position();
let arg = numeric_negate_expression( let arg = numeric_negate_expression(
@ -1574,7 +1557,17 @@ fn parse_defs_help<'a>(
/// * A type annotation /// * A type annotation
/// * A type annotation followed on the next line by a pattern, an `=`, and an expression /// * A type annotation followed on the next line by a pattern, an `=`, and an expression
pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>, SyntaxError<'a>> { pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>, SyntaxError<'a>> {
specialize(|e, _, _| SyntaxError::Expr(e), def_help(min_indent)) move |arena, state: State<'a>| {
// specialize(|e, _, _| SyntaxError::Expr(e), def_help(min_indent))
match def_help_help(min_indent).parse(arena, state) {
Err((progress, fail, state)) => Err((progress, SyntaxError::Expr(fail), state)),
Ok((progress, mut loc_defs, state)) => match loc_defs.pop() {
Some(loc_def) => Ok((progress, loc_def.value, state)),
None => panic!(),
},
}
}
} }
pub fn def_help_help<'a>(min_indent: u16) -> impl Parser<'a, Vec<'a, Located<Def<'a>>>, EExpr<'a>> { pub fn def_help_help<'a>(min_indent: u16) -> impl Parser<'a, Vec<'a, Located<Def<'a>>>, EExpr<'a>> {
@ -1923,78 +1916,6 @@ fn parse_def_expr_help<'a>(
.parse(arena, state) .parse(arena, state)
} }
fn parse_backarrow_help<'a>(
min_indent: u16,
def_start_col: u16,
equals_sign_indent: u16,
arena: &'a Bump,
state: State<'a>,
loc_first_pattern: Located<Pattern<'a>>,
spaces_after_equals: &'a [CommentOrNewline<'a>],
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
let state = check_def_indent(min_indent, def_start_col, equals_sign_indent, state)?;
// Indented more beyond the original indent of the entire def-expr.
let indented_more = def_start_col + 1;
then(
and!(
// Parse the body of the first def. 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.
move |arena, state| parse_expr_help(indented_more, arena, state),
and!(
// Optionally parse additional defs.
parse_defs_help(def_start_col),
// Parse the final expression that will be returned.
// It should be indented the same amount as the original.
space0_before_e(
move |arena, state: State<'a>| { parse_expr_help(def_start_col, arena, state) },
def_start_col,
EExpr::Space,
EExpr::IndentStart,
)
)
),
move |arena, state, progress, (loc_first_body, (defs, loc_ret))| {
let loc_first_body = if spaces_after_equals.is_empty() {
loc_first_body
} else {
Located {
value: Expr::SpaceBefore(
arena.alloc(loc_first_body.value),
spaces_after_equals,
),
region: loc_first_body.region,
}
};
let defs_region = Region::span_across(
&defs.get(0).map(|r| r.region).unwrap_or_else(Region::zero),
&loc_first_body.region,
);
let loc_defs = Located::at(
defs_region,
Expr::Defs(defs.into_bump_slice(), arena.alloc(loc_ret)),
);
Ok((
progress,
Expr::Backpassing(
arena.alloc([loc_first_pattern.clone()]),
arena.alloc(loc_first_body),
arena.alloc(loc_defs),
),
state,
))
},
)
.parse(arena, state)
}
fn parse_def_signature_help<'a>( fn parse_def_signature_help<'a>(
min_indent: u16, min_indent: u16,
colon_indent: u16, colon_indent: u16,
@ -2481,217 +2402,6 @@ fn assign_or_destructure_identifier<'a>() -> impl Parser<'a, Ident<'a>, EExpr<'a
crate::ident::parse_ident_help crate::ident::parse_ident_help
} }
fn ident_etc_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
then(
and!(
loc!(assign_or_destructure_identifier()),
// optional(loc_function_args_help(min_indent))
|_, s| Ok((NoProgress, None, s))
),
move |arena, state, progress, (loc_ident, opt_arguments)| {
debug_assert_eq!(progress, MadeProgress);
// This appears to be a var, keyword, or function application.
match opt_arguments {
Some(arguments) => ident_then_args(min_indent, loc_ident, arguments, arena, state),
None => ident_then_no_args(min_indent, loc_ident, arena, state),
}
},
)
}
fn ident_then_no_args<'a>(
min_indent: u16,
loc_ident: Located<Ident<'a>>,
arena: &'a Bump,
state: State<'a>,
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
#[derive(Debug)]
enum Next {
Equals(u16),
Colon(u16),
Backarrow(u16),
}
let parser = optional(and!(
backtrackable(space0_e(min_indent, EExpr::Space, EExpr::IndentEquals)),
one_of![
map!(equals_with_indent_help(), Next::Equals),
map!(colon_with_indent(), Next::Colon),
map!(backpassing_with_indent(), Next::Backarrow),
]
));
let (_, next, state) = parser.parse(arena, state)?;
match next {
Some((ident_spaces, next)) => {
let pattern: Pattern<'a> = Pattern::from_ident(arena, loc_ident.value);
let value = if ident_spaces.is_empty() {
pattern
} else {
Pattern::SpaceAfter(arena.alloc(pattern), ident_spaces)
};
let region = loc_ident.region;
let loc_pattern = Located { region, value };
match next {
Next::Equals(equals_indent) => {
// We got '=' with no args before it
let def_start_col = state.indent_col;
// TODO use equals_indent below?
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,
arena,
state,
loc_pattern,
spaces_after_equals,
)?;
Ok((MadeProgress, parsed_expr, state))
}
Next::Backarrow(equals_indent) => {
// We got '<-' with no args before it
let def_start_col = state.indent_col;
let (_, spaces_after_equals, state) =
space0_e(min_indent, EExpr::Space, EExpr::IndentDefBody)
.parse(arena, state)?;
let (_, parsed_expr, state) = parse_backarrow_help(
min_indent,
def_start_col,
equals_indent,
arena,
state,
loc_pattern,
spaces_after_equals,
)?;
Ok((MadeProgress, parsed_expr, state))
}
Next::Colon(colon_indent) => {
parse_def_signature_help(min_indent, colon_indent, arena, state, loc_pattern)
}
}
}
None => {
let ident = loc_ident.value.clone();
Ok((MadeProgress, ident_to_expr(arena, ident), state))
}
}
}
fn ident_then_args<'a>(
min_indent: u16,
loc_ident: Located<Ident<'a>>,
arguments: Vec<'a, Located<Expr<'a>>>,
arena: &'a Bump,
state: State<'a>,
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
debug_assert!(!arguments.is_empty());
#[derive(Debug)]
enum Next {
Equals(u16),
Colon(u16),
}
let parser = optional(and!(
backtrackable(space0_e(min_indent, EExpr::Space, EExpr::IndentEquals)),
one_of![
map!(equals_with_indent_help(), Next::Equals),
map!(colon_with_indent(), Next::Colon),
]
));
let (_, next, state) = parser.parse(arena, state)?;
match next {
Some((_ident_spaces, Next::Equals(_equals_indent))) => {
// We got args with an '=' after them, e.g. `foo a b = ...` This is a syntax error!
let region = Region::across_all(arguments.iter().map(|v| &v.region));
let fail = EExpr::ElmStyleFunction(region, state.line, state.column);
Err((MadeProgress, fail, state))
}
Some((ident_spaces, Next::Colon(colon_indent))) => {
let pattern: Pattern<'a> = {
let pattern = Pattern::from_ident(arena, loc_ident.value);
// Translate the loc_args Exprs into a Pattern::Apply
// They are probably type alias variables (e.g. `List a : ...`)
let mut arg_patterns = Vec::with_capacity_in(arguments.len(), arena);
for loc_arg in arguments {
match expr_to_pattern_help(arena, &loc_arg.value) {
Ok(arg_pat) => {
arg_patterns.push(Located {
value: arg_pat,
region: loc_arg.region,
});
}
Err(_malformed) => {
return Err((
MadeProgress,
EExpr::MalformedPattern(state.line, state.column),
state,
));
}
}
}
let loc_pattern = Located {
region: loc_ident.region,
value: pattern,
};
Pattern::Apply(arena.alloc(loc_pattern), arg_patterns.into_bump_slice())
};
let region = loc_ident.region;
let value = if ident_spaces.is_empty() {
pattern
} else {
Pattern::SpaceAfter(arena.alloc(pattern), ident_spaces)
};
let loc_pattern = Located { region, value };
parse_def_signature_help(min_indent, colon_indent, arena, state, loc_pattern)
}
None => {
// We got args and nothing else
let loc_expr = Located {
region: loc_ident.region,
value: ident_to_expr(arena, loc_ident.value),
};
let mut allocated_args = Vec::with_capacity_in(arguments.len(), arena);
for loc_arg in arguments {
allocated_args.push(&*arena.alloc(loc_arg));
}
Ok((
MadeProgress,
Expr::Apply(
arena.alloc(loc_expr),
allocated_args.into_bump_slice(),
CalledVia::Space,
),
state,
))
}
}
}
#[allow(dead_code)] #[allow(dead_code)]
fn with_indent<'a, E, T, P>(parser: P) -> impl Parser<'a, u16, E> fn with_indent<'a, E, T, P>(parser: P) -> impl Parser<'a, u16, E>
where where
@ -2745,22 +2455,6 @@ fn colon_with_indent<'a>() -> impl Parser<'a, u16, EExpr<'a>> {
} }
} }
fn backpassing_with_indent<'a>() -> impl Parser<'a, u16, EExpr<'a>> {
move |_arena, state: State<'a>| {
let indent_col = state.indent_col;
if state.bytes.starts_with(b"<-") {
match state.advance_without_indenting_e(2, EExpr::Space) {
Err(bad) => Err(bad),
Ok(good) => Ok((MadeProgress, indent_col, good)),
}
} else {
let colon = EExpr::BackpassArrow(state.line, state.column);
Err((NoProgress, colon, state))
}
}
}
fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> { fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> {
match src { match src {
Ident::GlobalTag(string) => Expr::GlobalTag(string), Ident::GlobalTag(string) => Expr::GlobalTag(string),