peggyjs / peggy

Peggy: Parser generator for JavaScript
https://peggyjs.org/
MIT License
914 stars 65 forks source link

Return an expression or decide how to continue #387

Closed barsdeveloper closed 1 year ago

barsdeveloper commented 1 year ago

Hello, I am rewriting a grammar from Parsimmon to Peggy and I would like to encode some behavior I have in my previous grammar. Is there any way to decide how to continue parsing using the value of some label? In Parsimmon this is the chain function but I was wondering whether this is possible in peggy.

For example let's say I have object with type information (and this is specified somewhere else). In my parsed test I do get a name and then some type following that name.

integer: 123
word: alpha

Now, I know I can create a grammar for a limited amount of those labels but let's say the labels are many (many) and the resulting types are complex and they are specified somewhere else, outside the grammar. How do I generate dynamic grammar from the value I get, decide how to continue parsing? The following is not valid, just a concept

decide = value: word ": " {
    if (value == "integer") {
        return integer // can't return a grammar rule
    } else if (value == "word") {
        return word // can't return a grammar rule
    } else {
        //...
    }
}
integer = [0-9]+
word = [a-z]i+

if decide is integer then it expects to parse integer, if it is word then it expects to parse a word and so on.

Mingun commented 1 year ago

If I correctly understand your needs, you have a two ways to do that:

barsdeveloper commented 1 year ago

Good idea, thanks. Do you know if I can have in the grammar (I am using CLI to generate my parser at compile time throught npm run build command) a mix of static and dynamic rules?

integer = [0-9]+ // static rule
word = [a-z]i+ // static rule
entry = tag `${some generated rule that makes the grammar}` // dynamic rule generated through javascript code

I understand it is a bit fuzzy but I am new to parser generators. Thanks for the help and patience.

Mingun commented 1 year ago

You cannot have ${some generated rule that makes the grammar} in the grammar itself, but you can generate your grammar before running the CLI. You also could write a plugin that will append necessary rules directly to the AST instead of generating grammar text. If you want, you can even write that plugin in that way, that is would read its input from the same grammar file, so technically your grammar will contain both static and dynamic rules:

{{
  // For example, you does not use top-level initializer and
  // you decide to write some code inside it for your plugin
}}
integer = [0-9]+ // static rule
word = [a-z]i+ // static rule

// dynamic rules will be injected to the AST by plugin, 
// plugin take their input from `ast.topLevelInitializer`
hildjj commented 1 year ago

I'm going to close this. Please reopen if there is a concrete feature to request.