66 Commits (5b3321d302315fa47c3147492a8bd619b2174089)

Author SHA1 Message Date
David Majda 5b3321d302 Implement |cache| option for |PEG.buildParser|
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.)
12 years ago
David Majda 1ee6731b51 Supply default option value only if the option is not specified
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.
12 years ago
David Majda 2aaa038499 Add a hack to skip last comma in |parseFunctions| 12 years ago
David Majda 8d74248251 Make "Generated by ..." comment match the copyright comment 12 years ago
David Majda 90d164445a Update embedded Codie to version 1.1.0 12 years ago
David Majda 52d7ec2224 Implement |trackLineAndColumn| option for |PEG.buildParser|
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.
12 years ago
David Majda 9615eb4bb6 Allow passing options to |PEG.buildParser|
These get passed down to the emitter templates.
12 years ago
David Majda f2f88b87ea Make current parse position visible in actions and predicates
The speed/size impact is insignificant.

Speed impact
------------
Before:     214.11 kB/s
After:      214.87 kB/s
Difference: 0.35%

Size impact
-----------
Before:     1042691 b
After:      1046731 b
Difference: 0.38%

(Measured by /tools/impact with Node.js v0.6.6 on x86_64 GNU/Linux.)
12 years ago
David Majda 4d5b1d58aa AST: Store rules in an array instead of an object
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.
12 years ago
David Majda ed45a1808e Fix |quote| visibility in generated parsers
|quote| is used outside of the |parse| function so it must be defined in
more outer scope.

Fixes a problem (introduced in e9d8dc8eba)
where construction of some error messages could throw an error.
12 years ago
David Majda a2af1fe612 Semantic predicates now have access to preceding labels
Part of a fix for GH-69.
12 years ago
David Majda 4cf50bcf9f Move param computations from the emitter into a separate pass
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.
12 years ago
David Majda efc38eef9b Consolidate all variable name computations into one compiler pass
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.
12 years ago
David Majda 46b2eaf3e3 Add |expected| and |found| properties to exceptions thrown by parsers
Based on a patch by Marcin Stefaniuk (marcin@stefaniuk.info).
12 years ago
David Majda e9d8dc8eba More responsibility for building an error message into |SyntaxError| 12 years ago
David Majda 21c6d9ccd3 Add |offset| property to exceptions thrown by parsers
Based on a patch by Marcin Stefaniuk (marcin@stefaniuk.info).
12 years ago
David Majda 791c495aec Update embedded Codie to version 1.0.1 13 years ago
David Majda 47969a2f61 Replace |for| loop iterating over sequence elements with |each| 13 years ago
David Majda 8acea01525 Fix reported error position when part of the input is not consumed
Closes GH-48.
13 years ago
David Majda c04af99df8 Implament case-insensitive class matching 13 years ago
David Majda b540b2d460 Implement case-insensitive literal matching 13 years ago
David Majda da12c2f5d4 Compile Codie templates only once 13 years ago
David Majda a5af9611a2 Introduce |context.delta| function to make creating contexts more DRY 13 years ago
David Majda be3b87ec71 Refactor "grammar" emitter function a bit 13 years ago
David Majda 2b09a7116d Refactor "rule" emitter function a bit 13 years ago
David Majda 131b6dd01f Refactor "sequence" emitter function a bit 13 years ago
David Majda f29ff236b8 Refactor "simple_and" emitter function a bit 13 years ago
David Majda 506d8107a1 Refactor "simple_not" emitter function a bit 13 years ago
David Majda 13ae52b2bf Refactor "semantic_and" emitter function a bit 13 years ago
David Majda 9111020ca2 Refactor "semantic_not" emitter function a bit 13 years ago
David Majda cc3bd4f310 Refactor "zero_or_more" emitter function a bit 13 years ago
David Majda 85c1b010b6 Refactor "one_or_more" emitter function a bit 13 years ago
David Majda b5ca96dd48 Refactor "action" emitter function a bit 13 years ago
David Majda 50a0371e2d Refactor "rule_ref" emitter function a bit 13 years ago
David Majda eaba6b8a9d Refactor "literal" emitter function a bit 13 years ago
David Majda 2120c908c7 Refactor "class" emitter function a bit 13 years ago
David Majda 0748fee1d3 Use Codie for code templates
This will allow moving some code into the templates later.
13 years ago
David Majda 38c25efde0 Use single quotes for code in the emitter
Strings with code should use single quotes so that double quotes (which
I generally prefer) could be used in the code itself without escaping.
13 years ago
David Majda 45c99f8f6b Generate more efficient code for empty literals
Original patch by Wolfgang Kluge:

  797173f676
13 years ago
David Majda eceda8b5e8 Use correct disjunction operator in |computeErrorPosition|
Original patch by Wolfgang Kluge:

  6b793b33df
13 years ago
David Majda bc4821581c src/emitter.js: Fix variable redefinitions
Fixes the following JSHint errors:

  ./src/emitter.js: line 95, col 21, 'name' is already defined.
  ./src/emitter.js: line 361, col 35, 'setReportFailuresCode' is already defined.
  ./src/emitter.js: line 362, col 39, 'restoreReportFailuresCode' is already defined.
  ./src/emitter.js: line 363, col 31, 'reportFailureCode' is already defined.
  ./src/emitter.js: line 393, col 38, 'setReportFailuresCode' used out of scope.Fixes the following JSHint errors:
  ./src/emitter.js: line 394, col 38, 'restoreReportFailuresCode' used out of scope.
  ./src/emitter.js: line 395, col 38, 'reportFailureCode' used out of scope.
  ./src/emitter.js: line 666, col 26, 'formalParams' is already defined.
  ./src/emitter.js: line 667, col 26, 'actualParams' is already defined.
  ./src/emitter.js: line 669, col 26, 'formalParams' is already defined.
  ./src/emitter.js: line 670, col 26, 'actualParams' is already defined.
  ./src/emitter.js: line 685, col 27, 'formalParams' used out of scope.
  ./src/emitter.js: line 686, col 27, 'actualParams' used out of scope.
  ./src/emitter.js: line 770, col 20, 'regexp' is already defined.
  ./src/emitter.js: line 784, col 22, 'regexp' used out of scope.
13 years ago
David Majda a52522c7c6 src/emitter.js: Remove unnecessary semicolon
Fixes the following JSHint error:

  ./src/emitter.js: line 77, col 4, Unnecessary semicolon.
13 years ago
David Majda d1b83e4ab3 src/emitter.js: Use strict comparison
Fixes the following JSHint error:

  ./src/emitter.js: line 44, col 48, Expected '!==' and instead saw '!='.
13 years ago
David Majda ab49197ef1 src/utils.js: Make |quote| escape control characters
Also change |quote| in src/emitter.js so both are in sync.

Fixes the following JSHint errors:

  ./src/parser.js: line 3613, col 27, Mixed spaces and tabs.
  ./src/parser.js: line 3613, col 31, Unsafe character.
  ./src/parser.js: line 3613, col 38, Control character in string: [     .
  ./src/parser.js: line 3613, col 40, Control character in string: [
13 years ago
David Majda 559db3a812 src/emitter.js: Sync |escape| in generated parsers with utils.js
Fixes the following JSHint errors:

  ./src/parser.js: line 102, col 26, 'escapeChar' is already defined.
  ./src/parser.js: line 103, col 22, 'length' is already defined.
  ./src/parser.js: line 106, col 23, 'escapeChar' used out of scope.
  ./src/parser.js: line 106, col 86, 'length' used out of scope.
13 years ago
David Majda 468597be27 Use |charCodeAt| instead of |charCode| when matching one-character literals
The speedup is marginal (if any) but let's have this anyway.

Speed impact
------------
Before:     212.49 kB/s
After:      213.01 kB/s
Difference: 0.24%

Size impact
-----------
Before:     1056976 b
After:      1058314 b
Difference: 0.12%

(Measured by /tools/impact with Node.js v0.4.8 on x86_64 GNU/Linux.)

Closes GH-50.
13 years ago
David Majda d3aff0c66a Use |charAt| instead of |substr| when matching classes
Speed impact
------------
Before:     131.36 kB/s
After:      213.59 kB/s
Difference: 62.59%

Size impact
-----------
Before:     1056976 b
After:      1056976 b
Difference: 0.00%

(Measured by /tools/impact with Node.js v0.4.8 on x86_64 GNU/Linux.)

Closes GH-49.
13 years ago
David Majda 0a1cea5f12 Use |charAt| instead of |substr| when matching one-character literals
Speed impact
------------
Before:     130.62 kB/s
After:      133.76 kB/s
Difference: 2.40%

Size impact
-----------
Before:     1058371 b
After:      1056976 b
Difference: -0.14%

(Measured by /tools/impact with Node.js v0.4.8 on x86_64 GNU/Linux.)
13 years ago
David Majda 2fc877e875 Match literals using |RegExp.prototype.test|
This is little faster than |String.prototype.match| in successful cases
since return value of |test| is just a boolean, not a special array as
with |match|.

Speed impact
------------
Before:     130.75 kB/s
After:      131.81 kB/s
Difference: 0.81%

Size impact
-----------
Before:     1059811 b
After:      1058371 b
Difference: -0.14%

(Measured by /tools/impact with Node.js v0.4.8 on x86_64 GNU/Linux.)
13 years ago
David Majda d123cf0eda Rewrite variable handling in generated parsers
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
13 years ago