253 Commits (1c14a2c8f2325e6f7f81e145c83c6af4c4481617)

Author SHA1 Message Date
David Majda ad27a300a8 Fix left recursion detection in sequences
Report left recursion also in cases where the recursive rule invocation
is not a direct element of a sequence, but is wrapped inside an
expression.

Fixes #359.
9 years ago
David Majda 703a352985 Change few testcase descriptions
Reaction to changes in 130cbcfaa3.
9 years ago
David Majda d7d7e87874 Make infinite loop and left recursion detectors work with named rules
Add missing |named| case to the visitor in lib/compiler/asts.js, which
makes the infinite loop and left recursion detectors work correctly with
named rules.

The missing case caused |make parser| to fail with:

  140:34: Infinite loop detected.
  make: *** [parser] Error 1
9 years ago
David Majda 317059760a Fix incorrect pass name in a spec description 9 years ago
David Majda 373f48c10f Fix small error in two testcases
Pointed out by @Mingun:

  6ce97457bf (commitcomment-10548605)
9 years ago
David Majda 6f2c75f7d8 Label specs: Improve structure and descriptions 9 years ago
David Majda 8487c9a0ff Label specs: Add missing test case 9 years ago
David Majda f4385da177 Label specs: Unify formatting with other code 9 years ago
David Majda ddff5feea3 Label specs: Simplify and regularize block-scoped label specs
There is no need to test 3 labels from the outside scope, 1 is enough.
9 years ago
Arlo Breault 12c169e7b5 Convert PEG.js code to strict mode
* Issues #323
10 years ago
Arlo Breault 1a32ae7bd0 Make PEG global explicit in helpers 10 years ago
David Majda eaca5f0acf Add location information to |GrammarError|
This means all errors thrown by |PEG.buildParser| now have associated
location information.
10 years ago
David Majda 89146915ce Add location information to AST nodes
This will allow to add location information to |GrammarError| exceptions
thrown in various passes.
10 years ago
David Majda d1fe86683b Improve location info in tracing events
Replace |line|, |column|, and |offset| properties of tracing events with
the |location| property. It contains an object similar to the one
returned by the |location| function available in action code:

  {
    start: { offset: 23, line: 5, column: 6 },
    end:   { offset: 25, line: 5, column: 8 }
  }

For the |rule.match| event, |start| refers to the position at the
beginning of the matched input and |end| refers to the position after
the end of the matched input.

For |rule.enter| and |rule.fail| events, both |start| and |end| refer to
the current position at the time the rule was entered.
10 years ago
David Majda 065f4e1b75 Improve location info in syntax errors
Replace |line|, |column|, and |offset| properties of |SyntaxError| with
the |location| property. It contains an object similar to the one
returned by the |location| function available in action code:

  {
    start: { offset: 23, line: 5, column: 6 },
    end:   { offset: 25, line: 5, column: 8 }
  }

For syntax errors produced in the middle of the input, |start| refers to
the first unparsed character and |end| refers to the character behind it
(meaning the span is 1 character). This corresponds to the portion of
the input in the |found| property.

For syntax errors produced the end of the input, both |start| and |end|
refer to a character past the end of the input (meaning the span is 0
characters).

For syntax errors produced by calling |expected| or |error| functions in
action code the location info is the same as the |location| function
would return.
10 years ago
David Majda b1ad2a1f61 Rename |reportedPos| to |savedPos|
Preform the following renames:

  * |reportedPos| -> |savedPos| (abstract machine variable)
  * |peg$reportedPos| -> |peg$savedPos| (variable in generated code)
  * |REPORT_SAVED_POS| -> |LOAD_SAVED_POS| (instruction)
  * |REPORT_CURR_POS| -> |UPDATE_SAVED_POS| (instruction)

The idea is that the name |reportedPos| is no longer accurate after the
|location| change (seea the previous commit) because now both
|reportedPos| and |currPos| are reported to user code. Renaming to
|savedPos| resolves this inaccuracy.

There is probably some better name for the concept than quite generic
|savedPos|, but it doesn't come to me.
10 years ago
David Majda 4f7145e360 Improve location info available in action code
Replace |line|, |column|, and |offset| functions with the |location|
function. It returns an object like this:

  {
    start: { offset: 23, line: 5, column: 6 },
    end:   { offset: 25, line: 5, column: 8 }
  }

In actions, |start| refers to the position at the beginning of action's
expression and |end| refers to the position after the end of action's
expression. This allows one to easily add location info e.g. to AST
nodes created in actions.

In predicates, both |start| and |end| refer to the current position.

Fixes #246.
10 years ago
David Majda 889563a0ae Add missing ";" 10 years ago
David Majda 3473c6cb64 Remove extra whitespace 10 years ago
David Majda fb320c4c59 Fix small errors in Jasmine matcher messages 10 years ago
David Majda d7fc0b5c3b Implement infinite loop detection
Fixes #26.
10 years ago
David Majda 6ce97457bf Fix left recursion detection
So far, left recursion detector assumed that left recursion occurs only
when the recursive rule is at the very left-hand side of rule's
expression:

  start = start

This didn't catch cases like this:

  start = "a"? start

In general, if a rule reference can be reached without consuming any
input, it can lead to left recursion. This commit fixes the detector to
consider that.

Fixes #190.
10 years ago
David Majda da57118a43 Implement basic support for tracing
Parsers can now be generated with support for tracing using the --trace
CLI option or a boolean |trace| option to |PEG.buildParser|. This makes
them trace their progress, which can be useful for debugging. Parsers
generated with tracing support are called "tracing parsers".

When a tracing parser executes, by default it traces the rules it enters
and exits by writing messages to the console. For example, a parser
built from this grammar:

  start = a / b
  a = "a"
  b = "b"

will write this to the console when parsing input "b":

  1:1 rule.enter start
  1:1 rule.enter   a
  1:1 rule.fail    a
  1:1 rule.enter   b
  1:2 rule.match   b
  1:2 rule.match start

You can customize tracing by passing a custom *tracer* to parser's
|parse| method using the |tracer| option:

  parser.parse(input, { trace: tracer });

This will replace the built-in default tracer (which writes to the
console) by the tracer you supplied.

The tracer must be an object with a |trace| method. This method is
called each time a tracing event happens. It takes one argument which is
an object describing the tracing event.

Currently, three events are supported:

  * rule.enter -- triggered when a rule is entered
  * rule.match -- triggered when a rule matches successfully
  * rule.fail  -- triggered when a rule fails to match

These events are triggered in nested pairs -- for each rule.enter event
there is a matching rule.match or rule.fail event.

The event object passed as an argument to |trace| contains these
properties:

  * type   -- event type
  * rule   -- name of the rule the event is related to
  * offset -- parse position at the time of the event
  * line   -- line at the time of the event
  * column -- column at the time of the event
  * result -- rule's match result (only for rule.match event)

The whole tracing API is somewhat experimental (which is why it isn't
documented properly yet) and I expect it will evolve over time as
experience is gained.

The default tracer is also somewhat bare-bones. I hope that PEG.js user
community will develop more sophisticated tracers over time and I'll be
able to integrate their best ideas into the default tracer.
10 years ago
David Majda fb5f6c6ee9 Make labels behave like block-scoped variables
Action and predicate code can now see variables defined in expressions
"above" them.

Based on a pull request by Bryon Vandiver (@asterick):

  https://github.com/pegjs/pegjs/pull/180

Fixes #316.
10 years ago
David Majda 73795a65cc Behavior specs cleanup: Add group specs
While groups don't create separate nodes on the AST level, they exist
as concept on the user level, so they should be specified.
10 years ago
David Majda e306b58443 Behavior specs cleanup: Improve error reporting specs 10 years ago
David Majda e9d038547d Behavior specs cleanup: Improve semantic predicate specs
Note that use of |text| inside semantic predicate code is no longer
tested and officially supported.
10 years ago
David Majda 3d9600b81b Behavior specs cleanup: Improve action specs 10 years ago
David Majda b623396cb8 Behavior specs cleanup: Improve initializer specs
Note that use of |text|, |offset|, |line|, and |column| inside
initializer code is no longer tested and officially supported.
10 years ago
David Majda fee58d0806 Behavior specs cleanup: Improve rule specs 10 years ago
David Majda fa70e70ddf Behavior specs cleanup: Improve choice specs 10 years ago
David Majda b3828919e2 Behavior specs cleanup: Improve sequence specs 10 years ago
David Majda 548209b48b Behavior specs cleanup: Improve simple predicate specs 10 years ago
David Majda 52144e48cb Behavior specs cleanup: Improve label specs 10 years ago
David Majda c5c44b9d0c Behavior specs cleanup: Improve text specs 10 years ago
David Majda bb708490a0 Behavior specs cleanup: Improve one or more specs 10 years ago
David Majda b9a3b44cf2 Behavior specs cleanup: Improve zero or more specs 10 years ago
David Majda c377eff876 Behavior specs cleanup: Improve optional specs 10 years ago
David Majda ade2c249f2 Behavior specs cleanup: Improve rule reference specs 10 years ago
David Majda 936d6453a5 Behavior specs cleanup: Improve dot specs 10 years ago
David Majda 74be12c657 Behavior specs cleanup: Improve character class specs 10 years ago
David Majda 54191fbf12 Behavior specs cleanup: Improve literal specs 10 years ago
David Majda 2faff0000e Behavior specs cleanup: Make |toParse| work without expected value
This means we can assert just "this string parses" and ignore the
returned value.
10 years ago
David Majda ce91921a1d Behavior specs cleanup: Don't describe named rules separately
While naming a rule creates a separate node on the AST level, it's not a
new concept on the user level, so its specs should be a part of rule
specs.
10 years ago
David Majda a597e65a66 Behavior specs cleanup: Reorder toplevel |describe| blocks
Reorder toplevel |describe| blocks to more closely match ordering used
in the PEG.js grammar and elsewhere in PEG.js.
10 years ago
David Majda 3308807d22 Behavior specs cleanup: Move spec/api/generated-parser-behavior.spec.js
Move spec/api/generated-parser-behavior.spec.js to
spec/behavior/generated-parser-behavior.spec.js. It's not an API test,
strictly speaking.
10 years ago
David Majda 84473db3ce Specs cleanup: Small description cleanups/fixes 10 years ago
David Majda 178d56699a Update GitHub project URLs
See https://groups.google.com/d/msg/pegjs/4a6zWKQSG6U/n8Pm257Lz6wJ.

I didn't update CHANGELOG.md as I consider issue URLs there historical artifacts
;-)
10 years ago
David Majda 5a2ca2abc7 Add two missing blank lines 11 years ago
David Majda 5ce5f7a612 Specs cleanup: Use raw node types in |generateBytecode| specs
Use raw node types instead of humanized node names in |generateBytecode|
specs. This corresponds more closely to the level the specs are written
at.
11 years ago
David Majda 0977dd37a3 Reordering in visitors and their specs
Reorder visiting functions and their specs to more closely match
ordering used in the PEG.js grammar.
11 years ago
David Majda 850ddf5889 Specs cleanup: Simplify compiler passes specs
After 898a7b5a2d the specs mostly tested
the visitor implementation, not actual code in the passes.
11 years ago
David Majda e101e1b6f3 Specs cleanup: Implement generated parser API specs
The generated parser API specs are mostly extracted from
generated-parser.spec.js, which got renamed to
generated-parser-behavior.spec.js to better reflect its purpose.
11 years ago
David Majda 94c8b08acf Specs cleanup: Implement plugin API specs 11 years ago
David Majda d0ff834a3d Specs cleanup: Implement PEG.js API specs
Some parts were previously part of generated parser specs, these were
moved.
11 years ago
David Majda 0306a76152 Specs cleanup: Rename & simplify |varyAll|
Rename |varyAll| to |varyOptimizationOptions|, because that's what the
function does. Simplify as we don't need a fully generic solution.
11 years ago
David Majda 3d637173ee Specs cleanup: Split specs into unit and API specs
Unit specs are unit tests of internal stuff. API specs are tests of the
user-visible APIs and behavior.

I think it makes sense to make this distinction because then the public
API line is more clearly visible e.g. when using the specs as
documentation.
11 years ago
David Majda dad1207c46 Improve semantics of the TEXT bytecode instruction
The TEXT instruction now replaces position at the top of the stack with
the input from that position until the current position. This is simpler
and cleaner semantics than the previous one, where TEXT also popped an
additional value from the stack and kept the position there.
11 years ago
David Majda a815a8b902 Implement additional PUSH_* bytecode instructions
Implement the following bytecode instructions:

  * PUSH_UNDEFINED
  * PUSH_NULL
  * PUSH_FAILED
  * PUSH_EMPTY_ARRAY

These instructions push simple JavaSccript values to the stack directly,
without going through constants. This makes the bytecode slightly
shorter and the bytecode generator somewhat simpler.

Also note that PUSH_EMPTY_ARRAY allows us to avoid a hack which protects
the [] constant from modification.
11 years ago
David Majda c6f0818d49 Use sentence case consistently in {spec,benchmark}/README.md headers 11 years ago
David Majda f102814998 Rewrite spec/README.md
More clarity, better grammar (hopefully).
11 years ago
David Majda 24e1644c58 Convert spec/README to Markdown
It will look nicer on GitHub.
11 years ago
David Majda 11aab6374f s/head/first/ & s/tail/rest/ in a testcase
Makes the testcase in sync with example grammars.
11 years ago
David Majda d9354c4632 Standardize on 3 spaces before // comments 11 years ago
David Majda f3a83788aa Inline functions extracted just because of JSHint
Rather than extracting functions just because JSHint complained about
defining functions inside a loop, let's inline then and silence the
warning.
11 years ago
David Majda 39084496ca Expose the parser object in action/predicate code
The action/predicate code didn't have access to the parser object. This
was mostly a side effect actions/predicates being implemented as nested
functions, in which |this| is a reference to the global object (an ugly
JavaScript quirk). The initializer, being implemented differently, had
access to the parser object via |this|, but this was not documented.

Because having access to the parser object can be useful, this commits
introduces a new |parser| variable which holds a reference to it, is
visible in action/predicate/initializer code, and is properly
documented.

See also:

  https://groups.google.com/forum/#!topic/pegjs/Na7YWnz6Bmg
11 years ago
David Majda 7e3b4ec4f8 PEG.js grammar: Remove reserved word detection
This is mostly done for consistency with the JavaScript example grammar,
from which the |Identifier| rule is taken from. See the previous commit
for details.
11 years ago
David Majda e78ffbba9c PEG.js grammar: Improve the |Code| rule a bit
Instead of matching segments between blocks character by character,
match them as a whole. Also align the style with other similar rules
(e.g. the comment ones).
11 years ago
David Majda 64eb5faf54 PEG.js grammar: Fix line continuation handling in character classes
Before this commit, line continuations in character classes contributed
an empty string to the list of characters and character ranges matched
by a class. While this didn't lead to a buggy behavior with the current
code generator, the AST was wrong and the problem could have caused bugs
later.

This commit fixes the problem.
11 years ago
David Majda 421b8d6e51 Clean up parser specs 11 years ago
David Majda 6f2510e49e PEG.js grammar: Make rules with operators more generic 11 years ago
David Majda 45c29a886f PEG.js grammar: Extract the |SemanticPredicateExpression| rule
Semantic predicates are kind of |PrimaryExpression|, not kind of
|PrefixedExpression|. Therefore I extracted a rule for them and
referenced it from the |PrimaryExpression|.
11 years ago
David Majda da18f6a729 PEG.js grammar: Extract the |RuleReferenceExpression| rule
This makes the |Primary| rule a bit more tidy.
11 years ago
David Majda 8e6f98e45c PEG.js grammar: Extract the |ActionExpression| rule
Having it separated from the |SequenceExpression| rule is cleaner and
more logical.
11 years ago
David Majda 5c6f4dd38b PEG.js grammar: Append |Expression| to expression rule names
Makes the rule names a bit longer but also clearer.
11 years ago
David Majda 27c2d26203 PEG.js grammar: More JavaScript-like initializer/rule separation
Initializer and rules are now separated in a similar way as JavaScript
statements -- either by a semicolon or a line terminator, possibly with
whitespace and comments mixed in.

One consequence is that the grammars like this are now illegal:

  foo = "a" bar = "b"

A semicolon needs to be inserted between the rules:

  foo = "a";bar = "b"

I consider this a good change as the now-illegal syntax was somewhat
confusing.
11 years ago
David Majda 4ce7593f5f PEG.js grammar: Extract the |AnyMatcher| rule
This makes the |Primary| rule a bit more tidy. Also, matching the |.|
character really belongs to the lexical part of the grammar, next to
literals and character classes.
11 years ago
David Majda c0df01b092 PEG.js grammar: Improve code block handling
* Rename the |Action| rule to |CodeBlock| (it better describes what
    the rule matches).

  * Implement the rule in a simpler way and move it after more basic
    lexical elements.
11 years ago
David Majda 13f72bb19d PEG.js grammar: More JavaScript-like rules for identifiers
This change has two side effects:

  * Label names can no longer be JavaScript reserved words.

  * |$| is allowed again in label names. However, because of the
    preference rules, names starting with it will be usually parsed as a
    text operator followed by another identifier (denoting a rule
    reference or label name).
11 years ago
David Majda 0d6b91cb20 PEG.js grammar: More JavaScript-like rules for strings/literals/classes 11 years ago
David Majda bcb5271649 PEG.js grammar: More JavaScript-like rules for skipped elements 11 years ago
David Majda a5a0609505 PEG.js grammar: Inline trivial character rules 11 years ago
David Majda ae89f5e469 PEG.js grammar: Change whitespace handling
Before this commit, whitespace was handled at the lexical level by
making tokens consume any whitespace coming after them. This was
accomplished by appending |__| to every token rule.

This commit changes whitespace handling to be more explicit. Tokens no
longer consume whitespace coming after them and syntactic rules have to
cope with it. While this slightly complicates the syntactic grammar, I
think it's a cleaner way. Moreover, it is what JavaScript example
grammar does.

One small side-effect of thich change is that the grammar is now
stand-alone (it doesn't require utils.js anymore).
11 years ago
David Majda 4725632641 PEG.js grammar: Capitalize rule names
When rule names are capitalized, it's easier to visually distinguish
them from non-capitalized label names. Moreover, I use capitalized rule
names in all my grammars these days.
11 years ago
David Majda fb72c430e6 PEG.js grammar: Fix line continuation handling
Before this commit, a line continuation (backslash followed by a line
terminator character) contributed a character to a string or a character
class it was used in. In JavaScript and many other languages, line
continuation doesn't contribute anything.

This commit aligns PEG.js line continuation behavior with JavaScript.
11 years ago
David Majda 3dbec0b30d PEG.js grammar: Fix how |rawText| is created
Before this commit, the value of the |rawText| property of "class" AST
nodes was created in a hackish way from processed input and it didn't
always exactly represent the actual input text.

This commit changes the code so that the value of the |rawText| property
is created using the |text| function. This is a clean way which also
resolves the exact representation problem.
11 years ago
David Majda df154daafb PEG.js grammar: Disallow empty sequences
Empty sequences are useless and they only confused users. Let's disallow
them.
11 years ago
David Majda 2263a30034 Update version to 0.8.0 11 years ago
David Majda 95fd64ec15 .jshintrc: Add the "forin" option & fix fallout
Also added few missing |hasOwnProperty| calls that JSHint didn't detect
because it only looks whether there is an |if| statement wrapping the
loop body.
11 years ago
David Majda a56d3ac94f Fix error messages in certain cases with trailing input
In case the generated parser parsed successfully part of input and left
some input unparsed (trailing input), the error message produced was
sometimes wrong. The code worked correctly only if there were no match
failures in the successfully parsed part (highly unlikely).

This commit fixes things by explicitly triggering a match failure with the
following expectation at the end of the successfully parsed part of the
input:

  peg$fail({ type: "end", description: "end of input" });

This change also made it possible to simplify the |buildMessage|
function, which can now ignore the case of no expectations.

Fixes #119.
11 years ago
David Majda 0bcf7bc61b Renumber bytecode instructions to make them sequential 11 years ago
David Majda 9f01c4b0c4 spec/generated-parser.spec.js: s/multiple-character/multi-character/ 11 years ago
David Majda 2d4ecaf39c spec/compiler/passes/generate-bytecode.spec.js: Fix comments 11 years ago
David Majda fbcefdf523 Fix |oneRuleGrammar| invocation
At one call site, the |oneRuleGrammar| was called with 3 parameters but
it only accepts 2. This commit removes the additional parameter.
11 years ago
David Majda e15c57066c Remove an error check after calling action code
The error check was useful when actions could have returned |null| to
trigger a match failure. This is no longer supported so the check isn't
needed anymore.

Speed impact
------------
Before:     1022.70 kB/s
After:      1035.45 kB/s
Difference: 1.24%

Size impact
-----------
Before:     975434 b
After:      931540 b
Difference: -4.50%

(Measured by /tools/impact with Node.js v0.6.18 on x86_64 GNU/Linux.)
11 years ago
David Majda 2f2152204a Refine error handling further
Before this commit, the |expected| and |error| functions didn't halt the
parsing immediately, but triggered a regular match failure. After they
were called, the parser could backtrack, try another branches, and only
if no other branch succeeded, it triggered an exception with information
possibly based on parameters passed to the |expected| or |error|
function (this depended on positions where failures in other branches
have occurred).

While nice in theory, this solution didn't work well in practice. There
were at least two problems:

  1. Action expression could have easily triggered a match failure later
     in the input than the action itself. This resulted in the
     action-triggered failure to be shadowed by the expression-triggered
     one.

     Consider the following example:

       integer = digits:[0-9]+ {
         var result = parseInt(digits.join(""), 10);

         if (result % 2 === 0) {
           error("The number must be an odd integer.");
           return;
         }

         return result;
       }

     Given input "2", the |[0-9]+| expression would record a match
     failure at position 1 (an unsuccessful attempt to parse yet another
     digit after "2"). However, a failure triggered by the |error| call
     would occur at position 0.

     This problem could have been solved by silencing match failures in
     action expressions, but that would lead to severe performance
     problems (yes, I tried and measured). Other possible solutions are
     hacks which I didn't want to introduce into PEG.js.

  2. Triggering a match failure in action code could have lead to
     unexpected backtracking.

     Consider the following example:

       class = "[" (charRange / char)* "]"

       charRange = begin:char "-" end:char {
         if (begin.data.charCodeAt(0) > end.data.charCodeAt(0)) {
           error("Invalid character range: " + begin + "-" + end + ".");
         }

         // ...
       }

       char = [a-zA-Z0-9_\-]

     Given input "[b-a]", the |charRange| rule would fail, but the
     parser would try the |char| rule and succeed repeatedly, resulting
     in "b-a" being parsed as a sequence of three |char|'s, which it is
     not.

     This problem could have been solved by using negative predicates,
     but that would complicate the grammar and still wouldn't get rid of
     unintuitive behavior.

Given these problems I decided to change the semantics of the |expected|
and |error| functions. They don't interact with regular match failure
mechanism anymore, but they cause and immediate parse failure by
throwing an exception. I think this is more intuitive behavior with less
harmful side effects.

The disadvantage of the new approach is that one can't backtrack from an
action-triggered error. I don't see this as a big deal as I think this
will be rarely needed and one can always use a semantic predicate as a
workaround.

Speed impact
------------
Before:     993.84 kB/s
After:      998.05 kB/s
Difference: 0.42%

Size impact
-----------
Before:     1019968 b
After:      975434 b
Difference: -4.37%

(Measured by /tools/impact with Node.js v0.6.18 on x86_64 GNU/Linux.)
11 years ago
David Majda 5460a881af Error handling: Implement the |error| function
The |error| function allows users to report custom match failures inside
actions.

If the |error| function is called, and the reported match failure turns
out to be the cause of a parse error, the error message reported by the
parser will be exactly the one specified in the |error| call.

Implements part of #198.

Speed impact
------------
Before:     999.83 kB/s
After:      1000.84 kB/s
Difference: 0.10%

Size impact
-----------
Before:     1017212 b
After:      1019968 b
Difference: 0.27%

(Measured by /tools/impact with Node.js v0.6.18 on x86_64 GNU/Linux.)
11 years ago
David Majda af701dcf80 Error handling: Implement the |expected| function
The |expected| function allows users to report regular match failures
inside actions.

If the |expected| function is called, and the reported match failure
turns out to be the cause of a parse error, the error message reported
by the parser will be in the usual "Expected ... but found ..." format
with the description specified in the |expected| call used as part of
the message.

Implements part of #198.

Speed impact
------------
Before:     1146.82 kB/s
After:      1031.25 kB/s
Difference: -10.08%

Size impact
-----------
Before:     950817 b
After:      973269 b
Difference: 2.36%

(Measured by /tools/impact with Node.js v0.6.18 on x86_64 GNU/Linux.)
11 years ago
David Majda 1b2279e026 Error handling: Make predicates always return |undefined|
After making the |?| operator return |null| instead of an empty string
in the previous commit, empty strings were still returned from
predicates. This didn't make much sense.

Return value of a predicate is unimportant (if you have one in hand, you
already know the predicate succeeded) and one could even argue that
predicates shouldn't return any value at all. The closest thing to
"return no value" in JavaScript is returning |undefined|, so I decided
to make predicates return exactly that.

Implements part of #198.
11 years ago
David Majda 86769a6c5c Error handling: Make |?| return |null| on unsuccessful match
Before this commit, the |?| operator returned an empty string upon
unsuccessful match. This commit changes the returned value to |null|. It
also updates the PEG.js grammar and the example grammars, which used the
value returned by |?| quite often.

Returning |null| is possible because it no longer indicates a match
failure.

I expect that this change will simplify many real-world grammars, as an
empty string is almost never desirable as a return value (except some
lexer-level rules) and it is often translated into |null| or some other
value in action code.

Implements part of #198.
11 years ago