mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 23:31:12 +00:00
Shrink debug build times via BoxedParser
This commit is contained in:
parent
867ade4f46
commit
752f7785b1
4 changed files with 229 additions and 8 deletions
|
@ -1,4 +1,4 @@
|
||||||
#![type_length_limit = "16777216"]
|
#![type_length_limit = "20932125"]
|
||||||
|
|
||||||
pub mod can;
|
pub mod can;
|
||||||
pub mod collections;
|
pub mod collections;
|
||||||
|
|
|
@ -23,6 +23,7 @@ where
|
||||||
S: 'a,
|
S: 'a,
|
||||||
S: Sized,
|
S: Sized,
|
||||||
P: Parser<'a, Located<S>>,
|
P: Parser<'a, Located<S>>,
|
||||||
|
P: 'a,
|
||||||
{
|
{
|
||||||
map_with_arena(
|
map_with_arena(
|
||||||
and(space0(min_indent), and(parser, space0(min_indent))),
|
and(space0(min_indent), and(parser, space0(min_indent))),
|
||||||
|
@ -63,6 +64,7 @@ where
|
||||||
S: Spaceable<'a>,
|
S: Spaceable<'a>,
|
||||||
S: 'a,
|
S: 'a,
|
||||||
P: Parser<'a, Located<S>>,
|
P: Parser<'a, Located<S>>,
|
||||||
|
P: 'a,
|
||||||
{
|
{
|
||||||
map_with_arena(
|
map_with_arena(
|
||||||
and(space1(min_indent), and(parser, space1(min_indent))),
|
and(space1(min_indent), and(parser, space1(min_indent))),
|
||||||
|
@ -102,6 +104,7 @@ where
|
||||||
S: Spaceable<'a>,
|
S: Spaceable<'a>,
|
||||||
S: 'a,
|
S: 'a,
|
||||||
P: Parser<'a, Located<S>>,
|
P: Parser<'a, Located<S>>,
|
||||||
|
P: 'a,
|
||||||
{
|
{
|
||||||
map_with_arena(
|
map_with_arena(
|
||||||
and(space0(min_indent), parser),
|
and(space0(min_indent), parser),
|
||||||
|
@ -125,6 +128,7 @@ where
|
||||||
S: Spaceable<'a>,
|
S: Spaceable<'a>,
|
||||||
S: 'a,
|
S: 'a,
|
||||||
P: Parser<'a, Located<S>>,
|
P: Parser<'a, Located<S>>,
|
||||||
|
P: 'a,
|
||||||
{
|
{
|
||||||
map_with_arena(
|
map_with_arena(
|
||||||
and(space1(min_indent), parser),
|
and(space1(min_indent), parser),
|
||||||
|
@ -148,6 +152,7 @@ where
|
||||||
S: Spaceable<'a>,
|
S: Spaceable<'a>,
|
||||||
S: 'a,
|
S: 'a,
|
||||||
P: Parser<'a, Located<S>>,
|
P: Parser<'a, Located<S>>,
|
||||||
|
P: 'a,
|
||||||
{
|
{
|
||||||
map_with_arena(
|
map_with_arena(
|
||||||
and(space0(min_indent), parser),
|
and(space0(min_indent), parser),
|
||||||
|
@ -171,6 +176,7 @@ where
|
||||||
S: Spaceable<'a>,
|
S: Spaceable<'a>,
|
||||||
S: 'a,
|
S: 'a,
|
||||||
P: Parser<'a, Located<S>>,
|
P: Parser<'a, Located<S>>,
|
||||||
|
P: 'a,
|
||||||
{
|
{
|
||||||
map_with_arena(
|
map_with_arena(
|
||||||
and(space1(min_indent), parser),
|
and(space1(min_indent), parser),
|
||||||
|
|
|
@ -461,6 +461,7 @@ pub fn collection<'a, Elem, OpeningBrace, ClosingBrace, Delimiter, S>(
|
||||||
where
|
where
|
||||||
OpeningBrace: Parser<'a, ()>,
|
OpeningBrace: Parser<'a, ()>,
|
||||||
Elem: Parser<'a, Located<S>>,
|
Elem: Parser<'a, Located<S>>,
|
||||||
|
Elem: 'a,
|
||||||
Delimiter: Parser<'a, ()>,
|
Delimiter: Parser<'a, ()>,
|
||||||
S: Spaceable<'a>,
|
S: Spaceable<'a>,
|
||||||
S: 'a,
|
S: 'a,
|
||||||
|
|
|
@ -170,13 +170,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn val<'a, Val>(value: Val) -> impl Parser<'a, Val>
|
|
||||||
where
|
|
||||||
Val: Clone,
|
|
||||||
{
|
|
||||||
move |_, state| Ok((value.clone(), state))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn and_then<'a, P1, P2, F, Before, After>(parser: P1, transform: F) -> impl Parser<'a, After>
|
pub fn and_then<'a, P1, P2, F, Before, After>(parser: P1, transform: F) -> impl Parser<'a, After>
|
||||||
where
|
where
|
||||||
P1: Parser<'a, Before>,
|
P1: Parser<'a, Before>,
|
||||||
|
@ -190,7 +183,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
pub fn map<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
|
pub fn map<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
|
||||||
|
where
|
||||||
|
P: Parser<'a, Before>,
|
||||||
|
F: Fn(Before) -> After,
|
||||||
|
{
|
||||||
|
map_impl(parser, transform)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn map_impl<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
|
||||||
where
|
where
|
||||||
P: Parser<'a, Before>,
|
P: Parser<'a, Before>,
|
||||||
F: Fn(Before) -> After,
|
F: Fn(Before) -> After,
|
||||||
|
@ -202,7 +205,20 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
pub fn map_with_arena<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
|
pub fn map_with_arena<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
|
||||||
|
where
|
||||||
|
P: Parser<'a, Before>,
|
||||||
|
F: Fn(&'a Bump, Before) -> After,
|
||||||
|
{
|
||||||
|
map_with_arena_impl(parser, transform)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn map_with_arena_impl<'a, P, F, Before, After>(
|
||||||
|
parser: P,
|
||||||
|
transform: F,
|
||||||
|
) -> impl Parser<'a, After>
|
||||||
where
|
where
|
||||||
P: Parser<'a, Before>,
|
P: Parser<'a, Before>,
|
||||||
F: Fn(&'a Bump, Before) -> After,
|
F: Fn(&'a Bump, Before) -> After,
|
||||||
|
@ -214,7 +230,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
pub fn attempt<'a, P, Val>(attempting: Attempting, parser: P) -> impl Parser<'a, Val>
|
pub fn attempt<'a, P, Val>(attempting: Attempting, parser: P) -> impl Parser<'a, Val>
|
||||||
|
where
|
||||||
|
P: Parser<'a, Val>,
|
||||||
|
{
|
||||||
|
attempt_impl(attempting, parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn attempt_impl<'a, P, Val>(attempting: Attempting, parser: P) -> impl Parser<'a, Val>
|
||||||
where
|
where
|
||||||
P: Parser<'a, Val>,
|
P: Parser<'a, Val>,
|
||||||
{
|
{
|
||||||
|
@ -229,7 +254,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
pub fn loc<'a, P, Val>(parser: P) -> impl Parser<'a, Located<Val>>
|
pub fn loc<'a, P, Val>(parser: P) -> impl Parser<'a, Located<Val>>
|
||||||
|
where
|
||||||
|
P: Parser<'a, Val>,
|
||||||
|
{
|
||||||
|
loc_impl(parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn loc_impl<'a, P, Val>(parser: P) -> impl Parser<'a, Located<Val>>
|
||||||
where
|
where
|
||||||
P: Parser<'a, Val>,
|
P: Parser<'a, Val>,
|
||||||
{
|
{
|
||||||
|
@ -255,7 +289,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
pub fn zero_or_more<'a, P, A>(parser: P) -> impl Parser<'a, Vec<'a, A>>
|
pub fn zero_or_more<'a, P, A>(parser: P) -> impl Parser<'a, Vec<'a, A>>
|
||||||
|
where
|
||||||
|
P: Parser<'a, A>,
|
||||||
|
{
|
||||||
|
zero_or_more_impl(parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn zero_or_more_impl<'a, P, A>(parser: P) -> impl Parser<'a, Vec<'a, A>>
|
||||||
where
|
where
|
||||||
P: Parser<'a, A>,
|
P: Parser<'a, A>,
|
||||||
{
|
{
|
||||||
|
@ -280,7 +323,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
pub fn one_or_more<'a, P, A>(parser: P) -> impl Parser<'a, Vec<'a, A>>
|
pub fn one_or_more<'a, P, A>(parser: P) -> impl Parser<'a, Vec<'a, A>>
|
||||||
|
where
|
||||||
|
P: Parser<'a, A>,
|
||||||
|
{
|
||||||
|
one_or_more_impl(parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn one_or_more_impl<'a, P, A>(parser: P) -> impl Parser<'a, Vec<'a, A>>
|
||||||
where
|
where
|
||||||
P: Parser<'a, A>,
|
P: Parser<'a, A>,
|
||||||
{
|
{
|
||||||
|
@ -384,7 +436,13 @@ fn line_too_long<'a>(attempting: Attempting, state: State<'a>) -> (Fail, State<'
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single char.
|
/// A single char.
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
pub fn char<'a>(expected: char) -> impl Parser<'a, ()> {
|
pub fn char<'a>(expected: char) -> impl Parser<'a, ()> {
|
||||||
|
char_impl(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn char_impl<'a>(expected: char) -> impl Parser<'a, ()> {
|
||||||
move |_arena, state: State<'a>| match state.input.chars().next() {
|
move |_arena, state: State<'a>| match state.input.chars().next() {
|
||||||
Some(actual) if expected == actual => Ok(((), state.advance_without_indenting(1)?)),
|
Some(actual) if expected == actual => Ok(((), state.advance_without_indenting(1)?)),
|
||||||
Some(other_ch) => Err(unexpected(other_ch, 0, state, Attempting::Keyword)),
|
Some(other_ch) => Err(unexpected(other_ch, 0, state, Attempting::Keyword)),
|
||||||
|
@ -393,7 +451,13 @@ pub fn char<'a>(expected: char) -> impl Parser<'a, ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A hardcoded keyword string with no newlines in it.
|
/// A hardcoded keyword string with no newlines in it.
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
pub fn string<'a>(keyword: &'static str) -> impl Parser<'a, ()> {
|
pub fn string<'a>(keyword: &'static str) -> impl Parser<'a, ()> {
|
||||||
|
string_impl(keyword)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn string_impl<'a>(keyword: &'static str) -> impl Parser<'a, ()> {
|
||||||
// We can't have newlines because we don't attempt to advance the row
|
// We can't have newlines because we don't attempt to advance the row
|
||||||
// in the state, only the column.
|
// in the state, only the column.
|
||||||
debug_assert!(!keyword.contains("\n"));
|
debug_assert!(!keyword.contains("\n"));
|
||||||
|
@ -497,7 +561,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
pub fn and<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, (A, B)>
|
pub fn and<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, (A, B)>
|
||||||
|
where
|
||||||
|
P1: Parser<'a, A>,
|
||||||
|
P2: Parser<'a, B>,
|
||||||
|
{
|
||||||
|
and_impl(p1, p2)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn and_impl<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, (A, B)>
|
||||||
where
|
where
|
||||||
P1: Parser<'a, A>,
|
P1: Parser<'a, A>,
|
||||||
P2: Parser<'a, B>,
|
P2: Parser<'a, B>,
|
||||||
|
@ -529,7 +603,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
pub fn either<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, Either<A, B>>
|
pub fn either<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, Either<A, B>>
|
||||||
|
where
|
||||||
|
P1: Parser<'a, A>,
|
||||||
|
P2: Parser<'a, B>,
|
||||||
|
{
|
||||||
|
either_impl(p1, p2)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn either_impl<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, Either<A, B>>
|
||||||
where
|
where
|
||||||
P1: Parser<'a, A>,
|
P1: Parser<'a, A>,
|
||||||
P2: Parser<'a, B>,
|
P2: Parser<'a, B>,
|
||||||
|
@ -969,3 +1053,133 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG COMBINATORS
|
||||||
|
//
|
||||||
|
// These use dyn for runtime dynamic dispatch. It prevents combinatoric
|
||||||
|
// explosions in types (and thus monomorphization, and thus build time),
|
||||||
|
// but has runtime overhead, so we only use these in debug builds.
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub struct BoxedParser<'a, Output> {
|
||||||
|
parser: Box<dyn Parser<'a, Output> + 'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
impl<'a, Output> BoxedParser<'a, Output> {
|
||||||
|
fn new<P>(parser: P) -> Self
|
||||||
|
where
|
||||||
|
P: Parser<'a, Output> + 'a,
|
||||||
|
{
|
||||||
|
BoxedParser {
|
||||||
|
parser: Box::new(parser),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
impl<'a, Output> Parser<'a, Output> for BoxedParser<'a, Output> {
|
||||||
|
fn parse(&self, arena: &'a Bump, state: State<'a>) -> ParseResult<'a, Output> {
|
||||||
|
self.parser.parse(arena, state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn map<'a, P, F, Before, After>(parser: P, transform: F) -> BoxedParser<'a, After>
|
||||||
|
where
|
||||||
|
P: Parser<'a, Before>,
|
||||||
|
F: Fn(Before) -> After,
|
||||||
|
F: 'a,
|
||||||
|
P: 'a,
|
||||||
|
Before: 'a,
|
||||||
|
After: 'a,
|
||||||
|
{
|
||||||
|
BoxedParser::new(map_impl(parser, transform))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn and<'a, P1, P2, A, B>(p1: P1, p2: P2) -> BoxedParser<'a, (A, B)>
|
||||||
|
where
|
||||||
|
P1: Parser<'a, A>,
|
||||||
|
P2: Parser<'a, B>,
|
||||||
|
P1: 'a,
|
||||||
|
P2: 'a,
|
||||||
|
A: 'a,
|
||||||
|
B: 'a,
|
||||||
|
{
|
||||||
|
BoxedParser::new(and_impl(p1, p2))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn map_with_arena<'a, P, F, Before, After>(parser: P, transform: F) -> BoxedParser<'a, After>
|
||||||
|
where
|
||||||
|
P: Parser<'a, Before>,
|
||||||
|
P: 'a,
|
||||||
|
F: Fn(&'a Bump, Before) -> After,
|
||||||
|
F: 'a,
|
||||||
|
Before: 'a,
|
||||||
|
After: 'a,
|
||||||
|
{
|
||||||
|
BoxedParser::new(map_with_arena_impl(parser, transform))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn loc<'a, P, Val>(parser: P) -> BoxedParser<'a, Located<Val>>
|
||||||
|
where
|
||||||
|
P: Parser<'a, Val>,
|
||||||
|
P: 'a,
|
||||||
|
Val: 'a,
|
||||||
|
{
|
||||||
|
BoxedParser::new(loc_impl(parser))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn attempt<'a, P, Val>(attempting: Attempting, parser: P) -> BoxedParser<'a, Val>
|
||||||
|
where
|
||||||
|
P: Parser<'a, Val>,
|
||||||
|
P: 'a,
|
||||||
|
Val: 'a,
|
||||||
|
{
|
||||||
|
BoxedParser::new(attempt_impl(attempting, parser))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn zero_or_more<'a, P, A>(parser: P) -> BoxedParser<'a, Vec<'a, A>>
|
||||||
|
where
|
||||||
|
P: Parser<'a, A>,
|
||||||
|
P: 'a,
|
||||||
|
{
|
||||||
|
BoxedParser::new(zero_or_more_impl(parser))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn char<'a>(expected: char) -> BoxedParser<'a, ()> {
|
||||||
|
BoxedParser::new(char_impl(expected))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn string<'a>(keyword: &'static str) -> BoxedParser<'a, ()> {
|
||||||
|
BoxedParser::new(string_impl(keyword))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn either<'a, P1, P2, A, B>(p1: P1, p2: P2) -> BoxedParser<'a, Either<A, B>>
|
||||||
|
where
|
||||||
|
P1: Parser<'a, A>,
|
||||||
|
P1: 'a,
|
||||||
|
P2: Parser<'a, B>,
|
||||||
|
P2: 'a,
|
||||||
|
A: 'a,
|
||||||
|
B: 'a,
|
||||||
|
{
|
||||||
|
BoxedParser::new(either_impl(p1, p2))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub fn one_or_more<'a, P, A>(parser: P) -> BoxedParser<'a, Vec<'a, A>>
|
||||||
|
where
|
||||||
|
P: Parser<'a, A>,
|
||||||
|
P: 'a,
|
||||||
|
{
|
||||||
|
BoxedParser::new(one_or_more_impl(parser))
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue