mumps.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. /*
  4. This MUMPS Language script was constructed using vbscript.js as a template.
  5. */
  6. ;(function (mod) {
  7. if (typeof exports == 'object' && typeof module == 'object')
  8. // CommonJS
  9. mod(require('../../lib/codemirror'))
  10. else if (typeof define == 'function' && define.amd)
  11. // AMD
  12. define(['../../lib/codemirror'], mod)
  13. // Plain browser env
  14. else mod(CodeMirror)
  15. })(function (CodeMirror) {
  16. 'use strict'
  17. CodeMirror.defineMode('mumps', function () {
  18. function wordRegexp(words) {
  19. return new RegExp('^((' + words.join(')|(') + '))\\b', 'i')
  20. }
  21. var singleOperators = new RegExp("^[\\+\\-\\*/&#!_?\\\\<>=\\'\\[\\]]")
  22. var doubleOperators = new RegExp("^(('=)|(<=)|(>=)|('>)|('<)|([[)|(]])|(^$))")
  23. var singleDelimiters = new RegExp('^[\\.,:]')
  24. var brackets = new RegExp('[()]')
  25. var identifiers = new RegExp('^[%A-Za-z][A-Za-z0-9]*')
  26. var commandKeywords = [
  27. 'break',
  28. 'close',
  29. 'do',
  30. 'else',
  31. 'for',
  32. 'goto',
  33. 'halt',
  34. 'hang',
  35. 'if',
  36. 'job',
  37. 'kill',
  38. 'lock',
  39. 'merge',
  40. 'new',
  41. 'open',
  42. 'quit',
  43. 'read',
  44. 'set',
  45. 'tcommit',
  46. 'trollback',
  47. 'tstart',
  48. 'use',
  49. 'view',
  50. 'write',
  51. 'xecute',
  52. 'b',
  53. 'c',
  54. 'd',
  55. 'e',
  56. 'f',
  57. 'g',
  58. 'h',
  59. 'i',
  60. 'j',
  61. 'k',
  62. 'l',
  63. 'm',
  64. 'n',
  65. 'o',
  66. 'q',
  67. 'r',
  68. 's',
  69. 'tc',
  70. 'tro',
  71. 'ts',
  72. 'u',
  73. 'v',
  74. 'w',
  75. 'x',
  76. ]
  77. // The following list includes intrinsic functions _and_ special variables
  78. var intrinsicFuncsWords = [
  79. '\\$ascii',
  80. '\\$char',
  81. '\\$data',
  82. '\\$ecode',
  83. '\\$estack',
  84. '\\$etrap',
  85. '\\$extract',
  86. '\\$find',
  87. '\\$fnumber',
  88. '\\$get',
  89. '\\$horolog',
  90. '\\$io',
  91. '\\$increment',
  92. '\\$job',
  93. '\\$justify',
  94. '\\$length',
  95. '\\$name',
  96. '\\$next',
  97. '\\$order',
  98. '\\$piece',
  99. '\\$qlength',
  100. '\\$qsubscript',
  101. '\\$query',
  102. '\\$quit',
  103. '\\$random',
  104. '\\$reverse',
  105. '\\$select',
  106. '\\$stack',
  107. '\\$test',
  108. '\\$text',
  109. '\\$translate',
  110. '\\$view',
  111. '\\$x',
  112. '\\$y',
  113. '\\$a',
  114. '\\$c',
  115. '\\$d',
  116. '\\$e',
  117. '\\$ec',
  118. '\\$es',
  119. '\\$et',
  120. '\\$f',
  121. '\\$fn',
  122. '\\$g',
  123. '\\$h',
  124. '\\$i',
  125. '\\$j',
  126. '\\$l',
  127. '\\$n',
  128. '\\$na',
  129. '\\$o',
  130. '\\$p',
  131. '\\$q',
  132. '\\$ql',
  133. '\\$qs',
  134. '\\$r',
  135. '\\$re',
  136. '\\$s',
  137. '\\$st',
  138. '\\$t',
  139. '\\$tr',
  140. '\\$v',
  141. '\\$z',
  142. ]
  143. var intrinsicFuncs = wordRegexp(intrinsicFuncsWords)
  144. var command = wordRegexp(commandKeywords)
  145. function tokenBase(stream, state) {
  146. if (stream.sol()) {
  147. state.label = true
  148. state.commandMode = 0
  149. }
  150. // The <space> character has meaning in MUMPS. Ignoring consecutive
  151. // spaces would interfere with interpreting whether the next non-space
  152. // character belongs to the command or argument context.
  153. // Examine each character and update a mode variable whose interpretation is:
  154. // >0 => command 0 => argument <0 => command post-conditional
  155. var ch = stream.peek()
  156. if (ch == ' ' || ch == '\t') {
  157. // Pre-process <space>
  158. state.label = false
  159. if (state.commandMode == 0) state.commandMode = 1
  160. else if (state.commandMode < 0 || state.commandMode == 2) state.commandMode = 0
  161. } else if (ch != '.' && state.commandMode > 0) {
  162. if (ch == ':') state.commandMode = -1
  163. // SIS - Command post-conditional
  164. else state.commandMode = 2
  165. }
  166. // Do not color parameter list as line tag
  167. if (ch === '(' || ch === '\u0009') state.label = false
  168. // MUMPS comment starts with ";"
  169. if (ch === ';') {
  170. stream.skipToEnd()
  171. return 'comment'
  172. }
  173. // Number Literals // SIS/RLM - MUMPS permits canonic number followed by concatenate operator
  174. if (stream.match(/^[-+]?\d+(\.\d+)?([eE][-+]?\d+)?/)) return 'number'
  175. // Handle Strings
  176. if (ch == '"') {
  177. if (stream.skipTo('"')) {
  178. stream.next()
  179. return 'string'
  180. } else {
  181. stream.skipToEnd()
  182. return 'error'
  183. }
  184. }
  185. // Handle operators and Delimiters
  186. if (stream.match(doubleOperators) || stream.match(singleOperators)) return 'operator'
  187. // Prevents leading "." in DO block from falling through to error
  188. if (stream.match(singleDelimiters)) return null
  189. if (brackets.test(ch)) {
  190. stream.next()
  191. return 'bracket'
  192. }
  193. if (state.commandMode > 0 && stream.match(command)) return 'variable-2'
  194. if (stream.match(intrinsicFuncs)) return 'builtin'
  195. if (stream.match(identifiers)) return 'variable'
  196. // Detect dollar-sign when not a documented intrinsic function
  197. // "^" may introduce a GVN or SSVN - Color same as function
  198. if (ch === '$' || ch === '^') {
  199. stream.next()
  200. return 'builtin'
  201. }
  202. // MUMPS Indirection
  203. if (ch === '@') {
  204. stream.next()
  205. return 'string-2'
  206. }
  207. if (/[\w%]/.test(ch)) {
  208. stream.eatWhile(/[\w%]/)
  209. return 'variable'
  210. }
  211. // Handle non-detected items
  212. stream.next()
  213. return 'error'
  214. }
  215. return {
  216. startState: function () {
  217. return {
  218. label: false,
  219. commandMode: 0,
  220. }
  221. },
  222. token: function (stream, state) {
  223. var style = tokenBase(stream, state)
  224. if (state.label) return 'tag'
  225. return style
  226. },
  227. }
  228. })
  229. CodeMirror.defineMIME('text/x-mumps', 'mumps')
  230. })