diff --git a/examples/unfinished/jsparse-demo/jsparse-demo.css b/examples/unfinished/jsparse-demo/jsparse-demo.css index bea973c397..f0c71202e7 100644 --- a/examples/unfinished/jsparse-demo/jsparse-demo.css +++ b/examples/unfinished/jsparse-demo/jsparse-demo.css @@ -25,38 +25,82 @@ html, body { height: 100%; } bottom: 0; } -#inputarea textarea { +#inputarea { border: 0; border-right: 1px solid #555; position: absolute; height: 100%; left: 0; right: 50%; +} + +#inputarea textarea { + position: absolute; + width: 100%; + height: 100%; font-family: monospace; font-size: 100%; + border: 0; +} + +#outputoptions { + position: absolute; + left: 50%; + right: 0; + overflow: visible; + bottom: 0; + height: 29px; + border-top: 1px solid #555; + + background: #ccc; } #output { position: absolute; - height: 100%; left: 50%; right: 0; overflow: auto; + top: 0; + bottom: 30px; font-family: monospace; } +#outputoptions .output-type { + text-decoration: none; + font-family: sans-serif; + font-size: 14px; + display: inline-block; + background: #e2e2e2; + vertical-align: top; + position: relative; + top: -1px; + padding: 3px 8px; + margin-left: 6px; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + border: 1px solid #777; + border-top: 1px solid #555; + cursor: pointer; +} + +#outputoptions .output-type.selected { + font-weight: bold; + background: #fff; + border-top: 1px solid #fff; +} + #inputarea textarea, #output { line-height: 130%; } -.lex { border: 1px solid #333; } +.lex { border: 1px solid #333; cursor: pointer; } .lex_keyword { background: #0f0; } .lex_identifier { background: #ff0; } .lex_punctuation { background: #0ff; } .lex_error { background: #f00; } -.lex_whitespace { background: #fcc; } +.lex_whitespace, .lex_newline, .lex_eof { background: #fcc; } .lex_comment { background: #ccc; } .lex_regex { background: #f0f; } diff --git a/examples/unfinished/jsparse-demo/jsparse-demo.html b/examples/unfinished/jsparse-demo/jsparse-demo.html index fd7986ba16..ab3d3b36f6 100644 --- a/examples/unfinished/jsparse-demo/jsparse-demo.html +++ b/examples/unfinished/jsparse-demo/jsparse-demo.html @@ -22,6 +22,11 @@ whitespace is significant here; browser swallows initial }} +
+ {{#each outputTypes}} + {{name}} + {{/each}} +
{{output}}
diff --git a/examples/unfinished/jsparse-demo/jsparse-demo.js b/examples/unfinished/jsparse-demo/jsparse-demo.js index 03920abd4e..a8a063c187 100644 --- a/examples/unfinished/jsparse-demo/jsparse-demo.js +++ b/examples/unfinished/jsparse-demo/jsparse-demo.js @@ -4,6 +4,8 @@ if (Meteor.is_client) { Meteor.startup(function () { if (! Session.get("input")) Session.set("input", "var x = 3"); + if (! Session.get("output-type")) + Session.set("output-type", "parse"); }); Template.page.input = function () { @@ -13,92 +15,103 @@ if (Meteor.is_client) { Template.page.output = function () { var input = Session.get("input") || ""; - // LEXER - /* - if (! input) - return ""; - - var L = new Lexer(input); - var html = ""; - while (L.next() !== 'EOF') { - if (L.type === "NEWLINE") { - html += '
'; - } else { - var text = Handlebars._escape(L.text || ' '); - text = text.replace(/(?!.)\s/g, '
'); // for multiline comments - text = text.replace(/\s/g, ' '); - html += '' + - text + ''; - if (L.type === "ERROR") - break; - } - }*/ - - // PARSER - var html; - var tree = null; - var parser = new JSParser(input); - try { - tree = parser.getSyntaxTree(); - } catch (parseError) { - var errorLexeme = parser.lexer.lastLexeme; - - html = Handlebars._escape( - input.substring(0, errorLexeme.startPos())); - html += Spark.setDataContext( - errorLexeme, - '' + - Handlebars._escape(errorLexeme.text() || '') + - ''); - html = html.replace(/(?!.)\s/g, '
'); - html += '
' + - Handlebars._escape(parseError.toString()) + '
'; - } - if (tree) { - var curPos = 0; - var unclosedInfos = []; - var toHtml = function (obj) { - if (obj instanceof ParseNode) { - var head = obj.name || ''; - var children = obj.children; - var info = { startPos: curPos }; - var isStatement = (head.indexOf('Stmnt') >= 0); - var html = Spark.setDataContext( - info, - '
' + Handlebars._escape(head) + '
' + - _.map(children, toHtml).join('') + '
'); - unclosedInfos.push(info); - return html; - } else if (obj.text) { - // token - _.each(unclosedInfos, function (info) { - info.endPos = curPos; - }); - curPos = obj.endPos(); - unclosedInfos.length = 0; - var text = obj.text(); - // insert zero-width spaces to allow wrapping - text = text.replace(/.{20}/g, "$&\n"); - text = Handlebars._escape(text); - text = text.replace(/\n/g, '​'); - return Spark.setDataContext( - obj, - '
' + text + '
'); + var outputType = Session.get("output-type"); + + if (outputType === "lex") { + // LEXER + + var lexer = new JSLexer(input); + var html = ""; + var L; + do { + L = lexer.next(); + var content; + if (L.type() === "NEWLINE") { + content = ' 
'; + } else if (L.type() === "EOF") { + content = Handlebars._escape(""); } else { - // other? - return '
' + - Handlebars._escape(JSON.stringify(obj)) + '
'; + content = Handlebars._escape(L.text() || ' '); + content = content.replace(/(?!.)\s/g, '
'); // for multiline comments + content = content.replace(/\s/g, ' '); } - }; - html = toHtml(tree); - curPos = parser.lexer.pos; - _.each(unclosedInfos, function (info) { - info.endPos = curPos; - }); - } + html += Spark.setDataContext( + L, + '' + + content + ''); + } while (! L.isError() && ! L.isEOF()); + return new Handlebars.SafeString(html); + + } else if (outputType === "parse") { + + // PARSER + var html; + var tree = null; + var parser = new JSParser(input); + try { + tree = parser.getSyntaxTree(); + } catch (parseError) { + var errorLexeme = parser.lexer.lastLexeme; + + html = Handlebars._escape( + input.substring(0, errorLexeme.startPos())); + html += Spark.setDataContext( + errorLexeme, + '' + + Handlebars._escape(errorLexeme.text() || '') + + ''); + html = html.replace(/(?!.)\s/g, '
'); + html += '
' + + Handlebars._escape(parseError.toString()) + '
'; + } + if (tree) { + var curPos = 0; + var unclosedInfos = []; + var toHtml = function (obj) { + if (obj instanceof ParseNode) { + var head = obj.name || ''; + var children = obj.children; + var info = { startPos: curPos }; + var isStatement = (head.indexOf('Stmnt') >= 0); + var html = Spark.setDataContext( + info, + '
' + Handlebars._escape(head) + '
' + + _.map(children, toHtml).join('') + '
'); + unclosedInfos.push(info); + return html; + } else if (obj.text) { + // token + _.each(unclosedInfos, function (info) { + info.endPos = curPos; + }); + curPos = obj.endPos(); + unclosedInfos.length = 0; + var text = obj.text(); + // insert zero-width spaces to allow wrapping + text = text.replace(/.{20}/g, "$&\n"); + text = Handlebars._escape(text); + text = text.replace(/\n/g, '​'); + return Spark.setDataContext( + obj, + '
' + text + '
'); + } else { + // other? + return '
' + + Handlebars._escape(JSON.stringify(obj)) + '
'; + } + }; + html = toHtml(tree); + curPos = parser.lexer.pos; + _.each(unclosedInfos, function (info) { + info.endPos = curPos; + }); + } - return new Handlebars.SafeString(html); + return new Handlebars.SafeString(html); + } + else return ''; // unknown output tab? }; Template.page.events({ @@ -125,9 +138,25 @@ if (Meteor.is_client) { 'click .parseerror': function (event) { selectInputText(this.startPos(), this.endPos()); return false; - } + }, + 'click .output-type': function (event) { + Session.set("output-type", this.value); + }, + 'click .lex': function (event) { + selectInputText(this.startPos(), this.endPos()); + return false; + }, }); + Template.page.outputTypes = [ + {name: "Lex", value: "lex"}, + {name: "Parse", value: "parse"} + ]; + + Template.page.is_outputtype_selected = function (which) { + return Session.equals("output-type", which) ? "selected" : ""; + }; + var selectTextInArea = function (e, start, end){ e.focus(); if (e.setSelectionRange) {