github.com/jancarloviray/community@v0.41.1-0.20170124221257-33a66c87cf2f/app/public/codemirror/mode/oz/oz.js (about)

     1  // CodeMirror, copyright (c) by Marijn Haverbeke and others
     2  // Distributed under an MIT license: http://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  
    14  CodeMirror.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", "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  
   250  CodeMirror.defineMIME("text/x-oz", "oz");
   251  
   252  });