elm.js 5.5 KB

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