apl.js 6.0 KB

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