Giter Site home page Giter Site logo

parser's Introduction

parser's People

Contributors

cbenz avatar evancz avatar jinjor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

parser's Issues

int parser with skipper crashes and is weird.

intTuple =
    succeed (,)
        |= int
        |. symbol "/"
        |= int

crashes in weird ways:

> run intTuple "1/1"
crash
> run intTuple "1/12"
crash
> run intTuple "1/123"
crash
> run intTuple "1/1234"
Ok (1,1) -- this succeeds with wrong result
> run intTuple "1/12345"
Ok (1,12) -- it depends on the length of the second int
> run intTuple "12/12345"
Ok (12,1) -- and on the first int
> run intTuple "123/12345"
crash

So it seems to crash if len(secondInt) - len(firstInt) <= 2

Exact error

Error: Ran into a `Debug.crash` in module `Parser`

This was caused by the `case` expression between lines 600 and 612.
One of the branches ended with a crash and the following value got through:

    Err "could not convert string '' to an Int"

The message provided by the code author is:

    The `Parser.int` parser seems to have a bug.
Please report an SSCCE to <https://github.com/elm-tools/parser/issues>.


If I replace int with float, it works as expected.

allow substitution of custom Problems for library-generated Problems based on context

I apologize if this is not really an issue, but I've had no luck figuring out how to do it, or getting ideas on Slack, Reddit, or the Google Group.

If an error condition is detected directly by my code while parsing, then I can use

Parser.fail "my custom error message"

But what if the problem is found not directly in my code, but in elm-tools/parser code that I call? For example,

Parser.list spaces Parser.int

If the current text doesn't look like a list of integers, then Parser.list will generate a Problem, with a readable but robotic error message like BadOneOf ([ExpectingSymbol ",",ExpectingSymbol "]"]). But suppose I want to output a custom error message instead of simply reporting the error message contained in the Problem generated by Parser.list. I can't see how to do this.

It's analogous to (in imperative languages with exceptions) catching an exception thrown by a called function and throwing a new, more informative exception based on the calling context.

The closest workaround I can tell (and a very ugly one) is to put lots of information into the context String:

(Parser.inContext "section_3.2.4.3" <| Parser.list spaces Parser.int)

and then to use a big if or case statement after calling Parser.run to check the context to see what part of the parser caused the problem, substituting the custom error message there:

if context.description == "section_1.1.1.1" then
    ...
else if context.description == "section_1.1.1.2" then
    ...
else if context.description == "section_3.2.4.3" then
    "my custom error message"
else ...

`float` crashes on negative numbers

SSCCE:

Parser.run Parser.float "-1"

Output:

Error: Ran into a `Debug.crash` in module `Parser`

This was caused by the `case` expression between lines 695 and 707.
One of the branches ended with a crash and the following value got through:

    Err "could not convert string '' to a Float"

The message provided by the code author is:

    The `Parser.float` parser seems to have a bug.
Please report an SSCCE to <https://github.com/elm-tools/parser/issues>.

Parser.float on ("e" ++ Int) results in Debug.crash

Minimal example

run float "e1"

Error message

Error: Ran into a Debug.crash in module Parser

This was caused by the case expression between lines 733 and 745.
One of the branches ended with a crash and the following value got through:

Err "could not convert string 'e1' to a Float"

The message provided by the code author is:

The `Parser.float` parser seems to have a bug.

Ellie reproduction

https://ellie-app.com/3LVKfT9BLLSa1/0

TypeError: Cannot read property '_0' of undefined

Hi

While trying out the parser, I ran into the above error with this code. I tried to make it short, it's still kind of lengthy, but this reproduces it, only when Identifier and Option are in the oneOf, and only when there is two levels of lists as with Expression and Term.


import Test exposing (..)
import Expect
import Parser exposing (..)
import Parser.LanguageKit exposing (..)
import Set


all : Test
all =
    describe "Parser Test"
        [ test "Parse identifier should pass" <|
            \() ->
                case run identifier "ABC" of
                    Ok res ->
                        Expect.equal res (Identifier "ABC")

                    Err err ->
                        Expect.fail <| toString err
        ]


type Expression
    = Expression (List Term)


type Term
    = Term (List Factor)


type Factor
    = Identifier String
    | Option Expression


expression : Parser Expression
expression =
    succeed Expression
        |= repeat zeroOrMore term


term : Parser Term
term =
    succeed Term
        |= repeat zeroOrMore factor


factor : Parser Factor
factor =
    oneOf [ identifier, opt ]


opt : Parser Factor
opt =
    succeed Option |. symbol "[" |. spaces |= (lazy (\_ -> expression)) |. spaces |. symbol "]"


identifier : Parser Factor
identifier =
    succeed Identifier |= variable isLetter isCharacter Set.empty


isLetter : Char -> Bool
isLetter c =
    List.member c letters


isDigit : Char -> Bool
isDigit c =
    List.member c digits


isSymbol : Char -> Bool
isSymbol c =
    List.member c symbols


isCharacter : Char -> Bool
isCharacter c =
    isLetter c || isDigit c || isSymbol c || c == '_'


isLetterOrDigitOrUnderscore : Char -> Bool
isLetterOrDigitOrUnderscore c =
    List.member c letters
        || List.member c digits
        || (c == '_')


letters : List Char
letters =
    [ 'A', 'B', 'C' ]


digits : List Char
digits =
    [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ]


symbols : List Char
symbols =
    [ '[', ']', '{', '}', '(', ')', '<', '>', '"', '\'', '=', ',', '.', ',', ';' ]


spaces : Parser ()
spaces =
    ignore zeroOrMore (\c -> c == ' ')
"dependencies": {
        "elm-community/json-extra": "2.0.0 <= v < 3.0.0",
        "elm-lang/html": "2.0.0 <= v < 3.0.0",
        "mgold/elm-random-pcg": "4.0.2 <= v < 5.0.0",
        "elm-lang/core": "5.0.0 <= v < 6.0.0",
        "elm-community/elm-test": "3.0.0 <= v < 4.0.0",
        "rtfeldman/node-test-runner": "3.0.0 <= v < 4.0.0",
        "elm-tools/parser": "2.0.1 <= v < 3.0.0"
    },
    "elm-version": "0.18.0 <= v < 0.19.0"

A regex-based parser

I created a regex-based parser (included below) that I have found to be incredibly useful. It is often significantly shorter/easier to represent some productions in the regex-based parser than using the built-in parsers, and it can also support things that are extremely difficult/complex (perhaps not impossible, but I couldn't work out how to do them).

This is unsurprising, as parsers often use regex as tokenizers, and regex is of course a means of specifying parsers for "regular languages".

Some examples of things that a regex parser primitive would allow:

  • I want to support the JS number syntax. I found it on stackoverflow and fairly trivially translated it for Elm's regex library: "[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?". I think this is possible in the parser, but is awkward (optional is a missing parser that would make this easier). This compares well to the 100ish lines to handle Ints in the current implementation.

  • In general, it is much easier to find a well-known regex for things on StackOverflow, rather than having to (possibly erroneously) handwrite one (with tons of tests!).

  • I want to allow "function names" to be built according to this regex: "[a-zA-Z:!@#%&\\*\\-_\\+\\|/\\?><]+". I think I would struggle to do that in less than 20 lines using existing parsers. A parser that would make this simpler would be "match any char in this string".

  • "\"(?:[^\"\\\\]|\\\\.)*\"" is the elm string version of a regex to match a quoted string, allowing an escaped string inside the string. I couldn't figure out how to do this at all, though I expect it is possible. This regex isn't pretty (mostly due to the need to escape things a lot), but it's a lot prettier than I think this would come out building it the manual way.

  • Regexes can be case-insensitive: "true" (with case-insensitivity) is a useful way of supporting [tT][rR][uU][eE]. A case-insensitive parsing primitive would allow this feature.

  • Regex would also support a range of things that aren't currently supported but are supported by regexes. Examples include a range of repeats (would solve #20), character-set negation ([^abc]), greedyness, lookahead, etc. These aren't all great features necessarily, but they can help in a pinch.

  • Regex also has very mature implementations in browsers, and this would likely avoid the problems in #14, #16 and #12.

Here's my homemade implementation:

token : String -> (String -> a) -> String -> Parser a
token name ctor re =  token_ name ctor ("^" ++ re |> Regex.regex)

tokenCI : String -> (String -> a) -> String -> Parser a
tokenCI name ctor re =  token_ name ctor ("^" ++ re |> Regex.regex |> Regex.caseInsensitive)

token_ : String -> (String -> a) -> Regex.Regex -> Parser a
token_ name ctor re =
  PInternal.Parser <| \({ source, offset, indent, context, row, col } as state) ->
    let substring = String.dropLeft offset source in
    case Regex.find (Regex.AtMost 1) re substring of
      [{match}] -> Good (ctor match) { state | offset = offset + String.length match 
                                                                       , col = col + String.length match}
      [] -> Bad (Parser.Parser.Fail <| "Regex " ++ name ++ " not matched: /" ++ toString re ++ "/") state
      _ -> Debug.crash <| "Should never get more than 1 match for regex: " ++ name

LanguageKit.whitespace throws JS exception when allowTabs=True

Hi, Really nice library, enjoying using it!
I noticed the whitespace function only works with allowTabs = False. When set to True, it looks like there's an infinite recursion somewhere.
See REPL session below based on the example from the documentation comments.
I'm using v2.0.1 of the library with Elm 0.18.

$ elm repl
---- elm-repl 0.18.0 -----------------------------------------------------------
 :help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
--------------------------------------------------------------------------------
> import Parser exposing (..)
> import Parser.LanguageKit exposing (..)
> jsWhitespace = whitespace { allowTabs = True, lineComment = LineComment "//", multiComment = UnnestableComment "/*" "*/" }
Parser <function> : Parser.Parser ()
> run jsWhitespace ""
RangeError: Maximum call stack size exceeded
> noTabsWhitespace = whitespace { allowTabs = False, lineComment = LineComment "//", multiComment = UnnestableComment "/*" "*/" }
Parser <function> : Parser.Parser ()
> run noTabsWhitespace ""
Ok () : Result.Result Parser.Error ()
>

It is very difficult to debug parsers

tl;dr: can't debug parsers well, here's some things I tried.

I have a relatively straightforward parser that is currently about 170 lines, and it isn't working. It is already extremely difficult to figure out why my parser isn't working. A feature around this (or a guide explaining how to do this if you already have known good techniques) would be extremely useful.

Here are some things I've tried:

  • The obvious place I have control over is the functions that are run after successful matches:
myInt = succeed (MyInt >> debug)
  |= ...
  |. ...

This showed me when something matched, which was slightly useful.

  • Next, I added contexts to all my parsers, and put debugging into the Parser itself: annotating every call like (parse state)
printContext : String -> (State -> Step a) -> State -> Step a
printContext msg parse state = 
  let outputStrFn msg con = List.map (\c -> c.description ++ " (" ++ msg ++ "): " ++ (toString c.row) ++ ", " ++ (toString c.col)) con |> String.join "\n"
      outputFn c = let _ = Debug.log (outputStrFn msg c) () in c
      result = parse { state | context = (outputFn state.context)}
  in 
    case result of
      Good _ _ -> let _ = Debug.log ("GOOD (" ++ msg ++ ")") (state.context |> List.head |> Maybe.map .description) in result
      Bad _ _ -> let _ = Debug.log ("BAD (" ++ msg ++ ")") (state.context |> List.head |> Maybe.map .description) in result


{-| Run a parser *and then* run another parser!
-}
andThen : (a -> Parser b) -> Parser a -> Parser b
andThen callback (Parser parseA) =
  Parser <| \state1 ->
    case printContext "andThen2" parseA state1 of       -- <===== HERE
      Bad x state2 ->
        Bad x state2

      Good a state2 ->
        let
          (Parser parseB) =
            callback a
        in
          printContext "andThen2" parseB state2             -- <===== ALSO HERE

This does show me how my parsers behave and give me a rough structure of what's happening. Indeed this shows me that some of my parsers in my oneOf aren't being called, but I'm still not sure what's going on.

I think this tells me that I need to see what's happening in my pipelines too. My best hypothesis right now is that oneOf is broken, but I still don't have enough info to have any conviction in that.

  • Next: annotating skips.

Running float parser on "." results in Debug.crash

---- elm-repl 0.18.0 -----------------------------------------------------------
 :help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
--------------------------------------------------------------------------------
> import Parser
> Parser.run Parser.float "."
Error: Ran into a `Debug.crash` in module `Parser`

This was caused by the `case` expression between lines 733 and 745.
One of the branches ended with a crash and the following value got through:

    Err "could not convert string '.' to a Float"

The message provided by the code author is:

    The `Parser.float` parser seems to have a bug.
Please report an SSCCE to <https://github.com/elm-tools/parser/issues>.
>

I'm using elm-tools/parser 2.0.1. Presumably this is a similar issue to #1?

Stack overflow

I've found a particular combination of parsers that, when combined, overflow the stack.

import Char
import Html exposing (..)
import Parser exposing (..)


main =
  text <| toString <| run root "a/b/c"

root =
  zeroOrMore (element |. optional separator)

element =
  mapWithSource always (ignoreWhile Char.isLower)

optional p =
  oneOf [ p, succeed () ]

separator =
  symbol "/"

I can't seem to get it any smaller, unfortunately. The two important parts: ignoreWhile Char.isLower and optional. If either of those are removed from the execution path (by dropping optional or using ignore 1 Char.isLower), the parser works.

Allow users to create their own parsers

Right now you can compose parsers, but you can't create new ones from scratch. I believe this would require at least Parser.Internal.Parser, Parser.Internal.Good, and Parser.Internal.Bad. Those aren't exposed, and AFAICT I can't access unexposed functions from another module.

Workaround: I vendored the parser so I could access them.

Add Regex-based parsers?

I'm using elm-tools/parser to try to parse large machine-generated files in STEP format. To get good parsing performance I've had to use a bunch of tricks like stripping out whitespace using regular expressions as a preprocessing step so that the 'actual' parsing can disregard whitespace. I've also avoided using any of the Char -> Bool predicate-based parsers since they seem quite slow compared to String-based ones like symbol and ignoreUntil.

It would be useful for performance (and perhaps convenience in some cases) to have Regex-based parsers like

regex : Regex -> Parser String
ignoreUntilRegex : Regex -> Parser ()

For example, right now replicating a hypothetical Parser.regex (Regex.regex "[A-Z_][A-Z_0-9]") is possible using the Parser module but involves a lot of use of character predicates and is quite slow as a result. Would it be possible to implement one or both of the above without sacrificing too much error message quality? (I'm not as concerned about error message quality myself since the text I care about is machine generated, but I agree that's an extremely important goal in general.)

keepOne : (Bool -> Char) -> Parser Char

TL;DR: I need something like keepOne : (Bool -> Char) -> Parser Char.

Context: I'm parsing commonmark markdown. The spec for thematic breaks specifies that while --- and the like are valid thematic breaks, a mix of characters is not. So I need to disallow *-* and other mixes of valid thematic break characters. I do this now by doing something like this:

initial : Parser Char
initial =
  keep (Exactly 1) anyBreakChar
    |> map (String.toList >> List.head >> Maybe.withDefault ' ')

This gives me the behavior I want, but allocates a string, a list, and a maybe (plus maybe some more stuff.) This is not terrible, but it's a big dance and results in unclear code (throwing the ' ' away, for example.)

Uncaught RangeError: Maximum call stack size exceeded when parsing huge file

I don't know the specifics that cause this error, but it consistently happens when I try to parse a large file for my obj file parser.
This could very well be because I wrote my parser somehow wrong.
I managed to reproduce this on runelm, here:
https://runelm.io/c/23z

If you change the url from the 'small file' to the 'big file' it will crash.

My actual code is very similar to the provided snippet.

I'm using chrome on linux .

float parser runs into Debug.crash on empty string

Minimal example

run float ""

exact error message

Error: Ran into a `Debug.crash` in module `Parser`

This was caused by the `case` expression between lines 695 and 707.
One of the branches ended with a crash and the following value got through:

    Err "could not convert string '' to a Float"

The message provided by the code author is:

    The `Parser.float` parser seems to have a bug.

I have to choose between delayedCommit and andThen

commonmark has a bunch of block-level elements. The first one I implemented was thematic breaks (---, ***, but not mixed) I took care of that like this:

thematicBreak : Parser Block
thematicBreak =
    let
        anyBreakChar : Char -> Bool
        anyBreakChar c =
            c == '*' || c == '-' || c == '_'

        initial : Parser String
        initial =
            succeed identity
                |= keep (Exactly 1) anyBreakChar
                |. ignore zeroOrMore whitespace

        subsequent : String -> Parser ()
        subsequent breakChar =
            symbol breakChar |. ignore zeroOrMore whitespace
    in
    inContext "thematic break"
        (succeed ThematicBreak
            |. oneToThreeSpaces
            |. (initial |> andThen (\c -> repeat (AtLeast 2) (subsequent c)))
            |. eol
        )

When I implemented the next block level element, I realized this commits too early. "No problem," I thought, "I'll just use delayedCommit". But if there's a way to get both andThen and delayedCommit working on the same parser, I don't see it! I ended up with this:

thematicBreak : Parser Block
thematicBreak =
    let
        single : Char -> Parser ()
        single breakChar =
            ignore (Exactly 1) ((==) breakChar)
                |. ignore zeroOrMore whitespace

        lineOf : Char -> Parser ()
        lineOf breakChar =
            delayedCommit
                (oneToThreeSpaces |. single breakChar)
                (repeat (AtLeast 2) (single breakChar) |> map (always ()))
    in
    inContext "thematic break" <|
        succeed ThematicBreak
            |. oneOf
                [ lineOf '*'
                , lineOf '-'
                , lineOf '_'
                ]
            |. eol

This works, but it doesn't feel as good to me. I don't like repeating myself!

Edit: this is unclear, and a lot of text. Sorry! Concretely: the part that matters for indicating commitment is up to three spaces and then *, -, or _.

Parser.LanguageKit.list gives stack overflow on very large lists

---- elm-repl 0.18.0 -----------------------------------------------------------
 :help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
--------------------------------------------------------------------------------
> import Parser
> import Parser.LanguageKit
> parser = Parser.LanguageKit.list (Parser.symbol "") Parser.int
Parser <function> : Parser.Parser (List Int)
> Parser.run parser "[1,2,3,4,5]"
Ok [1,2,3,4,5] : Result.Result Parser.Error (List Int)
> longList = "[" ++ (List.range 1 5000 |> List.map toString |> String.join ",") ++ "]"
"[1,2,3,...<elided>...,4998,4999,5000]" : String
> Parser.run parser longList
RangeError: Maximum call stack size exceeded

I'm running Elm 0.18 on Windows 10 64-bit.

EDIT: My workaround for now, for anyone else encountering the same issue, is to use a custom list parsing function like this (although more complex, since this version doesn't support whitespace or empty lists):

list =
    Parser.succeed (\first rest -> first :: rest)
        |. Parser.symbol "["
        |= Parser.int
        |= (Parser.repeat Parser.zeroOrMore
                (Parser.succeed identity
                    |. Parser.symbol ","
                    |= Parser.int
                )
           )
        |. Parser.symbol "]"

I'm guessing this will have lower-quality error messages than Parser.LanguageKit.list, but in my particular case I'm parsing machine-generated text so high-quality error messages are not quite as important.

Support languages with overlapping grammar rules

I have two productions with overlapping rules:

(consider the string 4 + 5, being matched with oneOf [number, binOpExpr] where binOpExpr references number as well.)

I wrote them the naive way, and discovered that one would commit, preventing the other from running because of the oneOf they were in. There was no ordering that would allow them succeed.

I think there is definitely a way of writing a parser in this framework to support the language, so the issue is that I didn't know how to do it. I think it would be useful to have one of these two things:

  • control over when to commit and when not to commit, as well as guidance for how to think about committing. I ended up hacking oneOf, to ignore committed parsers and keep going.

  • a guide to an idiomatic way to write parsers using this framework.

Thanks!

It's awkward to require at most n characters

Most of the block-level constructs in commonmark allow up to three characters of space before the start of the element. For example, ···#·hello is still <h1>hello</h1>. This is specifically 3 because 4 or more is the start of a code element. (····hello == <pre><code>hello</pre></code>)

To parse this, I have the following:

{-| Most of the CommonMark block elements allow one to three spaces before the
beginning of the block. So, helper parser!
-}
oneToThreeSpaces : Parser ()
oneToThreeSpaces =
    oneOf
        [ symbol "   "
        , symbol "  "
        , symbol " "
        , succeed ()
        ]

But it's kind of awkward to write like that. I'd rather write something like this:

{-| Most of the CommonMark block elements allow one to three spaces before the
beginning of the block. So, helper parser!
-}
oneToThreeSpaces : Parser ()
oneToThreeSpaces =
    ignore (AtMost 3) ((==) ' ')

Parser.float parses floats with leading zeros incorrectly

Parser.float accepts floats with leading zeros even if they are not immediately before the dot, but parses the result to zero. E.g.

> Parser.run Parser.float "00.23"
Ok 0 : Result.Result Parser.Error Float
> Parser.run Parser.float "01"
Ok 0 : Result.Result Parser.Error Float

Error when parsing integer prefixed with zero

I was parsing the following string where it contained an integer prefixed with zero and received an unexpected error when using the int parser. I expected the same behaviour as String.toInt to return Ok 0, but instead got and error for BadInt. I suspect that it parses the 0 and then continues to check if it hex, thus expecting a x and fails.

Here an example:

> import Parser exposing (..)
> parser = succeed (,) |= int
Parser <function> : Parser.Parser (a -> ( Int, a ))
> run parser "00"
Err { row = 1, col = 2, source = "00", problem = BadInt, context = [] }
    : Result.Result Parser.Error (a -> ( Int, a ))
> run parser "01"
Err { row = 1, col = 2, source = "01", problem = BadInt, context = [] }
    : Result.Result Parser.Error (a -> ( Int, a ))

Parser.LanguageKit.whitespace with allowTabs=True has infinite recursion

The following is executed in elm-repl v0.18. The first two calls with allowTabs=False terminate as expected (although I'm confused as to why "\t" has a positive match when allowTabs=False), but the next two calls with allowTabs=True cause what is apparently an infinite recursion:

> import Parser exposing (..)
> import Parser.LanguageKit exposing (..)
> run (whitespace { allowTabs=False, lineComment=NoLineComment, multiComment=NoMultiComment } ) " "
Ok () : Result.Result Parser.Error ()
> run (whitespace { allowTabs=False, lineComment=NoLineComment, multiComment=NoMultiComment } ) "\t"
Ok () : Result.Result Parser.Error ()
> run (whitespace { allowTabs=True, lineComment=NoLineComment, multiComment=NoMultiComment } ) " "
RangeError: Maximum call stack size exceeded
> run (whitespace { allowTabs=True, lineComment=NoLineComment, multiComment=NoMultiComment } ) "\t"
RangeError: Maximum call stack size exceeded

TypeError: _user$project$Main$exprType is not a function

I'm sure this is a permutation of some other error. There may be others like it, but this one is mine: https://ellie-app.com/XKBHwsdJyWa1/1

If you inline the function causing the error, i.e. by changing:

compare = exprType [ "=", "!=", "<", ">", "<=", ">=" ]
math = exprType [ "*", "/", "+", "-" ]

to

compare = oneOf (List.map toParser [ "=", "!=", "<", ">", "<=", ">=" ])
math = oneOf (List.map toParser [ "*", "/", "+", "-" ])

...then you get TypeError: f is not a function. Like things I've seen reported other places, the issue seems to be that the function gets invoked before it's defined. Unlike things I've seen reported other places, juggling definition orders in Elm doesn't seem to have an effect.

While writing (well, attempting to write) this parser, I've also busted the call stack without the use of repeat or zeroOrMore, and I spent about a day and a half playing thunk roulette with Cannot read property '_0' of undefined, so if you're looking for runtime errors, let me know. I've got plenty.

Debug.crash in Parser.int in pipeline

example 1

Parser.run (Parser.succeed identity |. Parser.symbol "R" |= Parser.int) "R1"

example 2

Parser.run (Parser.succeed identity |. Parser.ignoreUntilAfter "R" |= Parser.int) "R1"
Error: Ran into a `Debug.crash` in module `Parser`

This was caused by the `case` expression between lines 600 and 612.
One of the branches ended with a crash and the following value got through:

    Err "could not convert string '' to an Int"

The message provided by the code author is:

    The `Parser.int` parser seems to have a bug.
Please report an SSCCE to <https://github.com/elm-tools/parser/issues>.

Maybe I'm not supposed to use Parser.symbol for a letter such as "R"? But I didn't see any warnings about this and the error message give doesn't make it clearer.

run float "00.23" == Ok 0

Issue #33 reported the following behavior:

run float "00.23" == Ok 0
run float "01" == Ok 0

Need to test with newer implementation

Maximum call stack size exceeded using andThen

Minimal example

module Main exposing (..)

import Html exposing (Html, text)
import Parser exposing (andThen, keyword, oneOf, run)


main =
    view (createBigFile 10000)


createBigFile n =
    String.repeat n "1"


crashWithLotsOfText =
    oneOf
        [ keyword "1"
            |> andThen (\_ -> crashWithLotsOfText)
        , Parser.end
        ]


view txt =
    run crashWithLotsOfText txt
        |> Result.mapError (always "")
        |> Result.map (always "")
        |> (toString >> text)

Changing 10000 to 1000 compiles fine.

Error message

Uncaught RangeError: Maximum call stack size exceeded

Ellie reproduction

https://ellie-app.com/42MsxddqX9ya1/0

Parsing two ints fails when separated by an 'x'

My code:

> parser = Parser.succeed (,) |= Parser.int |. Parser.symbol "x" |= Parser.int
> Parser.run parser "1x1"

Expected output:

( 1, 1 ) : ( Int, Int )

Actual ouput:

Err { row = 1, col = 2, source = "1x1", problem = BadInt, context = [] }
    : Result.Result Parser.Error ( Int, Int )

Compilation error when using lazy parsers

I'm getting an error in the compiled code when I use a lazy parser. Here it is as an Ellie: https://ellie-app.com/dtBXJdLSTa1/0

When minimized, my code looks like this:

fnCall : Parser String
fnCall = 
  succeed (always "")
    |= repeat oneOrMore fnArg
    
fnArg : Parser String
fnArg =
  lazy (\_ -> fnCall)

This causes the following error:

elm.js:18405 Uncaught TypeError: Cannot read property '_0' of undefined
    at Function.func (elm.js:18405)
    at A2 (elm.js:92)
    at elm.js:20657
    at elm.js:23710
(anonymous) @ elm.js:18405
A2 @ elm.js:92
(anonymous) @ elm.js:20657
(anonymous) @ elm.js:23710
ui:1108 Elm threw when called with {}
ui:1109 Uncaught ReferenceError: Elm is not defined
    at ui:1109

which corresponds to this (I vendor Parser into my app, but I only change the module names)

var _user$project$Parser_Parser$repeat = F2(
	function (count, _p56) {
		var _p57 = _p56;
		var _p59 = _p57._0; // <------------------------HERE
		var _p58 = count;
		if (_p58.ctor === 'Exactly') {
			return _user$project$Parser_Parser_Internal$Parser(
				function (state) {
					return A4(
						_user$project$Parser_Parser$repeatExactly,
						_p58._0,
						_p59,
						{ctor: '[]'},
						state);
				});
		} else {

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.