Skip to content
This repository has been archived by the owner on Feb 10, 2021. It is now read-only.

Runtime exception in recursive parsers (elm compiler bug?) #23

Closed
turboMaCk opened this issue Mar 1, 2017 · 5 comments
Closed

Runtime exception in recursive parsers (elm compiler bug?) #23

turboMaCk opened this issue Mar 1, 2017 · 5 comments

Comments

@turboMaCk
Copy link

turboMaCk commented Mar 1, 2017

Hi folks 馃憢!

I think I've found bug but also believe this is cased by elm compiler rather that Combine itself. Anyway I think it's still good to have a record of this.

This is so far the most minimal example I've managed to find:

module Parser exposing (..)

import Combine exposing (..)
import Html exposing (Html)


type Expression
    = Node (List Expression)


node : Parser s Expression
node =
    Node
        <$> brackets (many expression)


expression : Parser s Expression
expression =
    Combine.lazy <| \() -> node


parseExpression : String -> Result String Expression
parseExpression s =
    case Combine.parse expression s of
        Ok ( _, _, expr ) ->
            Ok expr

        Err ( _, _, errs ) ->
            Err <| String.join " or " errs


json : String
json =
    """[]"""

main : Html msg
main =
    Html.text <| toString <| parseExpression json

I've tried to debug deeply but undefined value has been past many times so I didn't manage to identify where it actually happens (yet).

Hope it all make sense.

update: simpler example

@turboMaCk
Copy link
Author

update: I've managed to make example much simpler.

@turboMaCk turboMaCk changed the title Runtime exception (elm compiler bug?) Runtime exception in recursive parsers (elm compiler bug?) Mar 1, 2017
@turboMaCk
Copy link
Author

This is same issue reproduced by reducing official Scheme parser example:

module Scheme exposing (..)

import Combine exposing (..)


type E
    = EList (List E)


list : Parser s E
list =
    EList
        <$> parens (many expr)
        <?> "list"


expr : Parser s E
expr =
    lazy <|
        \() ->
            whitespace *> list <* whitespace


program : Parser s (List E)
program =
    manyTill expr end


parse : String -> Result String (List E)
parse s =
    case Combine.parse program s of
        Ok ( _, _, e ) ->
            Ok e

        Err ( _, _, errs ) ->
            Err <| String.join " or " errs


code =
    """()"""


res =
    parse code

@eeue56
Copy link

eeue56 commented Mar 1, 2017

@turboMaCk it would help a lot if you could also describe the error itself, paste it here.

@turboMaCk
Copy link
Author

@eeue56 I don't get why it disappeared from original post. I've tried to update but it's keep disappearing on save:(

exception is:

Uncaught TypeError: Cannot read property 'ctor' of undefined
    at _elm_community$parser_combinators$Combine$app

compiled code:

var _elm_community$parser_combinators$Combine$app = function (p) {
	var _p0 = p;
	if (_p0.ctor === 'Parser') {
		return _p0._0;
	} else {
		return _elm_lang$lazy$Lazy$force(_p0._0);
	}
};

More on investigation

I was playing with this a bit more and I have failing & fix example.

let me start with broken code (again using simplified Scheme parser)

module Scheme exposing (..)

import Combine exposing (..)


type E
    = EList (List E)
    | EComment String


comment : Parser s E
comment =
    EComment
        <$> regex ";[^\n]+"
        <?> "comment"


list : Parser s E
list =
    EList
        <$> parens (many expr)
        <?> "list"


expr : Parser s E
expr =
    lazy <|
        \() ->
            let
                parsers =
                    [ list
                    , comment
                    ]
            in
                whitespace *> choice parsers <* whitespace


program : Parser s (List E)
program =
    manyTill expr end


parse : String -> Result String (List E)
parse s =
    case Combine.parse program s of
        Ok ( _, _, e ) ->
            Ok e

        Err ( _, _, errs ) ->
            Err <| String.join " or " errs


code =
    """()"""


res =
    parse code

this fails in runtime with same exception.

Now you can fix code just by simply changing order of E constructors:

type E
    = EComment String
    | EList (List E)

works in repl as expected.

> res
Ok ([EList []]) : Result.Result String (List Scheme.E)

@stil4m
Copy link
Contributor

stil4m commented Mar 2, 2017

@turboMaCk I've fixed your issue in an Ellie (https://ellie-app.com/x4K8Ly3g9Na1/2)

You added the lazy to the expr, but it was needed on the list.
If you have a cyclic reference of combinators. For example: list -> expr -> list, it is kind of a best practice to define lazy on each of them.

I believe the issue that causes this problem is Elm Compiler #1527.

@stil4m stil4m closed this as completed Mar 2, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants