diff --git a/examples/parser/Parser/Core.roc b/examples/parser/Parser/Core.roc index a22e89f749..9001a113cb 100644 --- a/examples/parser/Parser/Core.roc +++ b/examples/parser/Parser/Core.roc @@ -88,14 +88,14 @@ parse = \parser, input, isParsingCompleted -> ## in a `oneOf` or `alt` have failed, to provide some more descriptive error message. fail : Str -> Parser * * 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. ## This is useful as basic building block, especially in combination with ## `map` and `keep`. const : a -> Parser * a const = \val -> - buildPrimitiveParser \input -> + @Parser \input -> Ok { val: val, input: input } ## 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. keep : Parser input (a -> b), Parser input a -> Parser input b keep = \funParser, valParser -> - combined = \input -> - { val: funVal, input: rest } <- Result.try (parsePartial funParser input) - parsePartial valParser rest - |> Result.map \{ val: val, input: rest2 } -> - { val: funVal val, input: rest2 } + @Parser \input -> + when parsePartial funParser input is + Ok { val: funVal, input: rest } -> + when parsePartial valParser rest is + 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 ## @@ -157,9 +162,18 @@ keep = \funParser, valParser -> ## skip : Parser input kept, Parser input skipped -> Parser input kept skip = \kept, skipped -> - const (\k -> \_ -> k) - |> keep kept - |> keep skipped + @Parser \input -> + when parsePartial kept input is + 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! # @@ -171,14 +185,15 @@ skip = \kept, skipped -> # than using `const` with `map` and/or `keep`. # Consider using those functions first. andThen : Parser input a, (a -> Parser input b) -> Parser input b -andThen = \firstParser, buildNextParser -> - fun = \input -> - { val: firstVal, input: rest } <- Result.try (parsePartial firstParser input) - nextParser = buildNextParser firstVal +andThen = \@Parser firstParser, buildNextParser -> + @Parser \input -> + when firstParser input is + Ok step -> + (@Parser nextParser) = buildNextParser step.val + nextParser step.input - parsePartial nextParser rest - - buildPrimitiveParser fun + Err e -> + Err e ## Try a list of parsers in turn, until one of them succeeds oneOf : List (Parser input a) -> Parser input a @@ -188,17 +203,31 @@ oneOf = \parsers -> ## Transforms the result of parsing into something else, ## using the given transformation function. map : Parser input a, (a -> b) -> Parser input b -map = \simpleParser, transform -> - const transform - |> keep simpleParser +map = \@Parser simpleParser, transform -> + @Parser \input -> + 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, ## using the given two-parameter transformation function. map2 : Parser input a, Parser input b, (a, b -> c) -> Parser input c -map2 = \parserA, parserB, transform -> - const (\a -> \b -> transform a b) - |> keep parserA - |> keep parserB +map2 = \@Parser parserA, @Parser parserB, transform -> + @Parser \input -> + when parserA input is + 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, ## using the given three-parameter transformation function. @@ -206,11 +235,24 @@ map2 = \parserA, parserB, transform -> ## If you need transformations with more inputs, ## take a look at `keep`. map3 : Parser input a, Parser input b, Parser input c, (a, b, c -> d) -> Parser input d -map3 = \parserA, parserB, parserC, transform -> - const (\a -> \b -> \c -> transform a b c) - |> keep parserA - |> keep parserB - |> keep parserC +map3 = \@Parser parserA, @Parser parserB, @Parser parserC, transform -> + @Parser \input -> + when parserA input is + Ok step1 -> + 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. # Removes a layer of 'result' from running the parser. @@ -249,15 +291,15 @@ maybe = \parser -> alt (parser |> map (\val -> Ok val)) (const (Err Nothing)) manyImpl : Parser input a, List a, input -> ParseResult input (List a) -manyImpl = \parser, vals, input -> - result = parsePartial parser input +manyImpl = \@Parser parser, vals, input -> + result = parser input when result is Err _ -> Ok { val: vals, input: input } 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, ## returning a list containing all the parsed elements. @@ -265,7 +307,7 @@ manyImpl = \parser, vals, input -> ## Also see `oneOrMore`. many : Parser input a -> Parser input (List a) many = \parser -> - buildPrimitiveParser \input -> + @Parser \input -> manyImpl parser [] input ## A parser which runs the element parser *one* or more times on the input, @@ -273,10 +315,14 @@ many = \parser -> ## ## Also see `many`. oneOrMore : Parser input a -> Parser input (List a) -oneOrMore = \parser -> - const (\val -> \vals -> List.prepend vals val) - |> keep parser - |> keep (many parser) +oneOrMore = \@Parser parser -> + @Parser \input -> + when parser input is + 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, ## and only returns the result of your main parser. @@ -286,10 +332,7 @@ oneOrMore = \parser -> ## >>> betweenBraces = \parser -> parser |> between (scalar '[') (scalar ']') between : Parser input a, Parser input open, Parser input close -> Parser input a between = \parser, open, close -> - const (\_ -> \val -> \_ -> val) - |> keep open - |> keep parser - |> keep close + map3 open parser close (\_, val, _ -> val) sepBy1 : Parser input a, Parser input sep -> Parser input (List a) sepBy1 = \parser, separator ->