mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Fix nasty perf bug in parsing types
This commit is contained in:
parent
7cc24cbced
commit
085c5e2fe7
5 changed files with 82 additions and 32 deletions
|
@ -836,7 +836,7 @@ where
|
|||
}
|
||||
|
||||
// This should be enough for anyone. Right? RIGHT?
|
||||
let indent_text = "| ; : ! ".repeat(20);
|
||||
let indent_text = "| ; : ! ".repeat(100);
|
||||
|
||||
let cur_indent = INDENT.with(|i| *i.borrow());
|
||||
|
||||
|
@ -1669,6 +1669,21 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a parser that fails if the next byte is the given byte.
|
||||
pub fn error_on_byte<'a, T, E, F>(byte_to_match: u8, to_error: F) -> impl Parser<'a, T, E>
|
||||
where
|
||||
T: 'a,
|
||||
E: 'a,
|
||||
F: Fn(Position) -> E,
|
||||
{
|
||||
debug_assert_ne!(byte_to_match, b'\n');
|
||||
|
||||
move |_arena: &'a Bump, state: State<'a>, _min_indent: u32| match state.bytes().first() {
|
||||
Some(x) if *x == byte_to_match => Err((MadeProgress, to_error(state.pos()))),
|
||||
_ => Err((NoProgress, to_error(state.pos()))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs two parsers in succession. If both parsers succeed, the output is a tuple of both outputs.
|
||||
/// Both parsers must have the same error type.
|
||||
///
|
||||
|
|
|
@ -10,9 +10,9 @@ use crate::expr::record_field;
|
|||
use crate::ident::{lowercase_ident, lowercase_ident_keyword_e};
|
||||
use crate::keyword;
|
||||
use crate::parser::{
|
||||
absolute_column_min_indent, and, collection_trailing_sep_e, either, increment_min_indent,
|
||||
indented_seq, loc, map, map_with_arena, skip_first, skip_second, succeed, then, zero_or_more,
|
||||
ERecord, ETypeAbilityImpl,
|
||||
absolute_column_min_indent, and, collection_trailing_sep_e, either, error_on_byte,
|
||||
increment_min_indent, indented_seq, loc, map, map_with_arena, skip_first, skip_second, succeed,
|
||||
then, zero_or_more, ERecord, ETypeAbilityImpl,
|
||||
};
|
||||
use crate::parser::{
|
||||
allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes,
|
||||
|
@ -582,37 +582,39 @@ fn expression<'a>(
|
|||
let (p1, first, state) = space0_before_e(term(stop_at_surface_has), EType::TIndentStart)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let result = and(
|
||||
zero_or_more(skip_first(
|
||||
byte(b',', EType::TFunctionArgument),
|
||||
one_of![
|
||||
space0_around_ee(
|
||||
term(stop_at_surface_has),
|
||||
EType::TIndentStart,
|
||||
EType::TIndentEnd
|
||||
let (p2, rest, rest_state) = zero_or_more(skip_first(
|
||||
backtrackable(byte(b',', EType::TFunctionArgument)),
|
||||
one_of![
|
||||
map_with_arena(
|
||||
and(
|
||||
backtrackable(space0_e(EType::TIndentStart)),
|
||||
and(term(stop_at_surface_has), space0_e(EType::TIndentEnd)),
|
||||
),
|
||||
fail(EType::TFunctionArgument)
|
||||
],
|
||||
))
|
||||
.trace("type_annotation:expression:rest_args"),
|
||||
and(
|
||||
space0_e(EType::TIndentStart),
|
||||
one_of![
|
||||
map(two_bytes(b'-', b'>', EType::TStart), |_| {
|
||||
FunctionArrow::Pure
|
||||
}),
|
||||
map(two_bytes(b'=', b'>', EType::TStart), |_| {
|
||||
FunctionArrow::Effectful
|
||||
}),
|
||||
],
|
||||
)
|
||||
.trace("type_annotation:expression:arrow"),
|
||||
comma_args_help,
|
||||
),
|
||||
error_on_byte(b',', EType::TFunctionArgument)
|
||||
],
|
||||
))
|
||||
.trace("type_annotation:expression:rest_args")
|
||||
.parse(arena, state.clone(), min_indent)?;
|
||||
|
||||
let result = and(
|
||||
space0_e(EType::TIndentStart),
|
||||
one_of![
|
||||
map(two_bytes(b'-', b'>', EType::TStart), |_| {
|
||||
FunctionArrow::Pure
|
||||
}),
|
||||
map(two_bytes(b'=', b'>', EType::TStart), |_| {
|
||||
FunctionArrow::Effectful
|
||||
}),
|
||||
],
|
||||
)
|
||||
.parse(arena, state.clone(), min_indent);
|
||||
.trace("type_annotation:expression:arrow")
|
||||
.parse(arena, rest_state, min_indent);
|
||||
|
||||
let (progress, annot, state) = match result {
|
||||
Ok((p2, (rest, (space_before_arrow, arrow)), state)) => {
|
||||
let (p3, return_type, state) =
|
||||
Ok((p3, (space_before_arrow, arrow), state)) => {
|
||||
let (p4, return_type, state) =
|
||||
space0_before_e(term(stop_at_surface_has), EType::TIndentStart)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
|
@ -636,7 +638,7 @@ fn expression<'a>(
|
|||
region,
|
||||
value: TypeAnnotation::Function(output, arrow, arena.alloc(return_type)),
|
||||
};
|
||||
let progress = p1.or(p2).or(p3);
|
||||
let progress = p1.or(p2).or(p3).or(p4);
|
||||
(progress, result, state)
|
||||
}
|
||||
Err(err) => {
|
||||
|
@ -694,6 +696,36 @@ fn expression<'a>(
|
|||
.trace("type_annotation:expression")
|
||||
}
|
||||
|
||||
fn comma_args_help<'a>(
|
||||
arena: &'a Bump,
|
||||
(spaces_before, (loc_val, spaces_after)): (
|
||||
&'a [CommentOrNewline<'a>],
|
||||
(Loc<TypeAnnotation<'a>>, &'a [CommentOrNewline<'a>]),
|
||||
),
|
||||
) -> Loc<TypeAnnotation<'a>> {
|
||||
if spaces_before.is_empty() {
|
||||
if spaces_after.is_empty() {
|
||||
loc_val
|
||||
} else {
|
||||
arena
|
||||
.alloc(loc_val.value)
|
||||
.with_spaces_after(spaces_after, loc_val.region)
|
||||
}
|
||||
} else if spaces_after.is_empty() {
|
||||
arena
|
||||
.alloc(loc_val.value)
|
||||
.with_spaces_before(spaces_before, loc_val.region)
|
||||
} else {
|
||||
let wrapped_expr = arena
|
||||
.alloc(loc_val.value)
|
||||
.with_spaces_after(spaces_after, loc_val.region);
|
||||
|
||||
arena
|
||||
.alloc(wrapped_expr.value)
|
||||
.with_spaces_before(spaces_before, wrapped_expr.region)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a basic type annotation that's a combination of variables
|
||||
/// (which are lowercase and unqualified, e.g. `a` in `List a`),
|
||||
/// type applications (which are uppercase and optionally qualified, e.g.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue