Trying to build a parser

I’m trying to learn parser library and stuck. It’s not working for single number (for example “3”), but I think it should because of

expression : Parser Expression
expression =
    oneOf
        [ addExpr
        , intExpr
        ]

after addExpr failed it should run intExpr. What do I do wrong? Here is whole code

module TokenParser exposing (..)

import Parser exposing (..)



-- EXPRESSIONS


type AST
    = Statement Expression


type Expression
    = IntValue Int
    | AddExpr Expression Expression


newLines =
    chompWhile (\c -> c == '\n')


addExpr : Parser Expression
addExpr =
    succeed
        AddExpr
        |= intExpr
        |. symbol "+"
        |= intExpr


intExpr =
    succeed IntValue
        |= int


expression : Parser Expression
expression =
    oneOf
        [ addExpr
        , intExpr
        ]


statement : Parser AST
statement =
    map Statement expression


statements : Parser (List AST)
statements =
    loop [] statementsHelp


statementsHelp : List AST -> Parser (Step (List AST) (List AST))
statementsHelp revStmts =
    oneOf
        [ succeed (\stmt -> Loop (stmt :: revStmts))
            |= statement
            |. newLines
        , succeed ()
            |. end
            |> map (\_ -> Done (List.reverse revStmts))
        ]


parse : String -> Result (List DeadEnd) (List AST)
parse string =
    run statements string

1 Like

I’m pretty sure that it’s because oneOf “commits” to the first path that looks like it will succeed (where at least the first character succeeds).

So because addExpr successfully parses the int part (and then later fails), oneOf will not evaluate the rest of the oneOf parsers. This is done for performance reasons so that the parser doesn’t have to backtrack and re-try parsing the same source code again.

The docs for oneOf link to this document that explain how to work around this behavior.

We’ve also talked about this in an Elm Radio episode about elm/parser, which you may find useful.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.