apl.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. (function(mod) {
  2. if (typeof exports == "object" && typeof module == "object") // CommonJS
  3. mod(require("../../lib/codemirror"));
  4. else if (typeof define == "function" && define.amd) // AMD
  5. define(["../../lib/codemirror"], mod);
  6. else // Plain browser env
  7. mod(CodeMirror);
  8. })(function(CodeMirror) {
  9. "use strict";
  10. CodeMirror.defineMode("apl", function() {
  11. var builtInOps = {
  12. ".": "innerProduct",
  13. "\\": "scan",
  14. "/": "reduce",
  15. "⌿": "reduce1Axis",
  16. "⍀": "scan1Axis",
  17. "¨": "each",
  18. "⍣": "power"
  19. };
  20. var builtInFuncs = {
  21. "+": ["conjugate", "add"],
  22. "−": ["negate", "subtract"],
  23. "×": ["signOf", "multiply"],
  24. "÷": ["reciprocal", "divide"],
  25. "⌈": ["ceiling", "greaterOf"],
  26. "⌊": ["floor", "lesserOf"],
  27. "∣": ["absolute", "residue"],
  28. "⍳": ["indexGenerate", "indexOf"],
  29. "?": ["roll", "deal"],
  30. "⋆": ["exponentiate", "toThePowerOf"],
  31. "⍟": ["naturalLog", "logToTheBase"],
  32. "○": ["piTimes", "circularFuncs"],
  33. "!": ["factorial", "binomial"],
  34. "⌹": ["matrixInverse", "matrixDivide"],
  35. "<": [null, "lessThan"],
  36. "≤": [null, "lessThanOrEqual"],
  37. "=": [null, "equals"],
  38. ">": [null, "greaterThan"],
  39. "≥": [null, "greaterThanOrEqual"],
  40. "≠": [null, "notEqual"],
  41. "≡": ["depth", "match"],
  42. "≢": [null, "notMatch"],
  43. "∈": ["enlist", "membership"],
  44. "⍷": [null, "find"],
  45. "∪": ["unique", "union"],
  46. "∩": [null, "intersection"],
  47. "∼": ["not", "without"],
  48. "∨": [null, "or"],
  49. "∧": [null, "and"],
  50. "⍱": [null, "nor"],
  51. "⍲": [null, "nand"],
  52. "⍴": ["shapeOf", "reshape"],
  53. ",": ["ravel", "catenate"],
  54. "⍪": [null, "firstAxisCatenate"],
  55. "⌽": ["reverse", "rotate"],
  56. "⊖": ["axis1Reverse", "axis1Rotate"],
  57. "⍉": ["transpose", null],
  58. "↑": ["first", "take"],
  59. "↓": [null, "drop"],
  60. "⊂": ["enclose", "partitionWithAxis"],
  61. "⊃": ["diclose", "pick"],
  62. "⌷": [null, "index"],
  63. "⍋": ["gradeUp", null],
  64. "⍒": ["gradeDown", null],
  65. "⊤": ["encode", null],
  66. "⊥": ["decode", null],
  67. "⍕": ["format", "formatByExample"],
  68. "⍎": ["execute", null],
  69. "⊣": ["stop", "left"],
  70. "⊢": ["pass", "right"]
  71. };
  72. var isOperator = /[\.\/⌿⍀¨⍣]/;
  73. var isNiladic = /⍬/;
  74. var isFunction = /[\+−×÷⌈⌊∣⍳\?⋆⍟○!⌹<≤=>≥≠≡≢∈⍷∪∩∼∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⌷⍋⍒⊤⊥⍕⍎⊣⊢]/;
  75. var isArrow = /←/;
  76. var isComment = /[⍝#].*$/;
  77. var stringEater = function(type) {
  78. var prev;
  79. prev = false;
  80. return function(c) {
  81. prev = c;
  82. if (c === type) {
  83. return prev === "\\";
  84. }
  85. return true;
  86. };
  87. };
  88. return {
  89. startState: function() {
  90. return {
  91. prev: false,
  92. func: false,
  93. op: false,
  94. string: false,
  95. escape: false
  96. };
  97. },
  98. token: function(stream, state) {
  99. var ch, funcName, word;
  100. if (stream.eatSpace()) {
  101. return null;
  102. }
  103. ch = stream.next();
  104. if (ch === '"' || ch === "'") {
  105. stream.eatWhile(stringEater(ch));
  106. stream.next();
  107. state.prev = true;
  108. return "string";
  109. }
  110. if (/[\[{\(]/.test(ch)) {
  111. state.prev = false;
  112. return null;
  113. }
  114. if (/[\]}\)]/.test(ch)) {
  115. state.prev = true;
  116. return null;
  117. }
  118. if (isNiladic.test(ch)) {
  119. state.prev = false;
  120. return "niladic";
  121. }
  122. if (/[¯\d]/.test(ch)) {
  123. if (state.func) {
  124. state.func = false;
  125. state.prev = false;
  126. } else {
  127. state.prev = true;
  128. }
  129. stream.eatWhile(/[\w\.]/);
  130. return "number";
  131. }
  132. if (isOperator.test(ch)) {
  133. return "operator apl-" + builtInOps[ch];
  134. }
  135. if (isArrow.test(ch)) {
  136. return "apl-arrow";
  137. }
  138. if (isFunction.test(ch)) {
  139. funcName = "apl-";
  140. if (builtInFuncs[ch] != null) {
  141. if (state.prev) {
  142. funcName += builtInFuncs[ch][1];
  143. } else {
  144. funcName += builtInFuncs[ch][0];
  145. }
  146. }
  147. state.func = true;
  148. state.prev = false;
  149. return "function " + funcName;
  150. }
  151. if (isComment.test(ch)) {
  152. stream.skipToEnd();
  153. return "comment";
  154. }
  155. if (ch === "∘" && stream.peek() === ".") {
  156. stream.next();
  157. return "function jot-dot";
  158. }
  159. stream.eatWhile(/[\w\$_]/);
  160. word = stream.current();
  161. state.prev = true;
  162. return "keyword";
  163. }
  164. };
  165. });
  166. CodeMirror.defineMIME("text/apl", "apl");
  167. });