elm.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: http://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('elm', function () {
  15. function switchState(source, setState, f) {
  16. setState(f)
  17. return f(source, setState)
  18. }
  19. var lowerRE = /[a-z]/
  20. var upperRE = /[A-Z]/
  21. var innerRE = /[a-zA-Z0-9_]/
  22. var digitRE = /[0-9]/
  23. var hexRE = /[0-9A-Fa-f]/
  24. var symbolRE = /[-&*+.\\/<>=?^|:]/
  25. var specialRE = /[(),[\]{}]/
  26. var spacesRE = /[ \v\f]/ // newlines are handled in tokenizer
  27. function normal() {
  28. return function (source, setState) {
  29. if (source.eatWhile(spacesRE)) {
  30. return null
  31. }
  32. var char = source.next()
  33. if (specialRE.test(char)) {
  34. return char === '{' && source.eat('-')
  35. ? switchState(source, setState, chompMultiComment(1))
  36. : char === '[' && source.match('glsl|')
  37. ? switchState(source, setState, chompGlsl)
  38. : 'builtin'
  39. }
  40. if (char === "'") {
  41. return switchState(source, setState, chompChar)
  42. }
  43. if (char === '"') {
  44. return source.eat('"') ? (source.eat('"') ? switchState(source, setState, chompMultiString) : 'string') : switchState(source, setState, chompSingleString)
  45. }
  46. if (upperRE.test(char)) {
  47. source.eatWhile(innerRE)
  48. return 'variable-2'
  49. }
  50. if (lowerRE.test(char)) {
  51. var isDef = source.pos === 1
  52. source.eatWhile(innerRE)
  53. return isDef ? 'def' : 'variable'
  54. }
  55. if (digitRE.test(char)) {
  56. if (char === '0') {
  57. if (source.eat(/[xX]/)) {
  58. source.eatWhile(hexRE) // should require at least 1
  59. return 'number'
  60. }
  61. } else {
  62. source.eatWhile(digitRE)
  63. }
  64. if (source.eat('.')) {
  65. source.eatWhile(digitRE) // should require at least 1
  66. }
  67. if (source.eat(/[eE]/)) {
  68. source.eat(/[-+]/)
  69. source.eatWhile(digitRE) // should require at least 1
  70. }
  71. return 'number'
  72. }
  73. if (symbolRE.test(char)) {
  74. if (char === '-' && source.eat('-')) {
  75. source.skipToEnd()
  76. return 'comment'
  77. }
  78. source.eatWhile(symbolRE)
  79. return 'keyword'
  80. }
  81. if (char === '_') {
  82. return 'keyword'
  83. }
  84. return 'error'
  85. }
  86. }
  87. function chompMultiComment(nest) {
  88. if (nest == 0) {
  89. return normal()
  90. }
  91. return function (source, setState) {
  92. while (!source.eol()) {
  93. var char = source.next()
  94. if (char == '{' && source.eat('-')) {
  95. ++nest
  96. } else if (char == '-' && source.eat('}')) {
  97. --nest
  98. if (nest === 0) {
  99. setState(normal())
  100. return 'comment'
  101. }
  102. }
  103. }
  104. setState(chompMultiComment(nest))
  105. return 'comment'
  106. }
  107. }
  108. function chompMultiString(source, setState) {
  109. while (!source.eol()) {
  110. var char = source.next()
  111. if (char === '"' && source.eat('"') && source.eat('"')) {
  112. setState(normal())
  113. return 'string'
  114. }
  115. }
  116. return 'string'
  117. }
  118. function chompSingleString(source, setState) {
  119. while (source.skipTo('\\"')) {
  120. source.next()
  121. source.next()
  122. }
  123. if (source.skipTo('"')) {
  124. source.next()
  125. setState(normal())
  126. return 'string'
  127. }
  128. source.skipToEnd()
  129. setState(normal())
  130. return 'error'
  131. }
  132. function chompChar(source, setState) {
  133. while (source.skipTo("\\'")) {
  134. source.next()
  135. source.next()
  136. }
  137. if (source.skipTo("'")) {
  138. source.next()
  139. setState(normal())
  140. return 'string'
  141. }
  142. source.skipToEnd()
  143. setState(normal())
  144. return 'error'
  145. }
  146. function chompGlsl(source, setState) {
  147. while (!source.eol()) {
  148. var char = source.next()
  149. if (char === '|' && source.eat(']')) {
  150. setState(normal())
  151. return 'string'
  152. }
  153. }
  154. return 'string'
  155. }
  156. var wellKnownWords = {
  157. case: 1,
  158. of: 1,
  159. as: 1,
  160. if: 1,
  161. then: 1,
  162. else: 1,
  163. let: 1,
  164. in: 1,
  165. type: 1,
  166. alias: 1,
  167. module: 1,
  168. where: 1,
  169. import: 1,
  170. exposing: 1,
  171. port: 1,
  172. }
  173. return {
  174. startState: function () {
  175. return { f: normal() }
  176. },
  177. copyState: function (s) {
  178. return { f: s.f }
  179. },
  180. token: function (stream, state) {
  181. var type = state.f(stream, function (s) {
  182. state.f = s
  183. })
  184. var word = stream.current()
  185. return wellKnownWords.hasOwnProperty(word) ? 'keyword' : type
  186. },
  187. }
  188. })
  189. CodeMirror.defineMIME('text/x-elm', 'elm')
  190. })