lerzegov/elm-syntax-fork/1.0.0

NOTE: the latest version is 1.1.0

ParserFast

@docs Parser, run

symbol : String -> res -> Parser res

Parse exact text like ( and ,. Make sure the given String isn't empty and does not contain \n or 2-part UTF-16 characters.

run (symbol "[" ()) "[" == Ok ()
run (symbol "[" ()) "4" == Err ... (ExpectingSymbol "[") ...

Note: This is good for stuff like brackets and semicolons, but it might need extra validations for binary operators like - because you can find yourself in weird situations. For example, is 3--4 a typo? Or is it 3 - -4? symbol functionality

symbolWithEndLocation : String -> (Location -> res) -> Parser res

symbolWithEndLocation functionality

symbolWithRange : String -> (Range -> res) -> Parser res

symbolWithRange functionality

symbolFollowedBy : String -> Parser next -> Parser next

Make sure the given String isn't empty and does not contain \n or 2-part UTF-16 characters. symbolFollowedBy functionality

Make sure the given String isn't empty and does not contain \n or 2-part UTF-16 characters. symbolBacktrackableFollowedBy functionality

followedBySymbol : String -> Parser a -> Parser a

followedBySymbol functionality

keyword : String -> res -> Parser res

Parse words without other word characters after like let, case, type or import. Make sure the given String isn't empty and does not contain \n or 2-part UTF-16 characters.

run (keyword "let" ()) "let"     == Ok ()
run (keyword "let" ()) "var"     == Err ... (ExpectingKeyword "let") ...
run (keyword "let" ()) "letters" == Err ... (ExpectingKeyword "let") ...

Note: Notice the third case there! keyword actually looks ahead one character to make sure it is not a letter, digit, or underscore. This will help with the weird cases like case(x, y) being totally fine but casex not being fine. keyword functionality

keywordFollowedBy : String -> Parser next -> Parser next

Make sure the given String isn't empty and does not contain \n or 2-part UTF-16 characters. keywordFollowedBy functionality

anyChar functionality

while : (Char -> Bool) -> Parser String

while functionality

whileWithoutLinebreak : (Char -> Bool) -> Parser String

whileWithoutLinebreak functionality

whileMapWithRange : (Char -> Bool) -> (Range -> String -> res) -> Parser res

whileMapWithRange functionality

ifFollowedByWhileWithoutLinebreak : (Char -> Bool) -> (Char -> Bool) -> Parser String

ifFollowedByWhileWithoutLinebreak functionality

ifFollowedByWhileMapWithoutLinebreak : (String -> res) -> (Char -> Bool) -> (Char -> Bool) -> Parser res

ifFollowedByWhileMapWithoutLinebreak functionality

ifFollowedByWhileMapWithRangeWithoutLinebreak : (Range -> String -> res) -> (Char -> Bool) -> (Char -> Bool) -> Parser res

ifFollowedByWhileMapWithRangeWithoutLinebreak functionality

ifFollowedByWhileValidateWithoutLinebreak : (Char -> Bool) -> (Char -> Bool) -> (String -> Bool) -> Parser String

Create a parser for variables. If we wanted to parse type variables in Elm, we could try something like this:

import Char
import ParserFast exposing (..)
import Set


typeVar : Parser String
typeVar =
    ParserFast.ifFollowedByWhileValidateWithoutLinebreak
        Char.isLower
        (\c -> Char.isAlphaNum c || c == '_')
        (\final -> final == "let" || final == "in" || final == "case" || final == "of")

This is saying it must start with a lower-case character. After that, characters can be letters, digits, or underscores. It is also saying that if you run into any of these reserved names after parsing as much as possible, it is definitely not a variable. ifFollowedByWhileValidateWithoutLinebreak functionality

(Range -> String -> res)
-> (Char -> Bool)
-> (Char -> Bool)
-> (String -> Bool)
-> Parser res

ifFollowedByWhileValidateMapWithRangeWithoutLinebreak functionality

(Char -> Bool)
-> (String -> Result String intermediate)
-> (intermediate -> Parser res)
-> Parser res

whileWithoutLinebreakAnd2PartUtf16ToResultAndThen functionality

(Range -> String -> res)
-> (Char -> Bool)
-> (String -> Bool)
-> String
-> Parser res

whileWithoutLinebreakAnd2PartUtf16ValidateMapWithRangeBacktrackableFollowedBySymbol functionality

integerDecimalMapWithRange : (Range -> Int -> res) -> Parser res

Parse an integer base 10.

run int "1"    == Ok 1
run int "1234" == Ok 1234


run int "-789" == Err ...
run int "0123" == Err ...
run int "1.34" == Err ...
run int "1e31" == Err ...
run int "123a" == Err ...
run int "0x1A" == Err ...






int : Parser Int
int =
    ParserFast.integerDecimalMapWithRange (\_ n -> n)

integerDecimalMapWithRange functionality

integerDecimalOrHexadecimalMapWithRange : (Range -> Int -> res) -> (Range -> Int -> res) -> Parser res

Parse an integer base 10 or base 16.

run int "1"    == Ok 1
run int "1234" == Ok 1234
run int "0x1A" == Ok 26


run int "-789" == Err ...
run int "0123" == Err ...
run int "1.34" == Err ...
run int "1e31" == Err ...
run int "123a" == Err ...






int : Parser Int
int =
    ParserFast.integerDecimalOrHexadecimalMapWithRange (\_ n -> n) (\_ n -> n)

integerDecimalOrHexadecimalMapWithRange functionality

(Range -> Float -> res)
-> (Range -> Int -> res)
-> (Range -> Int -> res)
-> Parser res

Parse an integer base 10 or base 16 or a float.

run number "1"    == Ok 1
run number "1234" == Ok 1234
run number "0x1A" == Ok 26
run number "1.34" == Ok 1.34
run number "2e3"  == Ok 2000


run number "-789" == Err ...
run number "0123" == Err ...
run number "123a" == Err ...






number : Parser Int
number =
    ParserFast.integerDecimalOrHexadecimalMapWithRange (\_ n -> n) (\_ n -> n) (\_ n -> n)

floatOrIntegerDecimalOrHexadecimalMapWithRange functionality

Match zero or more \n, \r and space characters, then proceed with the given parser skipWhileWhitespaceFollowedBy functionality

followedBySkipWhileWhitespace functionality

(Range -> String -> res)
-> ( Char, String )
-> ( Char, String )
-> Parser res

Parse multi-line comments that can itself contain other arbitrary multi-comments inside. nestableMultiCommentMapWithRange functionality

map : (a -> b) -> Parser a -> Parser b

Transform the successful result of a parser.

Maybe you have a value that is an integer or null:

nullOrInt : Parser (Maybe Int)
nullOrInt =
    ParserFast.oneOf2
        (ParserFast.map Just int)
        (ParserFast.keyword "null" Nothing)


-- run nullOrInt "0"    == Ok (Just 0)
-- run nullOrInt "13"   == Ok (Just 13)
-- run nullOrInt "null" == Ok Nothing
-- run nullOrInt "zero" == Err ...

map functionality

validate : (a -> Bool) -> String -> Parser a -> Parser a

validate functionality

lazy : (() -> Parser a) -> Parser a

Helper to delay computation, mostly to refer to a recursive parser.

Say we want a parser for simple boolean expressions:

true


false


true || false


true || (true || false)

Notice that a boolean expression might contain other boolean expressions. That means we will want to define our parser in terms of itself:

type Boolean
    = MyTrue
    | MyFalse
    | MyOr Boolean Boolean


boolean : Parser Boolean
boolean =
    ParserFast.oneOf3
        (ParserFast.keyword "true" MyTrue)
        (ParserFast.keyword "false" MyFalse)
        (ParserFast.symbolFollowedBy "("
            (ParserFast.map2 MyOr
                (ParserFast.skipWhileWhitespaceFollowedBy
                    (ParserFast.lazy (\_ -> boolean))
                    |> ParserFast.followedBySkipWhileWhitespace
                    |> ParserFast.followedBySymbol "||"
                    |> ParserFast.followedBySkipWhileWhitespace
                )
                (ParserFast.lazy (\_ -> boolean)
                    |> ParserFast.followedBySkipWhileWhitespace
                )
            )
            |> ParserFast.followedBySymbol ")"
        )

Notice that boolean uses boolean in its definition! In Elm, you can only define a value in terms of itself it is behind a function call. So lazy helps us define these self-referential parsers.

If the recursion is linear, first consider the loop- helpers to avoid stack overflows

map2 : (a -> b -> value) -> Parser a -> Parser b -> Parser value

Parse 2 parser in sequence and combine their results

map2WithStartLocation : (Location -> a -> b -> value) -> Parser a -> Parser b -> Parser value

map2WithStartLocation functionality

map2WithRange : (Range -> a -> b -> value) -> Parser a -> Parser b -> Parser value

map2WithRange functionality

map3 : (a -> b -> c -> value) -> Parser a -> Parser b -> Parser c -> Parser value

map3 functionality

(Location -> a -> b -> c -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser value

map3WithStartLocation functionality

(Range -> a -> b -> c -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser value

map3WithRange functionality

(a -> b -> c -> d -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> Parser value

map4 functionality

(Range -> a -> b -> c -> d -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> Parser value

map4WithRange functionality

(a -> b -> c -> d -> e -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> Parser e
-> Parser value

map5 functionality

(Location -> a -> b -> c -> d -> e -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> Parser e
-> Parser value

map5WithStartLocation functionality

(Range -> a -> b -> c -> d -> e -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> Parser e
-> Parser value

map5WithRange functionality

(a -> b -> c -> d -> e -> f -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> Parser e
-> Parser f
-> Parser value

map6 functionality

(Location -> a -> b -> c -> d -> e -> f -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> Parser e
-> Parser f
-> Parser value

map6WithStartLocation functionality

(Range -> a -> b -> c -> d -> e -> f -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> Parser e
-> Parser f
-> Parser value

map6WithRange functionality

(Range -> a -> b -> c -> d -> e -> f -> g -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> Parser e
-> Parser f
-> Parser g
-> Parser value

map7WithRange functionality

(Location -> a -> b -> c -> d -> e -> f -> g -> h -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> Parser e
-> Parser f
-> Parser g
-> Parser h
-> Parser value

map8WithStartLocation functionality

(Range -> a -> b -> c -> d -> e -> f -> g -> h -> i -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> Parser e
-> Parser f
-> Parser g
-> Parser h
-> Parser i
-> Parser value

map9WithRange functionality

Parser element
-> folded
-> (element -> folded -> folded)
-> (folded -> res)
-> Parser res

loopWhileSucceeds functionality

Parser element
-> Parser folded
-> (element -> folded -> folded)
-> (folded -> res)
-> Parser res

loopWhileSucceedsOntoResultFromParser functionality

Parser ()
-> Parser element
-> folded
-> (element -> folded -> folded)
-> (folded -> res)
-> Parser res

loopUntil functionality

orSucceed : Parser a -> a -> Parser a

orSucceed functionality

map2OrSucceed : (a -> b -> value) -> Parser a -> Parser b -> value -> Parser value

map2OrSucceed functionality

map2WithRangeOrSucceed : (Range -> a -> b -> value) -> Parser a -> Parser b -> value -> Parser value

map2WithRangeOrSucceed functionality

(a -> b -> c -> value)
-> Parser a
-> Parser b
-> Parser c
-> value
-> Parser value

map3OrSucceed functionality

(a -> b -> c -> d -> value)
-> Parser a
-> Parser b
-> Parser c
-> Parser d
-> value
-> Parser value

map4OrSucceed functionality

oneOf2 : Parser a -> Parser a -> Parser a

oneOf2 functionality

(first -> choice)
-> Parser first
-> (second -> choice)
-> Parser second
-> Parser choice

oneOf2Map functionality

(Int -> Int -> first -> Int -> Int -> choice)
-> Parser first
-> (Int -> Int -> second -> Int -> Int -> choice)
-> Parser second
-> Parser choice

oneOf2MapWithStartRowColumnAndEndRowColumn functionality

oneOf2OrSucceed : Parser a -> Parser a -> a -> Parser a

oneOf2OrSucceed functionality

oneOf3 : Parser a -> Parser a -> Parser a -> Parser a

oneOf3 functionality

oneOf4 : Parser a -> Parser a -> Parser a -> Parser a -> Parser a

oneOf4 functionality

oneOf5 : Parser a -> Parser a -> Parser a -> Parser a -> Parser a -> Parser a

oneOf5 functionality

-> Parser a
-> Parser a
-> Parser a
-> Parser a
-> Parser a
-> Parser a
-> Parser a

oneOf7 functionality

-> Parser a
-> Parser a
-> Parser a
-> Parser a
-> Parser a
-> Parser a
-> Parser a
-> Parser a
-> Parser a

oneOf9 functionality

For a given parser, take the current start column as indentation for the whole block parsed by the given parser withIndentSetToColumn functionality

withIndentSetToColumnMinus functionality

columnIndentAndThen : (Int -> Int -> Parser b) -> Parser b

Can be used to verify the current indentation like this:

checkIndent : Parser ()
checkIndent =
    columnIndentAndThen (\indent column -> column > indent)
        "expecting more spaces"

So the checkIndent parser only succeeds when you are "deeper" than the current indent level. You could use this to parse elm-style let expressions.

validateEndColumnIndentation : (Int -> Int -> Bool) -> String -> Parser a -> Parser a

validateEndColumnIndentation functionality

mapWithRange : (Range -> a -> b) -> Parser a -> Parser b

mapWithRange functionality

columnAndThen : (Int -> Parser a) -> Parser a

columnAndThen functionality

offsetSourceAndThen : (Int -> String -> Parser a) -> Parser a

Editors think of code as a grid, but behind the scenes it is just a flat array of UTF-16 characters. getOffset tells you your index in that flat array. So if you consume "\n\n\n\n" you are on row 5, column 1, and offset 4.

Note: JavaScript uses a somewhat odd version of UTF-16 strings, so a single character may take two slots. So in JavaScript, 'abc'.length === 3 but '🙈🙉🙊'.length === 6. Try it out! And since Elm runs in JavaScript, the offset moves by those rules.

offsetSourceAndThenOrSucceed : (Int -> String -> Maybe (Parser a)) -> a -> Parser a

offsetSourceAndThenOrSucceed functionality

problem : String -> Parser a

Indicate that a parser has reached a dead end. "Everything was going fine until I ran into this problem." Check out the -AndThen helpers for where to use this. problem functionality