all repos — NoPaste @ 29b774f090102303e43cf939b38ac2083e62d9f1

Resurrected - The PussTheCat.org fork of NoPaste

scripts/CodeMirror/mode/oz/oz.js (view raw)

  1// CodeMirror, copyright (c) by Marijn Haverbeke and others
  2// Distributed under an MIT license: https://codemirror.net/LICENSE
  3
  4(function(mod) {
  5  if (typeof exports == "object" && typeof module == "object") // CommonJS
  6    mod(require("../../lib/codemirror"));
  7  else if (typeof define == "function" && define.amd) // AMD
  8    define(["../../lib/codemirror"], mod);
  9  else // Plain browser env
 10    mod(CodeMirror);
 11})(function(CodeMirror) {
 12"use strict";
 13
 14CodeMirror.defineMode("oz", function (conf) {
 15
 16  function wordRegexp(words) {
 17    return new RegExp("^((" + words.join(")|(") + "))\\b");
 18  }
 19
 20  var singleOperators = /[\^@!\|<>#~\.\*\-\+\\/,=]/;
 21  var doubleOperators = /(<-)|(:=)|(=<)|(>=)|(<=)|(<:)|(>:)|(=:)|(\\=)|(\\=:)|(!!)|(==)|(::)/;
 22  var tripleOperators = /(:::)|(\.\.\.)|(=<:)|(>=:)/;
 23
 24  var middle = ["in", "then", "else", "of", "elseof", "elsecase", "elseif", "catch",
 25    "finally", "with", "require", "prepare", "import", "export", "define", "do"];
 26  var end = ["end"];
 27
 28  var atoms = wordRegexp(["true", "false", "nil", "unit"]);
 29  var commonKeywords = wordRegexp(["andthen", "at", "attr", "declare", "feat", "from", "lex",
 30    "mod", "div", "mode", "orelse", "parser", "prod", "prop", "scanner", "self", "syn", "token"]);
 31  var openingKeywords = wordRegexp(["local", "proc", "fun", "case", "class", "if", "cond", "or", "dis",
 32    "choice", "not", "thread", "try", "raise", "lock", "for", "suchthat", "meth", "functor"]);
 33  var middleKeywords = wordRegexp(middle);
 34  var endKeywords = wordRegexp(end);
 35
 36  // Tokenizers
 37  function tokenBase(stream, state) {
 38    if (stream.eatSpace()) {
 39      return null;
 40    }
 41
 42    // Brackets
 43    if(stream.match(/[{}]/)) {
 44      return "bracket";
 45    }
 46
 47    // Special [] keyword
 48    if (stream.match(/(\[])/)) {
 49        return "keyword"
 50    }
 51
 52    // Operators
 53    if (stream.match(tripleOperators) || stream.match(doubleOperators)) {
 54      return "operator";
 55    }
 56
 57    // Atoms
 58    if(stream.match(atoms)) {
 59      return 'atom';
 60    }
 61
 62    // Opening keywords
 63    var matched = stream.match(openingKeywords);
 64    if (matched) {
 65      if (!state.doInCurrentLine)
 66        state.currentIndent++;
 67      else
 68        state.doInCurrentLine = false;
 69
 70      // Special matching for signatures
 71      if(matched[0] == "proc" || matched[0] == "fun")
 72        state.tokenize = tokenFunProc;
 73      else if(matched[0] == "class")
 74        state.tokenize = tokenClass;
 75      else if(matched[0] == "meth")
 76        state.tokenize = tokenMeth;
 77
 78      return 'keyword';
 79    }
 80
 81    // Middle and other keywords
 82    if (stream.match(middleKeywords) || stream.match(commonKeywords)) {
 83      return "keyword"
 84    }
 85
 86    // End keywords
 87    if (stream.match(endKeywords)) {
 88      state.currentIndent--;
 89      return 'keyword';
 90    }
 91
 92    // Eat the next char for next comparisons
 93    var ch = stream.next();
 94
 95    // Strings
 96    if (ch == '"' || ch == "'") {
 97      state.tokenize = tokenString(ch);
 98      return state.tokenize(stream, state);
 99    }
100
101    // Numbers
102    if (/[~\d]/.test(ch)) {
103      if (ch == "~") {
104        if(! /^[0-9]/.test(stream.peek()))
105          return null;
106        else if (( stream.next() == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) || stream.match(/^[0-9]*(\.[0-9]+)?([eE][~+]?[0-9]+)?/))
107          return "number";
108      }
109
110      if ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) || stream.match(/^[0-9]*(\.[0-9]+)?([eE][~+]?[0-9]+)?/))
111        return "number";
112
113      return null;
114    }
115
116    // Comments
117    if (ch == "%") {
118      stream.skipToEnd();
119      return 'comment';
120    }
121    else if (ch == "/") {
122      if (stream.eat("*")) {
123        state.tokenize = tokenComment;
124        return tokenComment(stream, state);
125      }
126    }
127
128    // Single operators
129    if(singleOperators.test(ch)) {
130      return "operator";
131    }
132
133    // If nothing match, we skip the entire alphanumerical block
134    stream.eatWhile(/\w/);
135
136    return "variable";
137  }
138
139  function tokenClass(stream, state) {
140    if (stream.eatSpace()) {
141      return null;
142    }
143    stream.match(/([A-Z][A-Za-z0-9_]*)|(`.+`)/);
144    state.tokenize = tokenBase;
145    return "variable-3"
146  }
147
148  function tokenMeth(stream, state) {
149    if (stream.eatSpace()) {
150      return null;
151    }
152    stream.match(/([a-zA-Z][A-Za-z0-9_]*)|(`.+`)/);
153    state.tokenize = tokenBase;
154    return "def"
155  }
156
157  function tokenFunProc(stream, state) {
158    if (stream.eatSpace()) {
159      return null;
160    }
161
162    if(!state.hasPassedFirstStage && stream.eat("{")) {
163      state.hasPassedFirstStage = true;
164      return "bracket";
165    }
166    else if(state.hasPassedFirstStage) {
167      stream.match(/([A-Z][A-Za-z0-9_]*)|(`.+`)|\$/);
168      state.hasPassedFirstStage = false;
169      state.tokenize = tokenBase;
170      return "def"
171    }
172    else {
173      state.tokenize = tokenBase;
174      return null;
175    }
176  }
177
178  function tokenComment(stream, state) {
179    var maybeEnd = false, ch;
180    while (ch = stream.next()) {
181      if (ch == "/" && maybeEnd) {
182        state.tokenize = tokenBase;
183        break;
184      }
185      maybeEnd = (ch == "*");
186    }
187    return "comment";
188  }
189
190  function tokenString(quote) {
191    return function (stream, state) {
192      var escaped = false, next, end = false;
193      while ((next = stream.next()) != null) {
194        if (next == quote && !escaped) {
195          end = true;
196          break;
197        }
198        escaped = !escaped && next == "\\";
199      }
200      if (end || !escaped)
201        state.tokenize = tokenBase;
202      return "string";
203    };
204  }
205
206  function buildElectricInputRegEx() {
207    // Reindentation should occur on [] or on a match of any of
208    // the block closing keywords, at the end of a line.
209    var allClosings = middle.concat(end);
210    return new RegExp("[\\[\\]]|(" + allClosings.join("|") + ")$");
211  }
212
213  return {
214
215    startState: function () {
216      return {
217        tokenize: tokenBase,
218        currentIndent: 0,
219        doInCurrentLine: false,
220        hasPassedFirstStage: false
221      };
222    },
223
224    token: function (stream, state) {
225      if (stream.sol())
226        state.doInCurrentLine = 0;
227
228      return state.tokenize(stream, state);
229    },
230
231    indent: function (state, textAfter) {
232      var trueText = textAfter.replace(/^\s+|\s+$/g, '');
233
234      if (trueText.match(endKeywords) || trueText.match(middleKeywords) || trueText.match(/(\[])/))
235        return conf.indentUnit * (state.currentIndent - 1);
236
237      if (state.currentIndent < 0)
238        return 0;
239
240      return state.currentIndent * conf.indentUnit;
241    },
242    fold: "indent",
243    electricInput: buildElectricInputRegEx(),
244    lineComment: "%",
245    blockCommentStart: "/*",
246    blockCommentEnd: "*/"
247  };
248});
249
250CodeMirror.defineMIME("text/x-oz", "oz");
251
252});