|
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/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("oz", function (conf) {
function wordRegexp(words) { return new RegExp("^((" + words.join(")|(") + "))\\b"); }
var singleOperators = /[\^@!\|<>#~\.\*\-\+\\/,=]/; var doubleOperators = /(<-)|(:=)|(=<)|(>=)|(<=)|(<:)|(>:)|(=:)|(\\=)|(\\=:)|(!!)|(==)|(::)/; var tripleOperators = /(:::)|(\.\.\.)|(=<:)|(>=:)/;
var middle = ["in", "then", "else", "of", "elseof", "elsecase", "elseif", "catch", "finally", "with", "require", "prepare", "import", "export", "define", "do"]; var end = ["end"];
var atoms = wordRegexp(["true", "false", "nil", "unit"]); var commonKeywords = wordRegexp(["andthen", "at", "attr", "declare", "feat", "from", "lex", "mod", "div", "mode", "orelse", "parser", "prod", "prop", "scanner", "self", "syn", "token"]); var openingKeywords = wordRegexp(["local", "proc", "fun", "case", "class", "if", "cond", "or", "dis", "choice", "not", "thread", "try", "raise", "lock", "for", "suchthat", "meth", "functor"]); var middleKeywords = wordRegexp(middle); var endKeywords = wordRegexp(end);
// Tokenizers
function tokenBase(stream, state) { if (stream.eatSpace()) { return null; }
// Brackets
if(stream.match(/[{}]/)) { return "bracket"; }
// Special [] keyword
if (stream.match('[]')) { return "keyword" }
// Operators
if (stream.match(tripleOperators) || stream.match(doubleOperators)) { return "operator"; }
// Atoms
if(stream.match(atoms)) { return 'atom'; }
// Opening keywords
var matched = stream.match(openingKeywords); if (matched) { if (!state.doInCurrentLine) state.currentIndent++; else state.doInCurrentLine = false;
// Special matching for signatures
if(matched[0] == "proc" || matched[0] == "fun") state.tokenize = tokenFunProc; else if(matched[0] == "class") state.tokenize = tokenClass; else if(matched[0] == "meth") state.tokenize = tokenMeth;
return 'keyword'; }
// Middle and other keywords
if (stream.match(middleKeywords) || stream.match(commonKeywords)) { return "keyword" }
// End keywords
if (stream.match(endKeywords)) { state.currentIndent--; return 'keyword'; }
// Eat the next char for next comparisons
var ch = stream.next();
// Strings
if (ch == '"' || ch == "'") { state.tokenize = tokenString(ch); return state.tokenize(stream, state); }
// Numbers
if (/[~\d]/.test(ch)) { if (ch == "~") { if(! /^[0-9]/.test(stream.peek())) return null; else if (( stream.next() == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) || stream.match(/^[0-9]*(\.[0-9]+)?([eE][~+]?[0-9]+)?/)) return "number"; }
if ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) || stream.match(/^[0-9]*(\.[0-9]+)?([eE][~+]?[0-9]+)?/)) return "number";
return null; }
// Comments
if (ch == "%") { stream.skipToEnd(); return 'comment'; } else if (ch == "/") { if (stream.eat("*")) { state.tokenize = tokenComment; return tokenComment(stream, state); } }
// Single operators
if(singleOperators.test(ch)) { return "operator"; }
// If nothing match, we skip the entire alphanumeric block
stream.eatWhile(/\w/);
return "variable"; }
function tokenClass(stream, state) { if (stream.eatSpace()) { return null; } stream.match(/([A-Z][A-Za-z0-9_]*)|(`.+`)/); state.tokenize = tokenBase; return "variable-3" }
function tokenMeth(stream, state) { if (stream.eatSpace()) { return null; } stream.match(/([a-zA-Z][A-Za-z0-9_]*)|(`.+`)/); state.tokenize = tokenBase; return "def" }
function tokenFunProc(stream, state) { if (stream.eatSpace()) { return null; }
if(!state.hasPassedFirstStage && stream.eat("{")) { state.hasPassedFirstStage = true; return "bracket"; } else if(state.hasPassedFirstStage) { stream.match(/([A-Z][A-Za-z0-9_]*)|(`.+`)|\$/); state.hasPassedFirstStage = false; state.tokenize = tokenBase; return "def" } else { state.tokenize = tokenBase; return null; } }
function tokenComment(stream, state) { var maybeEnd = false, ch; while (ch = stream.next()) { if (ch == "/" && maybeEnd) { state.tokenize = tokenBase; break; } maybeEnd = (ch == "*"); } return "comment"; }
function tokenString(quote) { return function (stream, state) { var escaped = false, next, end = false; while ((next = stream.next()) != null) { if (next == quote && !escaped) { end = true; break; } escaped = !escaped && next == "\\"; } if (end || !escaped) state.tokenize = tokenBase; return "string"; }; }
function buildElectricInputRegEx() { // Reindentation should occur on [] or on a match of any of
// the block closing keywords, at the end of a line.
var allClosings = middle.concat(end); return new RegExp("[\\[\\]]|(" + allClosings.join("|") + ")$"); }
return {
startState: function () { return { tokenize: tokenBase, currentIndent: 0, doInCurrentLine: false, hasPassedFirstStage: false }; },
token: function (stream, state) { if (stream.sol()) state.doInCurrentLine = 0;
return state.tokenize(stream, state); },
indent: function (state, textAfter) { var trueText = textAfter.replace(/^\s+|\s+$/g, '');
if (trueText.match(endKeywords) || trueText.match(middleKeywords) || trueText.match(/(\[])/)) return conf.indentUnit * (state.currentIndent - 1);
if (state.currentIndent < 0) return 0;
return state.currentIndent * conf.indentUnit; }, fold: "indent", electricInput: buildElectricInputRegEx(), lineComment: "%", blockCommentStart: "/*", blockCommentEnd: "*/" }; });
CodeMirror.defineMIME("text/x-oz", "oz");
});
|