Skip to content

Commit

Permalink
Parser speed optimization zaach#341: when both --no-try-catch and `…
Browse files Browse the repository at this point in the history
…--no-default-action` are specified, all safeties are moved, including protection in the kernel against incorrect use of `$$`/`$0` in grammar rule action code blocks. Example examples/test-unused-rules-reporting.jison is augmented to showcase the (**technically correct but functionally buggy!!!) behaviour.
  • Loading branch information
GerHobbelt committed Jan 31, 2017
1 parent 5d05164 commit 15747fc
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
39 changes: 38 additions & 1 deletion examples/test-unused-rules-reporting.jison
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
// rule, i.e. will be *unused* in the generated parser/grammar!
//

// build options:
%options no-try-catch no-default-action main


%lex

%%
Expand Down Expand Up @@ -69,9 +73,42 @@ var assert = require("assert");
parser.main = function () {
var rv = parser.parse("a");
//
// BIG FAT WARNING:
//
// Due to `%options no-try-catch no-default-action`, combined with the
// *lack* of action code for the `e: WORD` grammar rule, *that* rule's
// result `$$` will be UNDETERMINED, i.e. up for grabs, random, chaos.
//
// In *this particular example and input being parsed* this
// translates to the *previous* `$$` being picked up, which happens to
// be known as it comes out of the epsilon rule: `"ε"`, hence
// the 'expected output' IS NOT `"εεaε"` but `"εεεε"`!
//
// Yes, *functionally* that's an ERROR/BUG for certain, but the
// technicalities mentioned above make this the 'correct' output
// anyway. The ACTUAL BUG in this grammar example is the `e: WORD` rule
// **not having any action code assigning a value to `$$`** since that
// is the only sane activity *everywhere* when you choose to compile
// with `%options no-default-action`.
//
// Aside: note that `%options no-try-catch no-default-action` does
// remove additional safeguards in the parser kernel code: this option
// combo also causes code to be removed with sets `$0` and `$$` to
// `undefined` *before* any rule's action code is executed so any
// protection against grammar-coder mistakes such as this action code
// chunk is removed in exchange for parser execution speed:
//
// %{ $$ = Math.sin($$ /* BUG! NOT SANE TO USE `$$` or `$0` AS INPUT! */); %}
//
// *Caveat Emptor* i.e. when ou choose Speed, you are expected to
// be fully aware that Safety is Not An Option Any More(tm)!
//
console.log("(reduce epsilon rules as early as possible)\n\n a ==> ", rv);
assert.equal(rv, "εεaε");
assert.equal(rv, "εεεε");
// if you get past the assert(), you're good.
console.log("tested OK");
Expand Down
13 changes: 13 additions & 0 deletions lib/jison.js
Original file line number Diff line number Diff line change
Expand Up @@ -3267,6 +3267,19 @@ function removeUnusedKernelFeatures(parseFn, info) {
.replace(/^[^\n]+\b__reentrant_call_depth\b[^\n]+$/gm, '\n');
}

if (info.options.noDefaultAction && info.options.noTryCatch) {
/*
* This is a very performance-oriented setting and does not care if the
* userland code for the grammar rules is flaky.
* Kill this protection code:
*
* // Do this to prevent ...
* vstack[sp] = undefined;
*/
parseFn = parseFn
.replace(/\s+\/\/ Do this to prevent nasty action block codes[^\n]+\n\s+vstack\[sp\] = undefined;[^\n]+\n/g, '\n\n');
}

info.performAction = actionFn;

return parseFn;
Expand Down

0 comments on commit 15747fc

Please sign in to comment.