parsingrustgrammarpegpest

Using Pest.rs, how can I avoid 'peek was called on empty stack' if the PUSH is optional?


Pest.rs has the ability to push and peek onto a stack. This is useful when a delimiter is given by the user like custom-quoting found in Perl, and PostgreSQL (double dollar syntax). How can I do this if the item may not be on the stack. For example, the Exim config file states,

It is also possible to use newline and other control characters (those with code values less than 32, plus DEL) as separators in lists. Such separators must be provided literally at the time the list is processed. For options that are string-expanded, you can write the separator using a normal escape sequence. This will be processed by the expander before the string is interpreted as a list. For example, if a newline-separated list of domains is generated by a lookup, you can process it directly by a line such as this:

domains = <\n ${lookup mysql{.....}}

You can see here the token <\n which overrides the default separator of : is optional. You can see here that the syntax is essentially,

list_sep        = ${ "<" ~ (!WHITE_SPACE ~ ANY) }
list            = {
  list_type
  ~ key
  ~ "="
  ~ PUSH(list_sep)?
  ~ !(PEEK ~ ANY)+
  ~ (PEEK ~ !(PEEK ~ ANY))*
}

But when I run that I get,

peek was called on empty stack

Is there anyway to provide for this operation with PEG such that the list is presented to the user as a string, but as an actual list of element tokens?


Solution

  • One method I've started doing is making sure the PUSH always happens. It even seems like an opitional PUSH should be a compiler error,

    Rather than

    ~ PUSH(list_sep)?
    

    Do this,

    ~ PUSH(list_sep?)