-
-
Save ravbell/d94b37f1a346a1f73b5a827d9eaf7c92 to your computer and use it in GitHub Desktop.
| use v6; | |
| #use Grammar::Tracer; | |
| grammar invoice { | |
| token ws { \h*}; | |
| token super-word {\S+}; | |
| token super-phrase { <super-word> [\h <super-word>]*} | |
| token line {^^ \h* [ <super-word> \h+]* <super-word>* \n}; | |
| token invoice-prelude-start {^^'Invoice Summary'\n} | |
| token invoice-prelude-end {<line> <?before 'Start Invoice Details'\n>}; | |
| rule invoice-prelude { | |
| <invoice-prelude-start> | |
| <line>*? | |
| <invoice-prelude-end> | |
| <line> | |
| } | |
| } | |
| multi sub MAIN(){ | |
| my $t = q :to/EOQ/; | |
| Invoice Summary | |
| asd fasdf | |
| asdfasdf | |
| asd 123-fasdf $1234.00 | |
| qwe {rq} [we-r_q] we | |
| Start Invoice Details | |
| EOQ | |
| say $t; | |
| say invoice.parse($t,:rule<invoice-prelude>); | |
| } | |
| multi sub MAIN('test'){ | |
| use Test; | |
| ok invoice.parse('Invoice Summary' ~ "\n", rule => <invoice-prelude-start>); | |
| ok invoice.parse('asdfa {sf} asd-[fasdf] #werwerw'~"\n", rule => <line>); | |
| ok invoice.parse('asdfawerwerw'~"\n", rule => <line>); | |
| ok invoice.subparse('fasdff;kjaf asdf asderwret'~"\n"~'Start Invoice Details'~"\n",rule => <invoice-prelude-end>); | |
| ok invoice.parse('fasdff;kjaf asdf asderwret'~"\n"~'Start Invoice Details'~"\n",rule => <invoice-prelude-end>); | |
| done-testing; | |
| } |
TLDR: The issue is that the test input line with Start Invoice Details ends with horizontal whitespace that you aren't dealing with.
Two ways to deal with it (other than changing the input)
# Explicitly: vvv
token invoice-prelude-end { <line> <?before 'Start Invoice Details' \h* \n>}
# Implicitly:
rule invoice-prelude-end { <line><?before 'Start Invoice Details' \n>}
# ^ must be a rule and there must be a space ^
# (uses the fact that you wrote your own <ws> token)Following are some more things that I think would be helpful
I would have used the “separated by” feature % in line and super-phrase
token super-phrase { <super-word>+ % \h } # single % doesn't capture trailing separator
token line {
^^ \h*
<super-word>* %% \h+ # double %% can capture optional trailing separator
\n
}Those are [almost] exactly equivalent to what you wrote.
(What you wrote has to fail to match <super-word> twice in <line>, but this only has to fail once.)
I would have used the surround feature ~ in invoice-prelude
token invoice-prelude {
# zero or more <line>s surrounded by <invoice-prelude-start> and <invoice-prelude-end>
<invoice-prelude-start> ~ <invoice-prelude-end> <line>*?
<line> # I assume this is here for debugging
}Note that it didn't actually gain anything by being a rule because all of the horizontal whitespace is already handled by the rest of the code.
I don't think that the last line of the invoice prelude is special, so remove <line> from invoice-prelude-end.
(<line>*? in invoice-prelude will capture it instead.)
token invoice-prelude-end {<?before 'Start Invoice Details' \h* \n>}The only regexs that could benefit from being a rule is invoice-prelude-start and invoice-prelude-end.
rule invoice-prelude-start {^^ Invoice Summary \n}
# `^^` is needed so the space ^ will match <.ws>
rule invoice-prelude-end {<?before ^^ Start Invoice Details $$>}That would only work if you are fine with it matching something like Invoice Summary .
Note that invoice-prelude-start needs to use \n to capture it, but invoice-prelude-end can use $$ instead because it isn't capturing \n anyway.
If you change super-word to something other than \S+, then you may also want to change ws to something like \h+ | <.wb>. (word boundary)
The parse on line 37 returns Nil. Do not understand why. Any ideas? All the individual tests for the tokens pass when you run the main with 'test' argument. Not sure what am I missing.