text: // 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("apl", function () {
          var builtInOps = {
              ".": "innerProduct",
              "\\": "scan",
              "/": "reduce",
              "⌿": "reduce1Axis",
              "⍀": "scan1Axis",
              "¨": "each",
              "⍣": "power"
          };
          var builtInFuncs = {
              "+": ["conjugate", "add"],
              "−": ["negate", "subtract"],
              "×": ["signOf", "multiply"],
              "÷": ["reciprocal", "divide"],
              "⌈": ["ceiling", "greaterOf"],
              "⌊": ["floor", "lesserOf"],
              "∣": ["absolute", "residue"],
              "⍳": ["indexGenerate", "indexOf"],
              "?": ["roll", "deal"],
              "⋆": ["exponentiate", "toThePowerOf"],
              "⍟": ["naturalLog", "logToTheBase"],
              "○": ["piTimes", "circularFuncs"],
              "!": ["factorial", "binomial"],
              "⌹": ["matrixInverse", "matrixDivide"],
              "<": [null, "lessThan"],
              "≤": [null, "lessThanOrEqual"],
              "=": [null, "equals"],
              ">": [null, "greaterThan"],
              "≥": [null, "greaterThanOrEqual"],
              "≠": [null, "notEqual"],
              "≡": ["depth", "match"],
              "≢": [null, "notMatch"],
              "∈": ["enlist", "membership"],
              "⍷": [null, "find"],
              "∪": ["unique", "union"],
              "∩": [null, "intersection"],
              "∼": ["not", "without"],
              "∨": [null, "or"],
              "∧": [null, "and"],
              "⍱": [null, "nor"],
              "⍲": [null, "nand"],
              "⍴": ["shapeOf", "reshape"],
              ",": ["ravel", "catenate"],
              "⍪": [null, "firstAxisCatenate"],
              "⌽": ["reverse", "rotate"],
              "⊖": ["axis1Reverse", "axis1Rotate"],
              "⍉": ["transpose", null],
              "↑": ["first", "take"],
              "↓": [null, "drop"],
              "⊂": ["enclose", "partitionWithAxis"],
              "⊃": ["diclose", "pick"],
              "⌷": [null, "index"],
              "⍋": ["gradeUp", null],
              "⍒": ["gradeDown", null],
              "⊤": ["encode", null],
              "⊥": ["decode", null],
              "⍕": ["format", "formatByExample"],
              "⍎": ["execute", null],
              "⊣": ["stop", "left"],
              "⊢": ["pass", "right"]
          };
  
          var isOperator = /[\.\/⌿⍀¨⍣]/;
          var isNiladic = /⍬/;
          var isFunction = /[\+−×÷⌈⌊∣⍳\?⋆⍟○!⌹<≤=>≥≠≡≢∈⍷∪∩∼∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⌷⍋⍒⊤⊥⍕⍎⊣⊢]/;
          var isArrow = /←/;
          var isComment = /[⍝#].*$/;
  
          var stringEater = function (type) {
              var prev;
              prev = false;
              return function (c) {
                  prev = c;
                  if (c === type) {
                      return prev === "\\";
                  }
                  return true;
              };
          };
          return {
              startState: function () {
                  return {
                      prev: false,
                      func: false,
                      op: false,
                      string: false,
                      escape: false
                  };
              },
              token: function (stream, state) {
                  var ch, funcName;
                  if (stream.eatSpace()) {
                      return null;
                  }
                  ch = stream.next();
                  if (ch === '"' || ch === "'") {
                      stream.eatWhile(stringEater(ch));
                      stream.next();
                      state.prev = true;
                      return "string";
                  }
                  if (/[\[{\(]/.test(ch)) {
                      state.prev = false;
                      return null;
                  }
                  if (/[\]}\)]/.test(ch)) {
                      state.prev = true;
                      return null;
                  }
                  if (isNiladic.test(ch)) {
                      state.prev = false;
                      return "niladic";
                  }
                  if (/[¯\d]/.test(ch)) {
                      if (state.func) {
                          state.func = false;
                          state.prev = false;
                      } else {
                          state.prev = true;
                      }
                      stream.eatWhile(/[\w\.]/);
                      return "number";
                  }
                  if (isOperator.test(ch)) {
                      return "operator apl-" + builtInOps[ch];
                  }
                  if (isArrow.test(ch)) {
                      return "apl-arrow";
                  }
                  if (isFunction.test(ch)) {
                      funcName = "apl-";
                      if (builtInFuncs[ch] != null) {
                          if (state.prev) {
                              funcName += builtInFuncs[ch][1];
                          } else {
                              funcName += builtInFuncs[ch][0];
                          }
                      }
                      state.func = true;
                      state.prev = false;
                      return "function " + funcName;
                  }
                  if (isComment.test(ch)) {
                      stream.skipToEnd();
                      return "comment";
                  }
                  if (ch === "∘" && stream.peek() === ".") {
                      stream.next();
                      return "function jot-dot";
                  }
                  stream.eatWhile(/[\w\$_]/);
                  state.prev = true;
                  return "keyword";
              }
          };
      });
  
      CodeMirror.defineMIME("text/apl", "apl");
  
  });
  