diff --git a/.gitignore b/.gitignore
index 3f1af7895..49b724ab5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@ node_modules
# Editor backup files
*.bak
*~
-web/content/assets/js/jison.js
\ No newline at end of file
+web/content/assets/js/jison.js
+web/crash.log
diff --git a/web/content/assets/js/try.js b/web/content/assets/js/try.js
index 29ebbcc38..2557c2d07 100644
--- a/web/content/assets/js/try.js
+++ b/web/content/assets/js/try.js
@@ -1,5 +1,7 @@
(function ($) {
+var worker = new Worker('../assets/js/worker.js');
+
var parser,
parser2;
@@ -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) {
@@ -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:
').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:
').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 {
diff --git a/web/content/assets/js/worker.js b/web/content/assets/js/worker.js
new file mode 100644
index 000000000..120596ed3
--- /dev/null
+++ b/web/content/assets/js/worker.js
@@ -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"}});
+});
\ No newline at end of file
diff --git a/web/content/assets/styles/try.css b/web/content/assets/styles/try.css
index f6c402a81..ed7711704 100644
--- a/web/content/assets/styles/try.css
+++ b/web/content/assets/styles/try.css
@@ -82,3 +82,8 @@ table tr:hover td {
background: #fee;
border: 2px solid red;
}
+
+.warning {
+ background: #feffef;
+ border: 2px solid yellow;
+}
\ No newline at end of file
diff --git a/web/content/try.html b/web/content/try.html
index 4a0de15c9..cc0946662 100644
--- a/web/content/try.html
+++ b/web/content/try.html
@@ -79,7 +79,6 @@
-