mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
jsparse demo improvements (lexer tab)
This commit is contained in:
@@ -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; }
|
||||
|
||||
@@ -22,6 +22,11 @@ whitespace is significant here; browser swallows initial
|
||||
}}<textarea id="inputtextarea">
|
||||
{{input}}</textarea>
|
||||
</div>
|
||||
<div id="outputoptions">
|
||||
{{#each outputTypes}}
|
||||
<ins class="output-type {{is_outputtype_selected value}}">{{name}}</ins>
|
||||
{{/each}}
|
||||
</div>
|
||||
<div id="output">
|
||||
{{output}}
|
||||
</div>
|
||||
|
||||
@@ -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 += '<br>';
|
||||
} else {
|
||||
var text = Handlebars._escape(L.text || ' ');
|
||||
text = text.replace(/(?!.)\s/g, '<br>'); // for multiline comments
|
||||
text = text.replace(/\s/g, ' ');
|
||||
html += '<span class="lex lex_' + L.type.toLowerCase() + '">' +
|
||||
text + '</span>';
|
||||
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,
|
||||
'<span class="parseerror">' +
|
||||
Handlebars._escape(errorLexeme.text() || '<EOF>') +
|
||||
'</span>');
|
||||
html = html.replace(/(?!.)\s/g, '<br>');
|
||||
html += '<div class="parseerrormessage">' +
|
||||
Handlebars._escape(parseError.toString()) + '</div>';
|
||||
}
|
||||
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,
|
||||
'<div class="box named' + (isStatement ? ' statement' : '') +
|
||||
'"><div class="box head">' + Handlebars._escape(head) + '</div>' +
|
||||
_.map(children, toHtml).join('') + '</div>');
|
||||
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,
|
||||
'<div class="box token">' + text + '</div>');
|
||||
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 = ' <br>';
|
||||
} else if (L.type() === "EOF") {
|
||||
content = Handlebars._escape("<EOF>");
|
||||
} else {
|
||||
// other?
|
||||
return '<div class="box other">' +
|
||||
Handlebars._escape(JSON.stringify(obj)) + '</div>';
|
||||
content = Handlebars._escape(L.text() || ' ');
|
||||
content = content.replace(/(?!.)\s/g, '<br>'); // 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,
|
||||
'<span class="lex lex_' + L.type().toLowerCase() + '" ' +
|
||||
'title="' + Handlebars._escape(L.type()) + '">' +
|
||||
content + '</span>');
|
||||
} 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,
|
||||
'<span class="parseerror">' +
|
||||
Handlebars._escape(errorLexeme.text() || '<EOF>') +
|
||||
'</span>');
|
||||
html = html.replace(/(?!.)\s/g, '<br>');
|
||||
html += '<div class="parseerrormessage">' +
|
||||
Handlebars._escape(parseError.toString()) + '</div>';
|
||||
}
|
||||
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,
|
||||
'<div class="box named' + (isStatement ? ' statement' : '') +
|
||||
'"><div class="box head">' + Handlebars._escape(head) + '</div>' +
|
||||
_.map(children, toHtml).join('') + '</div>');
|
||||
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,
|
||||
'<div class="box token">' + text + '</div>');
|
||||
} else {
|
||||
// other?
|
||||
return '<div class="box other">' +
|
||||
Handlebars._escape(JSON.stringify(obj)) + '</div>';
|
||||
}
|
||||
};
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user