mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-20 15:27:45 +03:00
optimize Parser.Core
shaves 1 second off of the HTTP parser tests
This commit is contained in:
parent
545e6bc989
commit
c4e6dcff22
@ -88,14 +88,14 @@ parse = \parser, input, isParsingCompleted ->
|
|||||||
## in a `oneOf` or `alt` have failed, to provide some more descriptive error message.
|
## in a `oneOf` or `alt` have failed, to provide some more descriptive error message.
|
||||||
fail : Str -> Parser * *
|
fail : Str -> Parser * *
|
||||||
fail = \msg ->
|
fail = \msg ->
|
||||||
buildPrimitiveParser \_input -> Err (ParsingFailure msg)
|
@Parser \_input -> Err (ParsingFailure msg)
|
||||||
|
|
||||||
## Parser that will always produce the given `val`, without looking at the actual input.
|
## Parser that will always produce the given `val`, without looking at the actual input.
|
||||||
## This is useful as basic building block, especially in combination with
|
## This is useful as basic building block, especially in combination with
|
||||||
## `map` and `keep`.
|
## `map` and `keep`.
|
||||||
const : a -> Parser * a
|
const : a -> Parser * a
|
||||||
const = \val ->
|
const = \val ->
|
||||||
buildPrimitiveParser \input ->
|
@Parser \input ->
|
||||||
Ok { val: val, input: input }
|
Ok { val: val, input: input }
|
||||||
|
|
||||||
## Try the `first` parser and (only) if it fails, try the `second` parser as fallback.
|
## Try the `first` parser and (only) if it fails, try the `second` parser as fallback.
|
||||||
@ -135,13 +135,18 @@ alt = \first, second ->
|
|||||||
## This is because the parameters to the function will be applied one-by-one as parsing continues.
|
## This is because the parameters to the function will be applied one-by-one as parsing continues.
|
||||||
keep : Parser input (a -> b), Parser input a -> Parser input b
|
keep : Parser input (a -> b), Parser input a -> Parser input b
|
||||||
keep = \funParser, valParser ->
|
keep = \funParser, valParser ->
|
||||||
combined = \input ->
|
@Parser \input ->
|
||||||
{ val: funVal, input: rest } <- Result.try (parsePartial funParser input)
|
when parsePartial funParser input is
|
||||||
parsePartial valParser rest
|
Ok { val: funVal, input: rest } ->
|
||||||
|> Result.map \{ val: val, input: rest2 } ->
|
when parsePartial valParser rest is
|
||||||
{ val: funVal val, input: rest2 }
|
Ok { val: val, input: rest2 } ->
|
||||||
|
Ok { val: funVal val, input: rest2 }
|
||||||
|
|
||||||
buildPrimitiveParser combined
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
## Skip over a parsed item as part of a pipeline
|
## Skip over a parsed item as part of a pipeline
|
||||||
##
|
##
|
||||||
@ -157,9 +162,18 @@ keep = \funParser, valParser ->
|
|||||||
##
|
##
|
||||||
skip : Parser input kept, Parser input skipped -> Parser input kept
|
skip : Parser input kept, Parser input skipped -> Parser input kept
|
||||||
skip = \kept, skipped ->
|
skip = \kept, skipped ->
|
||||||
const (\k -> \_ -> k)
|
@Parser \input ->
|
||||||
|> keep kept
|
when parsePartial kept input is
|
||||||
|> keep skipped
|
Ok step1 ->
|
||||||
|
when parsePartial skipped step1.input is
|
||||||
|
Ok step2 ->
|
||||||
|
Ok { val: step1.val, input: step2.input }
|
||||||
|
|
||||||
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
# Internal utility function. Not exposed to users, since usage is discouraged!
|
# Internal utility function. Not exposed to users, since usage is discouraged!
|
||||||
#
|
#
|
||||||
@ -171,14 +185,15 @@ skip = \kept, skipped ->
|
|||||||
# than using `const` with `map` and/or `keep`.
|
# than using `const` with `map` and/or `keep`.
|
||||||
# Consider using those functions first.
|
# Consider using those functions first.
|
||||||
andThen : Parser input a, (a -> Parser input b) -> Parser input b
|
andThen : Parser input a, (a -> Parser input b) -> Parser input b
|
||||||
andThen = \firstParser, buildNextParser ->
|
andThen = \@Parser firstParser, buildNextParser ->
|
||||||
fun = \input ->
|
@Parser \input ->
|
||||||
{ val: firstVal, input: rest } <- Result.try (parsePartial firstParser input)
|
when firstParser input is
|
||||||
nextParser = buildNextParser firstVal
|
Ok step ->
|
||||||
|
(@Parser nextParser) = buildNextParser step.val
|
||||||
|
nextParser step.input
|
||||||
|
|
||||||
parsePartial nextParser rest
|
Err e ->
|
||||||
|
Err e
|
||||||
buildPrimitiveParser fun
|
|
||||||
|
|
||||||
## Try a list of parsers in turn, until one of them succeeds
|
## Try a list of parsers in turn, until one of them succeeds
|
||||||
oneOf : List (Parser input a) -> Parser input a
|
oneOf : List (Parser input a) -> Parser input a
|
||||||
@ -188,17 +203,31 @@ oneOf = \parsers ->
|
|||||||
## Transforms the result of parsing into something else,
|
## Transforms the result of parsing into something else,
|
||||||
## using the given transformation function.
|
## using the given transformation function.
|
||||||
map : Parser input a, (a -> b) -> Parser input b
|
map : Parser input a, (a -> b) -> Parser input b
|
||||||
map = \simpleParser, transform ->
|
map = \@Parser simpleParser, transform ->
|
||||||
const transform
|
@Parser \input ->
|
||||||
|> keep simpleParser
|
when simpleParser input is
|
||||||
|
Ok step ->
|
||||||
|
Ok { val: transform step.val, input: step.input }
|
||||||
|
|
||||||
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
## Transforms the result of parsing into something else,
|
## Transforms the result of parsing into something else,
|
||||||
## using the given two-parameter transformation function.
|
## using the given two-parameter transformation function.
|
||||||
map2 : Parser input a, Parser input b, (a, b -> c) -> Parser input c
|
map2 : Parser input a, Parser input b, (a, b -> c) -> Parser input c
|
||||||
map2 = \parserA, parserB, transform ->
|
map2 = \@Parser parserA, @Parser parserB, transform ->
|
||||||
const (\a -> \b -> transform a b)
|
@Parser \input ->
|
||||||
|> keep parserA
|
when parserA input is
|
||||||
|> keep parserB
|
Ok step1 ->
|
||||||
|
when parserB step1.input is
|
||||||
|
Ok step2 ->
|
||||||
|
Ok { val: transform step1.val step2.val, input: step2.input }
|
||||||
|
|
||||||
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
## Transforms the result of parsing into something else,
|
## Transforms the result of parsing into something else,
|
||||||
## using the given three-parameter transformation function.
|
## using the given three-parameter transformation function.
|
||||||
@ -206,11 +235,24 @@ map2 = \parserA, parserB, transform ->
|
|||||||
## If you need transformations with more inputs,
|
## If you need transformations with more inputs,
|
||||||
## take a look at `keep`.
|
## take a look at `keep`.
|
||||||
map3 : Parser input a, Parser input b, Parser input c, (a, b, c -> d) -> Parser input d
|
map3 : Parser input a, Parser input b, Parser input c, (a, b, c -> d) -> Parser input d
|
||||||
map3 = \parserA, parserB, parserC, transform ->
|
map3 = \@Parser parserA, @Parser parserB, @Parser parserC, transform ->
|
||||||
const (\a -> \b -> \c -> transform a b c)
|
@Parser \input ->
|
||||||
|> keep parserA
|
when parserA input is
|
||||||
|> keep parserB
|
Ok step1 ->
|
||||||
|> keep parserC
|
when parserB step1.input is
|
||||||
|
Ok step2 ->
|
||||||
|
when parserC step2.input is
|
||||||
|
Ok step3 ->
|
||||||
|
Ok { val: transform step1.val step2.val step3.val, input: step3.input }
|
||||||
|
|
||||||
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
# ^ And this could be repeated for as high as we want, of course.
|
# ^ And this could be repeated for as high as we want, of course.
|
||||||
# Removes a layer of 'result' from running the parser.
|
# Removes a layer of 'result' from running the parser.
|
||||||
@ -249,15 +291,15 @@ maybe = \parser ->
|
|||||||
alt (parser |> map (\val -> Ok val)) (const (Err Nothing))
|
alt (parser |> map (\val -> Ok val)) (const (Err Nothing))
|
||||||
|
|
||||||
manyImpl : Parser input a, List a, input -> ParseResult input (List a)
|
manyImpl : Parser input a, List a, input -> ParseResult input (List a)
|
||||||
manyImpl = \parser, vals, input ->
|
manyImpl = \@Parser parser, vals, input ->
|
||||||
result = parsePartial parser input
|
result = parser input
|
||||||
|
|
||||||
when result is
|
when result is
|
||||||
Err _ ->
|
Err _ ->
|
||||||
Ok { val: vals, input: input }
|
Ok { val: vals, input: input }
|
||||||
|
|
||||||
Ok { val: val, input: inputRest } ->
|
Ok { val: val, input: inputRest } ->
|
||||||
manyImpl parser (List.append vals val) inputRest
|
manyImpl (@Parser parser) (List.append vals val) inputRest
|
||||||
|
|
||||||
## A parser which runs the element parser *zero* or more times on the input,
|
## A parser which runs the element parser *zero* or more times on the input,
|
||||||
## returning a list containing all the parsed elements.
|
## returning a list containing all the parsed elements.
|
||||||
@ -265,7 +307,7 @@ manyImpl = \parser, vals, input ->
|
|||||||
## Also see `oneOrMore`.
|
## Also see `oneOrMore`.
|
||||||
many : Parser input a -> Parser input (List a)
|
many : Parser input a -> Parser input (List a)
|
||||||
many = \parser ->
|
many = \parser ->
|
||||||
buildPrimitiveParser \input ->
|
@Parser \input ->
|
||||||
manyImpl parser [] input
|
manyImpl parser [] input
|
||||||
|
|
||||||
## A parser which runs the element parser *one* or more times on the input,
|
## A parser which runs the element parser *one* or more times on the input,
|
||||||
@ -273,10 +315,14 @@ many = \parser ->
|
|||||||
##
|
##
|
||||||
## Also see `many`.
|
## Also see `many`.
|
||||||
oneOrMore : Parser input a -> Parser input (List a)
|
oneOrMore : Parser input a -> Parser input (List a)
|
||||||
oneOrMore = \parser ->
|
oneOrMore = \@Parser parser ->
|
||||||
const (\val -> \vals -> List.prepend vals val)
|
@Parser \input ->
|
||||||
|> keep parser
|
when parser input is
|
||||||
|> keep (many parser)
|
Ok step ->
|
||||||
|
manyImpl (@Parser parser) [step.val] step.input
|
||||||
|
|
||||||
|
Err e ->
|
||||||
|
Err e
|
||||||
|
|
||||||
## Runs a parser for an 'opening' delimiter, then your main parser, then the 'closing' delimiter,
|
## Runs a parser for an 'opening' delimiter, then your main parser, then the 'closing' delimiter,
|
||||||
## and only returns the result of your main parser.
|
## and only returns the result of your main parser.
|
||||||
@ -286,10 +332,7 @@ oneOrMore = \parser ->
|
|||||||
## >>> betweenBraces = \parser -> parser |> between (scalar '[') (scalar ']')
|
## >>> betweenBraces = \parser -> parser |> between (scalar '[') (scalar ']')
|
||||||
between : Parser input a, Parser input open, Parser input close -> Parser input a
|
between : Parser input a, Parser input open, Parser input close -> Parser input a
|
||||||
between = \parser, open, close ->
|
between = \parser, open, close ->
|
||||||
const (\_ -> \val -> \_ -> val)
|
map3 open parser close (\_, val, _ -> val)
|
||||||
|> keep open
|
|
||||||
|> keep parser
|
|
||||||
|> keep close
|
|
||||||
|
|
||||||
sepBy1 : Parser input a, Parser input sep -> Parser input (List a)
|
sepBy1 : Parser input a, Parser input sep -> Parser input (List a)
|
||||||
sepBy1 = \parser, separator ->
|
sepBy1 = \parser, separator ->
|
||||||
|
Loading…
Reference in New Issue
Block a user