elm.js
205 lines
| 5.4 KiB
| application/javascript
|
JavascriptLexer
r1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others | |||
// Distributed under an MIT license: http://codemirror.net/LICENSE | ||||
(function(mod) { | ||||
if (typeof exports == "object" && typeof module == "object") // CommonJS | ||||
mod(require("../../lib/codemirror")); | ||||
else if (typeof define == "function" && define.amd) // AMD | ||||
define(["../../lib/codemirror"], mod); | ||||
else // Plain browser env | ||||
mod(CodeMirror); | ||||
})(function(CodeMirror) { | ||||
"use strict"; | ||||
CodeMirror.defineMode("elm", function() { | ||||
function switchState(source, setState, f) { | ||||
setState(f); | ||||
return f(source, setState); | ||||
} | ||||
// These should all be Unicode extended, as per the Haskell 2010 report | ||||
var smallRE = /[a-z_]/; | ||||
var largeRE = /[A-Z]/; | ||||
var digitRE = /[0-9]/; | ||||
var hexitRE = /[0-9A-Fa-f]/; | ||||
var octitRE = /[0-7]/; | ||||
var idRE = /[a-z_A-Z0-9\']/; | ||||
var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:\u03BB\u2192]/; | ||||
var specialRE = /[(),;[\]`{}]/; | ||||
var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer | ||||
function normal() { | ||||
return function (source, setState) { | ||||
if (source.eatWhile(whiteCharRE)) { | ||||
return null; | ||||
} | ||||
var ch = source.next(); | ||||
if (specialRE.test(ch)) { | ||||
if (ch == '{' && source.eat('-')) { | ||||
var t = "comment"; | ||||
if (source.eat('#')) t = "meta"; | ||||
return switchState(source, setState, ncomment(t, 1)); | ||||
} | ||||
return null; | ||||
} | ||||
if (ch == '\'') { | ||||
if (source.eat('\\')) | ||||
source.next(); // should handle other escapes here | ||||
else | ||||
source.next(); | ||||
if (source.eat('\'')) | ||||
return "string"; | ||||
return "error"; | ||||
} | ||||
if (ch == '"') { | ||||
return switchState(source, setState, stringLiteral); | ||||
} | ||||
if (largeRE.test(ch)) { | ||||
source.eatWhile(idRE); | ||||
if (source.eat('.')) | ||||
return "qualifier"; | ||||
return "variable-2"; | ||||
} | ||||
if (smallRE.test(ch)) { | ||||
var isDef = source.pos === 1; | ||||
source.eatWhile(idRE); | ||||
return isDef ? "variable-3" : "variable"; | ||||
} | ||||
if (digitRE.test(ch)) { | ||||
if (ch == '0') { | ||||
if (source.eat(/[xX]/)) { | ||||
source.eatWhile(hexitRE); // should require at least 1 | ||||
return "integer"; | ||||
} | ||||
if (source.eat(/[oO]/)) { | ||||
source.eatWhile(octitRE); // should require at least 1 | ||||
return "number"; | ||||
} | ||||
} | ||||
source.eatWhile(digitRE); | ||||
var t = "number"; | ||||
if (source.eat('.')) { | ||||
t = "number"; | ||||
source.eatWhile(digitRE); // should require at least 1 | ||||
} | ||||
if (source.eat(/[eE]/)) { | ||||
t = "number"; | ||||
source.eat(/[-+]/); | ||||
source.eatWhile(digitRE); // should require at least 1 | ||||
} | ||||
return t; | ||||
} | ||||
if (symbolRE.test(ch)) { | ||||
if (ch == '-' && source.eat(/-/)) { | ||||
source.eatWhile(/-/); | ||||
if (!source.eat(symbolRE)) { | ||||
source.skipToEnd(); | ||||
return "comment"; | ||||
} | ||||
} | ||||
source.eatWhile(symbolRE); | ||||
return "builtin"; | ||||
} | ||||
return "error"; | ||||
} | ||||
} | ||||
function ncomment(type, nest) { | ||||
if (nest == 0) { | ||||
return normal(); | ||||
} | ||||
return function(source, setState) { | ||||
var currNest = nest; | ||||
while (!source.eol()) { | ||||
var ch = source.next(); | ||||
if (ch == '{' && source.eat('-')) { | ||||
++currNest; | ||||
} else if (ch == '-' && source.eat('}')) { | ||||
--currNest; | ||||
if (currNest == 0) { | ||||
setState(normal()); | ||||
return type; | ||||
} | ||||
} | ||||
} | ||||
setState(ncomment(type, currNest)); | ||||
return type; | ||||
} | ||||
} | ||||
function stringLiteral(source, setState) { | ||||
while (!source.eol()) { | ||||
var ch = source.next(); | ||||
if (ch == '"') { | ||||
setState(normal()); | ||||
return "string"; | ||||
} | ||||
if (ch == '\\') { | ||||
if (source.eol() || source.eat(whiteCharRE)) { | ||||
setState(stringGap); | ||||
return "string"; | ||||
} | ||||
if (!source.eat('&')) source.next(); // should handle other escapes here | ||||
} | ||||
} | ||||
setState(normal()); | ||||
return "error"; | ||||
} | ||||
function stringGap(source, setState) { | ||||
if (source.eat('\\')) { | ||||
return switchState(source, setState, stringLiteral); | ||||
} | ||||
source.next(); | ||||
setState(normal()); | ||||
return "error"; | ||||
} | ||||
var wellKnownWords = (function() { | ||||
var wkw = {}; | ||||
var keywords = [ | ||||
"case", "of", "as", | ||||
"if", "then", "else", | ||||
"let", "in", | ||||
"infix", "infixl", "infixr", | ||||
"type", "alias", | ||||
"input", "output", "foreign", "loopback", | ||||
"module", "where", "import", "exposing", | ||||
"_", "..", "|", ":", "=", "\\", "\"", "->", "<-" | ||||
]; | ||||
for (var i = keywords.length; i--;) | ||||
wkw[keywords[i]] = "keyword"; | ||||
return wkw; | ||||
})(); | ||||
return { | ||||
startState: function () { return { f: normal() }; }, | ||||
copyState: function (s) { return { f: s.f }; }, | ||||
token: function(stream, state) { | ||||
var t = state.f(stream, function(s) { state.f = s; }); | ||||
var w = stream.current(); | ||||
return (wellKnownWords.hasOwnProperty(w)) ? wellKnownWords[w] : t; | ||||
} | ||||
}; | ||||
}); | ||||
CodeMirror.defineMIME("text/x-elm", "elm"); | ||||
r346 | }); | |||