Skip to content

Commit

Permalink
Add web workers, parse automatically
Browse files Browse the repository at this point in the history
I thought the demo might be nicer if it used web workers
to parse the grammar in the background. That way it doesn't
block the DOM, so it's a bit smoother.

Additionally, since we're not blocking the DOM, we can just
automatically re-parse the file as the user types. I set a
debounce of 700ms so that it doesn't fire too frequently. I also
removed the "Generate" button entirely, and set it up so there's a little
"Parsing..." message while it's parsing. I also made to sure to do
a fallback if web workers aren't supported in the browser (and I tested
that it works).

You can try a demo
[here](https://nolanlawson.s3.amazonaws.com/jison/try/index.html).
  • Loading branch information
nolanlawson committed Mar 3, 2015
1 parent 245f6dd commit 28debc7
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 34 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ node_modules
# Editor backup files
*.bak
*~
web/content/assets/js/jison.js
web/content/assets/js/jison.js
web/crash.log
133 changes: 101 additions & 32 deletions web/content/assets/js/try.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
(function ($) {

var worker = new Worker('../assets/js/worker.js');

var parser,
parser2;

Expand All @@ -13,8 +15,20 @@ print = function (){}

var printOut = function (str) { $("#out").html(str); };

function debounce(timeout, fn) {
var timer;

return function() {
clearTimeout(timer);

timer = setTimeout(function() {
fn();
timer = null;
}, timeout);
};
}

$(document).ready(function () {
$("#process_btn").click(processGrammar);
$("#parse_btn").click(runParser);

$("#examples").change(function(ev) {
Expand All @@ -23,52 +37,107 @@ $(document).ready(function () {
$.get("/jison/examples/"+file, function (data) {
$("#grammar").val(data);
$(document.body).removeClass("loading");
processGrammar();
});
});


// recompile the grammar using a web worker,
// as the user types
var onChange = debounce(700, processGrammar);
$('#grammar').bind('input propertychange', onChange);
processGrammar();
});

function processGrammar () {
var type = "lalr";

var grammar = $("#grammar").val();
try {
var cfg = JSON.parse(grammar);
} catch(e) {

function onError(e) {
console.log(e);
$("#gen_out").html("Oops. Make sure your grammar is " +
"in the correct format."+ "\n" + e.stack)
.removeClass('good')
.removeClass('warning')
.addClass('bad');
}

function onSuccess(result) {

try {
var cfg = bnf.parse(grammar);
parser = Jison.Generator(result.cfg, {type: result.type});
} catch (e) {
$("#gen_out").html("Oops. Make sure your grammar is in the correct format.\n"+e).addClass('bad');
return;
return onError(e);
}

$("#out").removeClass("good").removeClass("bad").html('');
$("#gen_out").removeClass("good").removeClass("bad").removeClass('warning');
if (!parser.conflicts) {
$("#gen_out").html('Generated successfully!').addClass('good');
} else {
$("#gen_out").html('Conflicts encountered:<br/>').addClass('bad');
}
}

Jison.print = function () {};
parser = Jison.Generator(cfg, {type: type});
$("#download_btn").click(function () {
window.location.href = "data:application/javascript;charset=utf-8;base64,"+Base64.encode(parser.generate());
}).removeAttr('disabled');



parser.resolutions.forEach(function (res) {
var r = res[2];
if (!r.bydefault) return;
$("#gen_out").append(r.msg+"\n"+"("+r.s+", "+r.r+") -> "+r.action);
});

parser2 = parser.createParser();
}

// for newer browsers
function callWorker(grammar) {
worker.addEventListener('error', onError);
worker.addEventListener('message', function(e) {
onSuccess(e.data.result);
});

// ask the web worker to parse the grammar for us
worker.postMessage(grammar);
}

// for older browsers (IE <=9, Android <=4.3)
function callNonWorker(grammar) {
Jison.print = function () {};
var cfg;

$("#out").removeClass("good").removeClass("bad").html('');
$("#gen_out").removeClass("good").removeClass("bad");
if (!parser.conflicts) {
$("#gen_out").html('Generated successfully!').addClass('good');
try {
cfg = JSON.parse(grammar);
} catch (e) {
try {
cfg = bnf.parse(grammar);
} catch (e) {
return onError(e);
}
}

onSuccess({cfg: cfg, type: 'lalr'});
}

$("#gen_out").html("Parsing...")
.removeClass('good')
.removeClass('bad')
.addClass('warning');
$('#download_btn').attr('disabled', true);

var grammar = $("#grammar").val();

if (typeof Worker !== 'undefined') {
callWorker(grammar);
} else {
$("#gen_out").html('Conflicts encountered:<br/>').addClass('bad');
callNonWorker(grammar);
}

$("#download_btn").click(function () {
window.location.href = "data:application/javascript;charset=utf-8;base64,"+Base64.encode(parser.generate());
}).removeAttr('disabled');

parser.resolutions.forEach(function (res) {
var r = res[2];
if (!r.bydefault) return;
$("#gen_out").append(r.msg+"\n"+"("+r.s+", "+r.r+") -> "+r.action);
});

parser2 = parser.createParser();
}

function runParser () {
if (!parser) processGrammar();
if (!parser) {
processGrammar();
}
printOut("Parsing...");
var source = $("#source").val();
try {
Expand Down
24 changes: 24 additions & 0 deletions web/content/assets/js/worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

importScripts('jison.js');
Jison.print = function () {};

// request to parse a grammar
self.addEventListener('message', function (e) {
if (typeof e.data !== 'string') {
return;
}

var grammar = e.data;

var cfg;

try {
cfg = JSON.parse(grammar);
} catch (e) {
// intentionally throw an error here if it fails to parse
cfg = bnf.parse(grammar);
}

self.postMessage({result: {cfg: cfg, type: "lalr"}});
});
5 changes: 5 additions & 0 deletions web/content/assets/styles/try.css
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,8 @@ table tr:hover td {
background: #fee;
border: 2px solid red;
}

.warning {
background: #feffef;
border: 2px solid yellow;
}
1 change: 0 additions & 1 deletion web/content/try.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ <h2>Describe Your Language</h2>
;
</textarea>
<p>
<button id="process_btn">Generate Parser</button>
<button id="download_btn" disabled>Download</button>
</p>
<pre id="gen_out"></pre>
Expand Down

0 comments on commit 28debc7

Please sign in to comment.