I have a simple question for all PEG.js users. Given the following
grammar, what output (final value of "n") would you expect for input
"ac" and why?
{ var n = 0; }
start = (a "b") / (a "c") { return n; }
a = "a" { n++; }
I am especially interested to hear answers from people who are not
that familiar with PEG.js. Answering this question will help me
resolve issue #77 (https://github.com/dmajda/pegjs/issues/77) the
right way.
I'd say the most "correct" answer would be 1, because even though the "a"
is matched twice, we're only interested in its computation of the "valid
syntax path for the given input 'ac'". I could understand and (I think)
tolerate, though, that since "a" is in fact matched twice, its action block
would also be executed twice. However I see no reason for doing this (you
could just match it but ignore the action block unless it is part of a
valid syntax parse). Or, ideally, you would leave that option to the
grammar writers somehow, on a per-rule basis.
Just my two cents.
Excellent work, as usual, with PEG.js. Please keep it up; this project is
extremely useful for a lot of people.
On Sun, Jun 17, 2012 at 9:08 AM, David Majda <da...@majda.cz> wrote:
> Hi,
> I have a simple question for all PEG.js users. Given the following
> grammar, what output (final value of "n") would you expect for input
> "ac" and why?
> { var n = 0; }
> start = (a "b") / (a "c") { return n; }
> a = "a" { n++; }
> I am especially interested to hear answers from people who are not
> that familiar with PEG.js. Answering this question will help me
> resolve issue #77 (https://github.com/dmajda/pegjs/issues/77) the
> right way.
Oh, and I also feel it's a little counterintuitive that an action block
whose return value is essentially discarded has its side-effects sustained,
even though that might be helpful in some cases (hence me saying it could
be a good idea to be able to "flip a switch" to enable this behavior on a
per-rule basis).
> I'd say the most "correct" answer would be 1, because even though the "a"
> is matched twice, we're only interested in its computation of the "valid
> syntax path for the given input 'ac'". I could understand and (I think)
> tolerate, though, that since "a" is in fact matched twice, its action block
> would also be executed twice. However I see no reason for doing this (you
> could just match it but ignore the action block unless it is part of a
> valid syntax parse). Or, ideally, you would leave that option to the
> grammar writers somehow, on a per-rule basis.
> Just my two cents.
> Excellent work, as usual, with PEG.js. Please keep it up; this project is
> extremely useful for a lot of people.
> On Sun, Jun 17, 2012 at 9:08 AM, David Majda <da...@majda.cz> wrote:
>> Hi,
>> I have a simple question for all PEG.js users. Given the following
>> grammar, what output (final value of "n") would you expect for input
>> "ac" and why?
>> { var n = 0; }
>> start = (a "b") / (a "c") { return n; }
>> a = "a" { n++; }
>> I am especially interested to hear answers from people who are not
>> that familiar with PEG.js. Answering this question will help me
>> resolve issue #77 (https://github.com/dmajda/pegjs/issues/77) the
>> right way.
I would expect that the final value of "n" is 2. Here's why -- since
the code block within curly braces constitutes an action and that
action returns a value which determines whether the rule containing
the action is a match or not, the action *must* be executed.
Otherwise, how would you determine if the rule containing the action
is a match? That action of rule a in your example could have contained
code that returns null in some cases, and should therefore be executed
in order to determine whether rule a matches.
So, the way actions and predicates are defined now in PEGjs
(http://pegjs.majda.cz/documentation) - I think that actions should be
executed as the parser reaches them i.e. I don't think it is OK to
delay execution of actions for later. I would suggest that, if such
behavior is needed, that another type of code blocks is defined, let's
call it "delayed action". This "delayed action" would be defined with
a special syntax. Example:
{ var n = 0; }
start = (a "b") / (a "c") { return n; }
a = "a" ${ n++; }
In this case, the action in rule a ( {n++; } ) is defined as a
"delayed action" ($) and is therefore never executed when the parser
arrives upon it. Rather, the parser assumes that the action will
return a non-null value, stores the action and resumes parsing. If an
alternative of a rule is not matched, the actions stored for that
alternative (and all nested rules that were parsed) are discarded and
the other alternative of the rule is used for parsing, and the actions
for that alternative are stored in the same way. However, if the
parser successfully parses the whole input - it goes back and runs the
stored actions in the right sequence.
In the example -- the parser will try to match the first alternative
of rule start ("ab"), it will successfully match rule a and it will
store (not execute) the action in rule a. However, the parser will
discard the stored action once it detects that there is no "b" to
match the alternative. Next, the parser will try to match the second
alternative of rule start ("ac"), the action of rule a will be stored
again, the whole alternative "ac" will successfully match, and
therefore the stored action will be executed and n will be 1.
On Sun, Jun 17, 2012 at 2:08 PM, David Majda <da...@majda.cz> wrote:
> Hi,
> I have a simple question for all PEG.js users. Given the following
> grammar, what output (final value of "n") would you expect for input
> "ac" and why?
> { var n = 0; }
> start = (a "b") / (a "c") { return n; }
> a = "a" { n++; }
> I am especially interested to hear answers from people who are not
> that familiar with PEG.js. Answering this question will help me
> resolve issue #77 (https://github.com/dmajda/pegjs/issues/77) the
> right way.
On Sun, Jun 17, 2012 at 12:19 PM, Ivan Žužak <izu...@gmail.com> wrote:
> Hi,
> I would expect that the final value of "n" is 2. Here's why -- since
> the code block within curly braces constitutes an action and that
> action returns a value which determines whether the rule containing
> the action is a match or not, the action *must* be executed.
> Otherwise, how would you determine if the rule containing the action
> is a match? That action of rule a in your example could have contained
> code that returns null in some cases, and should therefore be executed
> in order to determine whether rule a matches.
> So, the way actions and predicates are defined now in PEGjs
> (http://pegjs.majda.cz/documentation) - I think that actions should be
> executed as the parser reaches them i.e. I don't think it is OK to
> delay execution of actions for later. I would suggest that, if such
> behavior is needed, that another type of code blocks is defined, let's
> call it "delayed action". This "delayed action" would be defined with
> a special syntax. Example:
> { var n = 0; }
> start = (a "b") / (a "c") { return n; }
> a = "a" ${ n++; }
> In this case, the action in rule a ( {n++; } ) is defined as a
> "delayed action" ($) and is therefore never executed when the parser
> arrives upon it. Rather, the parser assumes that the action will
> return a non-null value, stores the action and resumes parsing. If an
> alternative of a rule is not matched, the actions stored for that
> alternative (and all nested rules that were parsed) are discarded and
> the other alternative of the rule is used for parsing, and the actions
> for that alternative are stored in the same way. However, if the
> parser successfully parses the whole input - it goes back and runs the
> stored actions in the right sequence.
> In the example -- the parser will try to match the first alternative
> of rule start ("ab"), it will successfully match rule a and it will
> store (not execute) the action in rule a. However, the parser will
> discard the stored action once it detects that there is no "b" to
> match the alternative. Next, the parser will try to match the second
> alternative of rule start ("ac"), the action of rule a will be stored
> again, the whole alternative "ac" will successfully match, and
> therefore the stored action will be executed and n will be 1.
> Best,
> Ivan
> On Sun, Jun 17, 2012 at 2:08 PM, David Majda <da...@majda.cz> wrote:
> > Hi,
> > I have a simple question for all PEG.js users. Given the following
> > grammar, what output (final value of "n") would you expect for input
> > "ac" and why?
> > { var n = 0; }
> > start = (a "b") / (a "c") { return n; }
> > a = "a" { n++; }
> > I am especially interested to hear answers from people who are not
> > that familiar with PEG.js. Answering this question will help me
> > resolve issue #77 (https://github.com/dmajda/pegjs/issues/77) the
> > right way.
> I have a simple question for all PEG.js users. Given the following
> grammar, what output (final value of "n") would you expect for input
> "ac" and why?
> { var n = 0; }
> start = (a "b") / (a "c") { return n; }
> a = "a" { n++; }
Thanks everyone for their answers. It may not be obvious but you
helped me a lot!