I'm trying to use Farkle to parse the input for Advent of Code 2020 Day 7. You can find my current WIP here. I have a few questions about the implementation of my parser that I hope you can help me with.
Firstly, my parser is failing on the input text light red bags contain 1 bright white bag, 2 muted yellow bags. with the following error:
(1, 9) Cannot recognize character 'd'.
The error seems to be indicating that the text fragment 'light red' can't be parsed. However, I have a unit test which tests parsing the bag colour and this is passing. It's not clear to me why the parser I have written can't parse the entire line of text, when the tests I have written for parsing the individual elements of the line all pass.
Secondly, I have written the following parser to parse the word 'bag', which can either be singular or plural:
static let bagWord = regexString "bag(s)?" |> terminal "BagWord" (T(fun _ data -> data.ToString()))
I use it when parsing the name of a bag, e.g. 'light red bags':
static let bagType = "BagType" ||= [ !@ colour .>>. bagWord => (fun c _ -> c) ]
It works, but I'm wondering whether there is a better way of doing this. I'm not really interested in the result of parsing this word. You can see from the above code fragment that I'm discarding the result. However it doesn't look as if I can use literal text here, because the word can either be singular or plural. Do you have any suggestions?
Thirdly, I don't know how to extend the parser so that it can handle the following input when a bag contains no contents:
faded blue bags contain no other bags.
It looks like I need to use some kind of alternation construct here which tries one type of Farkle and then falls back to using another type if the first one fails. I see that there is something called choice
in the library, but this is a low-level construct for Regexes. I think I would need something that can choose between different Farkles, first trying the one which matches against bags with contents, and then trying the one which matches against bags with no contents if the first one fails. What can I do here?
Many thanks
Paul