dlang-community / Pegged

A Parsing Expression Grammar (PEG) module, using the D programming language.
534 stars 66 forks source link

Fix defaultFormatFailMsg at compile time #301

Closed GallaFrancesco closed 3 years ago

GallaFrancesco commented 3 years ago

Trying to generate a grammar whose PEG syntax is wrong at compile time with pegged v0.4.5 and DMD v2.095.0 or v2.096.1 fails with:

./../pegged/peg.d(284,30): Error: static variable `defaultFormatFailMsg` cannot be read at compile time
../../pegged/peg.d(284,30):        called from here: `this.failMsg(cast(string delegate(Position, string, string, const(ParseTree)))defaultFormatFailMsg, "Sucess")`
../../pegged/peg.d(271,40):        called from here: `this.toStringThisNode(allChildrenSuccessful)`
../../pegged/peg.d(266,60):        called from here: `child.toString(tabs ~ (i < this.children.length - 1LU ? " | " : "   "))`
../../pegged/peg.d(257,12):        13 recursive calls to function `toString`
../../pegged/grammar.d(106,75):        called from here: `defAsParseTree.toString("")`
src/pegged/examples/simple_arithmetic.d(11,14):        called from here: `grammar("\x0aArithmetic:\x0a    Term     < Factor (Add / Sub)*\x0a    Add      <-- \"+\" Factor\x0a    Sub      < \"-\" Factor\x0a    Factor   < Primary (Mul / Div)*\x0a    Mul      < \"*\" Primary\x0a    Div      < \"/\" Primary\x0a    Primary  < Parens / Neg / Number / Variable\x0a    Parens   < :\"(\" Term :\")\"\x0a    Neg      < \"-\" Primary\x0a    Number   < ~([0-9]+)\x0a    Variable <- identifier\x0a
veelo commented 3 years ago

I have trouble understanding this code (like why is this a delegate) and why this change fixes the problem. Good job figuring this out! I'd be interested if you can share more clarity, but I'll merge this anyway because it clearly works better this way. Thanks!

Zardoz89 commented 3 years ago

I have trouble understanding this code (like why is this a delegate) and why this change fixes the problem.

Perhaps, because this :

 string failMsg(string delegate(Position, string, string, const ParseTree) formatFailMsg = defaultFormatFailMsg,
        string successMsg = "Sucess") const @property
{

failMsg expects a delegate to format fail messages.

Why this change fixed? I don't know, but kudos to @GallaFrancesco for finding and fixing it.

GallaFrancesco commented 3 years ago

failMsg expects a delegate because delegates can be passed down as function arguments, see https://tour.dlang.org/tour/en/basics/delegates and https://dlang.org/spec/function.html#closures

I'm no expert, but the reason why using auto does not work at compile time could be that failMsg accepts a delegate which should be initialized at compile time. immutable global declaration with explicit initialization are treated as constants (which allows for CTFE) while auto global declarations are not. See the following example:

veelo commented 3 years ago

That helps. Thanks both of you.