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.)
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.
This simplifies the code a bit and makes the AST more regular (each node
type has a fixed set of properties). The latter may get useful later
when generalizing visitors.
This has two main benefits:
1. The knowledge about scoping params in at one designated place,
making all future adjustments in this area easier.
2. Action-related code does not handle sequences specially anymore.
Such knowledge/behavior doesn't belong there.
Before this change, knowledge about variable names was spread between
the |computeStackDepths| pass and the code emitter code. For example,
the fact that the |&...| expression needs one variable to store a
position was represented in both places.
This changes consolidates that knowledge and introduces a new
|computeVarNames| pass. This pass replaces old |computeStackDepths|
pass, does all computations realted to variable names and stores the
results in the AST. Note that some knowledge about variables
(inevitably) remained in emitter code templates.
Beside DRYing things up, this change simplifies the emitter
significantly. By storing variable names in the AST it also allows
introduction of a pass that will identify parameters passed to actions
using proper symbol tables. Right now, this is done in a hackish way
directly in the emitter, which won't work well with changes planned in
GH-69.
Fixes the following JSHint errors:
./test/parser-test.js: line 353, col 54, Bad escapement.
./test/parser-test.js: line 384, col 54, Bad escapement.
./test/parser-test.js: line 436, col 60, Bad escapement.
./test/parser-test.js: line 437, col 60, Bad escapement.
./test/parser-test.js: line 472, col 50, Bad escapement.
Fixes the following JSHint errors:
./test/parser-test.js: line 49, col 4, Missing semicolon.
./test/parser-test.js: line 58, col 4, Missing semicolon.
./test/parser-test.js: line 77, col 2, Unnecessary semicolon.
./test/parser-test.js: line 137, col 23, Missing semicolon.
Fixes the following JSHint errors:
./test/parser-test.js: line 521, col 29, Nested comment.
./test/parser-test.js: line 521, col 29, Stopping, unable to continue. (87% scanned).
Fixes the following JSHint errors:
./test/passes-test.js: line 12, col 6, Missing semicolon.
./test/passes-test.js: line 25, col 4, Missing semicolon.
./test/passes-test.js: line 229, col 41, Missing semicolon.
Fixes the following JSHint errors:
./test/checks-test.js: line 26, col 8, Don't make functions within a loop.
./test/checks-test.js: line 31, col 5, Don't make functions within a loop.
./test/checks-test.js: line 59, col 8, Don't make functions within a loop.
./test/checks-test.js: line 64, col 5, Don't make functions within a loop.
Before this commit, variables for saving match results and parse
positions in generated parsers were not used efficiently. Each rule
basically used its own variable(s) for storing the data, with names
generated sequentially during code emitting. There was no reuse of
variables and a lot of unnecessary assignments between them.
It is easy to see that both match results and parse positions can
actually be stored on a stack that grows as the parser walks deeper in
the grammar tree and shrinks as it returns. Moreover, if one creates a
new stack for each rule the parser enters, its maximum depth can be
computed statically from the grammar. This allows us to implement the
stack not as an array, but as a set of numbered variables in each
function that handles parsing of a grammar rule, avoiding potentially
slow array accesses.
This commit implements the idea from the previous paragraph, using
separate stack for match results and for parse positions. As a result,
defined variables are reused and unnecessary copying avoided.
Speed implications
------------------
This change speeds up the benchmark suite execution by 2.14%.
Detailed results (benchmark suite totals as reported by "jake benchmark"
on Node.js 0.4.8):
-----------------------------------
Test # Before After
-----------------------------------
1 129.01 kB/s 131.98 kB/s
2 129.39 kB/s 130.13 kB/s
3 128.63 kB/s 132.57 kB/s
4 127.53 kB/s 129.82 kB/s
5 127.98 kB/s 131.80 kB/s
-----------------------------------
Average 128.51 kB/s 131.26 kB/s
-----------------------------------
Size implications
-----------------
This change makes a sample of generated parsers 8.60% smaller:
Before:
$ wc -c src/parser.js examples/*.js
110867 src/parser.js
13886 examples/arithmetics.js
450125 examples/css.js
632390 examples/javascript.js
61365 examples/json.js
1268633 total
After:
$ wc -c src/parser.js examples/*.js
99597 src/parser.js
13077 examples/arithmetics.js
399893 examples/css.js
592044 examples/javascript.js
54797 examples/json.js
1159408 total
The change does not change the benchmark suite execution speed
statistically significantly.
Detailed results (benchmark suite totals as reported by "jake benchmark"
on Node.js 0.4.8):
-----------------------------------
Test # Before After
-----------------------------------
1 128.20 kB/s 128.03 kB/s
2 130.36 kB/s 128.73 kB/s
3 126.53 kB/s 129.72 kB/s
4 127.46 kB/s 127.48 kB/s
5 127.63 kB/s 128.53 kB/s
-----------------------------------
Average 128.04 kB/s 125.50 kB/s
-----------------------------------
Closes GH-25.
Calling the parsing function could have been done without the ugly table
using |eval|, but this seemed to degrade performance significantly (by
about 3 %). This is probably because engines optimize badly in presence
of |eval|.
The method used in this patch does not change the benchmark suite
execution speed statistically significantly on V8.
Detailed results (benchmark suite totals):
---------------------------------
Test # Before After
---------------------------------
1 38.24 kB/s 38.28 kB/s
2 38.35 kB/s 38.15 kB/s
3 38.43 kB/s 38.40 kB/s
4 38.53 kB/s 38.20 kB/s
5 38.25 kB/s 38.39 kB/s
---------------------------------
Average 38.36 kB/s 38.39 kB/s
---------------------------------
Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.1