Implement a new syntax to extract matched strings from expressions. For
example, instead of:
identifier = first:[a-zA-Z_] rest:[a-zA-Z0-9_]* { return first + rest.join(""); }
you can now just write:
identifier = $([a-zA-Z_] [a-zA-Z0-9_]*)
This is useful mostly for "lexical" rules at the bottom of many
grammars.
Note that structured match results are still built for the expressions
prefixed by "$", they are just ignored. I plan to optimize this later
(sometime after the code generator rewrite).
Includes:
* Moving the source code from /src to /lib.
* Adding an explicit file list to package.json
* Updating the Makefile.
* Updating the spec and benchmark suites and their READMEs.
Part of a fix for GH-32.
PEG.js source code becomes a set of Node.js modules that include each
other as needed. The distribution version is built by bundling these
modules together, wrapping them inside a bit of boilerplate code that
makes |module.exports| and |require| work.
Part of a fix for GH-32.
When the Git repository will be a npm package, there will be no
preprocessing step and thus no @VERSION substitution. Let's get rid of
it.
Part of a fix for GH-32.
Change the value of the |name| property of |PEG.GrammarError| instances
from "PEG.GrammarError" to just "GrammarError". This better reflects the
fact that PEG.js can get required under different name than "PEG".
Before this commit, generated parser were able to start parsing from any
rule. This was nice, but it made rule code inlining impossible.
Since this commit, the list of allowed start rules has to be specified
explicitly using the |allowedStartRules| option of the |PEG.buildParser|
method (or the --allowed-start-rule option on the command-line). These
rules will be excluded from inlining when it's implemented.
"modelled" is a British variant, "modeled" an US one. PEG.js officially
uses American English.
Based on pull request by John Gietzen:
https://github.com/dmajda/pegjs/pull/102
This commit replaces the |startRule| parameter of the |parse| method in
generated parsers with more generic |options| -- an options object. This
options object can be used to pass custom options to the parser because
it is visible as the |options| variable inside parser code.
The start rule can now be specified as the |startRule| option. This
means you have to replace all calls like:
parser.parse("input", "myStartRule");
with
parser.parse("input", { startRule: "myStartRule" });
Closes GH-37.
The purpose of this change is to avoid the need to index register
variables storing match results of sequences whose elements are labeled.
The indexing happened when match results of labeled elements were passed
to action/predicate functions.
In order to avoid indexing, the register allocator needs to ensure that
registers storing match results of any labeled sequence elements are
still "alive" after finishing parsing of the sequence. They should not
be used to store anything else at least until code of all actions and
predicates that can see the labels is executed. This requires that the
|allocateRegisters| pass has the knowledge of scoping. Because that
knowledge was already implicitly embedded in the |coputeParams| pass,
the logical step to prevent duplication was to merge it with the
|allocateRegisters| pass. This is what this commit does.
As a part of the merge the tests of both passes were largely refactored.
This is both to accomodate the merge and to make the tests in sync with
the code again (the tests became a bit out-of-sync during the last few
commits -- they tested more than was needed).
The speed/size impact is slightly positive:
Speed impact
------------
Before: 849.86 kB/s
After: 858.16 kB/s
Difference: 0.97%
Size impact
-----------
Before: 876618 b
After: 875602 b
Difference: -0.12%
(Measured by /tools/impact with Node.js v0.6.18 on x86_64 GNU/Linux.)
This commit changes the model underlying parser variables used to store
match results and parse positions. Until now they were treated as a
stack, now they are thought of as registers. The actual behavior does
not change (yet), only the terminology.
More specifically, this commit:
* Changes parser variable names from |result0|, |result1|, etc. to
|r0|, |r1|, etc.
* Changes various internal names and comments to match the new model.
* Renames the |computeVarIndices| pass to |allocateRegisters|.
One stack is conceptually simpler, requires less code and will make a
transition to a register-based machine easier.
Note that the stack variables are now named a bit incorrectly
(|result0|, |result1|, etc. even when they store also parse positions).
I didn't bother with renaming because a transition to a register-based
machine will follow soon and the names will change anyway.
The speed/size impact is insignificant.
Speed impact
------------
Before: 839.05 kB/s
After: 839.67 kB/s
Difference: 0.07%
Size impact
-----------
Before: 949783 b
After: 961578 b
Difference: 1.24%
(Measured by /tools/impact with Node.js v0.6.18 on x86_64 GNU/Linux.)
Before this commit, each node was responsible for computing the value of
its |resultIndex| property in the |computeVarIndices| pass. This was
possible because |resultIndex| was always equal to |index.result|,
meaning that nodes always wrote their match results to the top of the
stack.
This behavior would cause problems in the future where nodes will use
the stack also for storing positions. Parent nodes storing position on
the stack would have to copy their childs' match results from the top of
the stack to some position below where parent's match result would be
expected. There would be no way to tell the children to place their
match result somewhere else than the top of the stack and avoid copying.
This commit fixes the described problem by shifting the responsibility
for setting the value of node's |resultIndex| property to its parent.
This way it can direct its child to place its result wherever it wants
to.
This commit replaces all variable name computations in |computeVarNames|
and |computeParams| passes by computations of indices. The actual names
are computed later in the |generateCode| pass.
This change makes the code generator the only place that deals with the
actual variable names, making them easier to change for example.
The code generator code seems bit more complicated after the change, but
this complexity will pay off (and mostly disappear) later.
Places all code that does something with "action" AST nodes under code
handling "choice" nodes.
This ordering is logical because now all the node handling code matches
the sequence in which various node types usually appear when descending
through the AST tree.
Changes all code that does something with "literal", "class" or "any"
AST nodes so that the code deals with these in the follwing order:
1. literal
2. class
3. any
Previously the code used this ordering:
1. literal
2. any
3. class
The new ordering is more logical because the nodes are handled from the
most specific to the most generic.
PEG.js grammar rules are represented by |rule| nodes in the AST. Until
now, all such nodes had a |displayName| property which was either |null|
or stored rule's human-readable name. This commit gets rid of the
|displayName| property and starts representing rules with a
human-readable name using a new |named| node (a child of the |rule|
node).
This change simplifies code generation code a bit as tests for
|displayName| can be removed (see changes in generate-code.js). It also
separates different concerns from each other nicely.
This option enables/disables the results cache in generated parsers.
Until now, it was always enabled, but after this commit it needs to be
enabled explicitly (i.e. the |cache| option default value is |false|).
The reason is that parsing without it is *much* faster according to the
benchmark.
Note that disabling the cache breaks the linear parsing time guarantee,
meaning that with some grammars you can get exponential parsing time
with respect to the input length. This, together with the possibility of
improving the cache performance in the future, is the reason to keep it
as an option.
Speed impact
------------
Before: 214.08 kB/s
After: 827.52 kB/s
Difference: 286.54%
Size impact
-----------
Before: 1045396 b
After: 949783 b
Difference: -9.15%
(Measured by /tools/impact with Node.js v0.6.6 on x86_64 GNU/Linux.)
The "|| trick" is too brittle in this case -- it wouldn't work e.g. for
options with default value |true| and passed value |false|, enforcing
inconsistent default values handling.
This commit makes the library define the |PEG| global variable (for
browser export) and possibly assign it into |module.exports| (for
Node.js export) later. The |module.exports| assignment is done *outside*
the main library |function| statement.
The big idea behind this is to make copy & paste inclusion of the
library into another code easier -- one just needs to strip the last
three lines.
This option makes the generated parser track line and column during
parsing. Tracked line and column are made available inside actions and
predicates as |line| and |column| variables.
Note that in actions these variables denote start position of the
action's expression while in predicates they denote the current
position. The slightly different behavior is motivated by expected
usage.