Last active
December 16, 2015 01:19
-
-
Save caisui/5354494 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
const EOF = {}; | |
function iterLine(source) { | |
source += "\n"; | |
var re = /\r\n?|\n/g; | |
var m; | |
var line = 1; | |
var offset = 0; | |
while (m = re.exec(source)) { | |
yield [line++, source.substring(offset, m.index)]; | |
offset = re.lastIndex; | |
} | |
yield [, EOF]; | |
} | |
const KEYWORD = Set([ | |
"break", | |
"delete", | |
"import", | |
"this", | |
"case", | |
"do", | |
"in", | |
"throw", | |
"catch", | |
"else", | |
"instanceof", | |
"try", | |
"class", | |
"export", | |
"let", | |
"typeof", | |
"continue", | |
"finally", | |
"new", | |
"var", | |
"const", | |
"for", | |
"return", | |
"void", | |
"debugger", | |
"function", | |
"super", | |
"while", | |
"default", | |
"if", | |
"switch", | |
"with", | |
"yield", | |
"let", | |
"of", | |
"true", | |
"false", | |
]); | |
const reWORD = let (s = `\s\x00-\x23\x25-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f`) | |
new RegExp(`([${s}]*)([^${s}]*)`, "y"); | |
function wrapKeyword(src) { | |
reWORD.lastIndex = 0; | |
res = ``; | |
while (m = reWORD.exec(src)) { | |
if (!m[0]) break; | |
if (m[1]) res += xml`${m[1]}`; | |
if (m[2]) { | |
res += KEYWORD.has(m[2]) ? xml`<span class="word">${m[2]}</span>` : xml`${m[2]}`; | |
} | |
} | |
return res; | |
} | |
function wrap(className, str) { | |
return xml`<span class=${className}>${str}</span>`; | |
} | |
function showResult(source, error) { | |
var res = ""; | |
var iter = iterLine(source); | |
var n, line, offset, i, j, c, close; | |
var re = /(\/\/|\/\*|\/[^\/]+\/|["'`])/g; | |
const CLOSE_LINE = `${"\n"}</span>`; | |
L_ROOT: while (1) { | |
[n, line] = iter.next(); | |
if (line === EOF) break; | |
res += `<span id="L${n}" line="${n}">`; | |
offset = 0; | |
L_BODY: while (1) { | |
re.lastIndex = offset; | |
m = re.exec(line); | |
if (!m) { | |
res += wrapKeyword(line.substring(offset)); | |
break; | |
} else if (m[1] === "//") { | |
res += wrapKeyword(line.substring(offset, m.index - 1)) | |
+ wrap("comment", line.substring(re.lastIndex -2)); | |
break; | |
} else if (m[1] === "/*") { | |
res += wrapKeyword(line.substring(offset, m.index - 1)); | |
offset = m.index; | |
while (1) { | |
i = line.indexOf("*/", offset); | |
if (i === -1) { | |
res += wrap("comment", line.substring(offset)); | |
} else { | |
i += 2; | |
res += wrap("comment", line.substring(offset, i)); | |
offset = i; | |
continue L_BODY; | |
} | |
res += CLOSE_LINE; | |
[n, line] = line = iter.next(); | |
if (line === EOF) break L_ROOT; | |
res += `<span id="L${n}" line="${n}">`; | |
offset = 0; | |
} | |
} else if (/^["'`]$/.test(m[1])) { | |
close = m[1]; | |
let color = close === "`" ? "bquote" : "string"; | |
res += wrapKeyword(line.substring(offset, re.lastIndex - 1)); | |
L_STR: while (1) { | |
for (c = line[i = re.lastIndex]; c; c = line[++i]) { | |
if (c === "\\") { | |
i++; | |
} else if (c === close) { | |
res += wrap(color, line.substring(re.lastIndex - 1, ++i)); | |
offset = i; | |
continue L_BODY; | |
} | |
} | |
res += wrap(color, line.substring(re.lastIndex - 1)); | |
res += CLOSE_LINE; | |
[n, line] = iter.next(); | |
if (line === EOF) break L_ROOT; | |
res += `<span id="L${n}" line="${n}">`; | |
offset = 0; | |
re.lastIndex = 0; | |
} | |
break; | |
} else { | |
res += wrapKeyword(line.substring(offset)); | |
break; | |
} | |
} | |
res += CLOSE_LINE; | |
} | |
res = | |
`<!doctype html> | |
<html> | |
<head> | |
<style> | |
[line]:before { | |
content: attr(line); | |
display: inline-block; | |
text-align: right; | |
width: 3em; | |
padding-right: .5em; | |
color: gray; | |
} | |
.word { | |
color: #00a; | |
font-weight: bold; | |
} | |
.comment { | |
color: #a00; | |
} | |
.string { | |
color: green; | |
} | |
.bquote { | |
color: orange; | |
} | |
[line] { | |
display: block; | |
} | |
[line]:hover { | |
background-color: #eee; | |
} | |
[line]:target { | |
background-color: rgba(244, 244, 255, .5); | |
width: 100%; | |
} | |
.error { | |
color: red; | |
font-weight: bold; | |
} | |
</style> | |
</head> | |
<body>${ | |
error ? let(n = error.lineNumber) | |
xml`<div class="error">${error}: <a href=${`#L${n}`}>${n}</a></div>` : `` | |
}<pre> | |
${res} | |
</pre>${ | |
// XXX:hash が 上手くいかないので | |
error ? | |
xml`<script> | |
location.hash = "#L${error.lineNumber}"; | |
</script>` : "" | |
}</html>`; | |
// hash が うまくいかない | |
var url = URL.createObjectURL(new content.window.Blob([res], {type:"text/html"})); | |
//if (error.lineNumber) { | |
// url += `#L${error.lineNumber}`; | |
//} | |
liberator.open(url); | |
} | |
commands.addUserCommand(["checkAndSource", "cas"], "file's syntax check. and execute", | |
function (args) { | |
var obj = {}; | |
try { | |
Cu.import("resource://liberator/template.js", obj); | |
Cu.import("resource://gre/modules/reflect.jsm", obj); | |
var src = obj.convert(File(args[0]).read()); | |
try { | |
obj.Reflect.parse(src); | |
if (args.bang) { | |
showResult(src); | |
} | |
liberator.echomsg(`validated: ${args[0]}`); | |
if (!args["--check-only"]) { | |
io.source(args[0]); | |
} | |
} catch (ex) { | |
showResult(src, ex); | |
liberator.echoerr(ex, null, `${args[0]}:${ex.lineNumber}: `); | |
} | |
} catch (ex) { | |
Cu.reportError(ex); | |
liberator.echoerr(ex); | |
} | |
}, { | |
bang: true, | |
literal: 0, | |
argCount: 1, | |
completer: function (context) { completion.file(context, true); }, | |
options: [ | |
[["--check-only", "-c"], commands.OPTION_NOARG], | |
], | |
}, true); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment