I am running into a parser recursion problem I can’t figure out. Any advice on what is causing the issue would be appreciated.
The following code works fine when the function rawData
is defined with a finite number elements (as shown in the commented code immediately below). But does not halt (until the stack overflows) when defined with Parser.loop
as shown in the code. The same loop construct works fine with all the other functions (e.g. files
and directories
)
module Reader exposing (..)
import Parser exposing (..)
type TermCmd
= CD Argument
| LS
type Argument
= Home
| UpOne
| DownOne String
type Content
= Dir String (List Content)
| File Int String String
type alias RawData =
List ( List TermCmd, List Content )
rawData : Parser RawData
rawData =
loop [] <| loopHelper dataChunk -- This never ends...
-- succeed (\a b c d -> [ a, b, c, d ]) -- This works if I only need a known number of chunks
-- |= dataChunk
-- |= dataChunk
-- |= dataChunk
-- |= dataChunk
dataChunk : Parser ( List TermCmd, List Content )
dataChunk =
succeed Tuple.pair
|= commands
|= contents
directory : Parser Content
directory =
succeed Dir
|. symbol "dir"
|. spaces
|= (chompUntilEndOr "\n"
|> getChompedString
)
|= succeed []
|. spaces
file : Parser Content
file =
succeed File
|= int
|. spaces
|= (chompWhile (\c -> c /= '.' && c /= '\n')
|> getChompedString
)
|= (chompUntilEndOr "\n"
|> getChompedString
|> Parser.map (String.dropLeft 1)
)
|. spaces
command : Parser TermCmd
command =
succeed identity
|. symbol "$"
|. spaces
|= oneOf
[ succeed CD
|. symbol "cd"
|. spaces
|= argument
, succeed LS
|. symbol "ls"
]
|. spaces
argument : Parser Argument
argument =
oneOf
[ succeed UpOne |. symbol ".."
, succeed Home |. symbol "/"
, succeed DownOne |= (chompUntilEndOr "\n" |> getChompedString)
, problem "Bad argument"
]
|. spaces
contents : Parser (List Content)
contents =
let
contentHelper revContent =
oneOf
[ succeed (\ctnt -> Loop (ctnt :: revContent))
|= file
, succeed (\ctnt -> Loop (ctnt :: revContent))
|= directory
, succeed ()
|> map (\_ -> Done (List.reverse revContent))
]
in
loop [] contentHelper
commands : Parser (List TermCmd)
commands =
loop [] <| loopHelper command
directories : Parser (List Content)
directories =
loop [] <| loopHelper directory
files : Parser (List Content)
files =
loop [] <| loopHelper file
loopHelper : Parser a -> List a -> Parser (Step (List a) (List a))
loopHelper parser revContent =
oneOf
[ succeed (\ctnt -> Loop (ctnt :: revContent))
|= parser
, succeed ()
|> map (\_ -> Done (List.reverse revContent))
]
sampleInput =
"$ cd /\n$ ls\ndir a\n14848514 b.txt\n8504156 c.dat\ndir d\n$ cd a\n$ ls\ndir e\n29116 f\n2557 g\n62596 h.lst\n$ cd e\n$ ls\n584 i\n$ cd ..\n$ cd ..\n$ cd d\n$ ls\n4060174 j\n8033020 d.log\n5626152 d.ext\n7214296 k"