2016-07-23 13:29:20 +08:00
|
|
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
2019-10-15 16:40:42 +08:00
|
|
|
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
2016-07-23 13:29:20 +08:00
|
|
|
|
|
|
|
(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);
|
2019-10-15 16:40:42 +08:00
|
|
|
return isDef ? "type" : "variable";
|
2016-07-23 13:29:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
|
|
|
});
|