kach / nearley

📜🔜🌲 Simple, fast, powerful parser toolkit for JavaScript.
https://nearley.js.org
MIT License
3.57k stars 231 forks source link

Recursive macros does not work #644

Open nalvarezdiaz opened 6 months ago

nalvarezdiaz commented 6 months ago

Hello,

I'm creating a grammar which includes 2 expressions for creating unions and intersections. Initially, I've created a static version of these joins but I'm using the same strategy for multiple "primitives". So, I've checked docs and macros are key to avoid duplicating all that code.

The code below is the reproduction of the issue and not my real use case which is bigger and difficult to follow.

# Macros definitions
Macro[X]     ->  Foo[$X] | Bar[$X]
Foo[X]       ->  "foo" _  Macro[$X]
Bar[X]       ->  "bar" _  Macro[$X]
_            ->  [ \t]:+

# Use of a macro
Main -> Macro[Test] | Macro[Help]
Test  -> "test"
Help  -> "help"

I'll expect from that grammar above be able to write expressions like:

However, it does not compile because it is trying to solve macros recursively. This is the error

RangeError: Maximum call stack size exceeded
    at unique (/nearley/lib/compile.js:299:24)
    at buildMacroCallToken (nearley/lib/compile.js:275:24)
    at buildToken (/nearley/lib/compile.js:149:24)
    at buildRule (/nearley/lib/compile.js:95:29)
    at produceRules (/nearley/lib/compile.js:84:28)
    at buildMacroCallToken (/nearley/lib/compile.js:291:13)
    at buildToken (/nearley/lib/compile.js:149:24)
    at buildRule (/nearley/lib/compile.js:95:29)
    at produceRules (/nearley/lib/compile.js:84:28)
    at buildMacroCallToken (/nearley/lib/compile.js:291:13)

I'm interested in know if it is a not supported featured. In that case, it could be great to support them.

Thanks in advance.

robintown commented 4 months ago

This is not a supported feature according to https://nearley.js.org/docs/grammar#macros

Macros are expanded at compile time and inserted in places they are used. They are not “real” rules. Therefore, macros cannot be recursive (nearleyc will go into an infinite loop trying to expand the macro-loop).