dylan.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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. function forEach(arr, f) {
  15. for (var i = 0; i < arr.length; i++) f(arr[i], i)
  16. }
  17. function some(arr, f) {
  18. for (var i = 0; i < arr.length; i++) if (f(arr[i], i)) return true
  19. return false
  20. }
  21. CodeMirror.defineMode('dylan', function (_config) {
  22. // Words
  23. var words = {
  24. // Words that introduce unnamed definitions like "define interface"
  25. unnamedDefinition: ['interface'],
  26. // Words that introduce simple named definitions like "define library"
  27. namedDefinition: ['module', 'library', 'macro', 'C-struct', 'C-union', 'C-function', 'C-callable-wrapper'],
  28. // Words that introduce type definitions like "define class".
  29. // These are also parameterized like "define method" and are
  30. // appended to otherParameterizedDefinitionWords
  31. typeParameterizedDefinition: ['class', 'C-subtype', 'C-mapped-subtype'],
  32. // Words that introduce trickier definitions like "define method".
  33. // These require special definitions to be added to startExpressions
  34. otherParameterizedDefinition: ['method', 'function', 'C-variable', 'C-address'],
  35. // Words that introduce module constant definitions.
  36. // These must also be simple definitions and are
  37. // appended to otherSimpleDefinitionWords
  38. constantSimpleDefinition: ['constant'],
  39. // Words that introduce module variable definitions.
  40. // These must also be simple definitions and are
  41. // appended to otherSimpleDefinitionWords
  42. variableSimpleDefinition: ['variable'],
  43. // Other words that introduce simple definitions
  44. // (without implicit bodies).
  45. otherSimpleDefinition: ['generic', 'domain', 'C-pointer-type', 'table'],
  46. // Words that begin statements with implicit bodies.
  47. statement: ['if', 'block', 'begin', 'method', 'case', 'for', 'select', 'when', 'unless', 'until', 'while', 'iterate', 'profiling', 'dynamic-bind'],
  48. // Patterns that act as separators in compound statements.
  49. // This may include any general pattern that must be indented
  50. // specially.
  51. separator: ['finally', 'exception', 'cleanup', 'else', 'elseif', 'afterwards'],
  52. // Keywords that do not require special indentation handling,
  53. // but which should be highlighted
  54. other: ['above', 'below', 'by', 'from', 'handler', 'in', 'instance', 'let', 'local', 'otherwise', 'slot', 'subclass', 'then', 'to', 'keyed-by', 'virtual'],
  55. // Condition signaling function calls
  56. signalingCalls: ['signal', 'error', 'cerror', 'break', 'check-type', 'abort'],
  57. }
  58. words['otherDefinition'] = words['unnamedDefinition'].concat(words['namedDefinition']).concat(words['otherParameterizedDefinition'])
  59. words['definition'] = words['typeParameterizedDefinition'].concat(words['otherDefinition'])
  60. words['parameterizedDefinition'] = words['typeParameterizedDefinition'].concat(words['otherParameterizedDefinition'])
  61. words['simpleDefinition'] = words['constantSimpleDefinition'].concat(words['variableSimpleDefinition']).concat(words['otherSimpleDefinition'])
  62. words['keyword'] = words['statement'].concat(words['separator']).concat(words['other'])
  63. // Patterns
  64. var symbolPattern = '[-_a-zA-Z?!*@<>$%]+'
  65. var symbol = new RegExp('^' + symbolPattern)
  66. var patterns = {
  67. // Symbols with special syntax
  68. symbolKeyword: symbolPattern + ':',
  69. symbolClass: '<' + symbolPattern + '>',
  70. symbolGlobal: '\\*' + symbolPattern + '\\*',
  71. symbolConstant: '\\$' + symbolPattern,
  72. }
  73. var patternStyles = {
  74. symbolKeyword: 'atom',
  75. symbolClass: 'tag',
  76. symbolGlobal: 'variable-2',
  77. symbolConstant: 'variable-3',
  78. }
  79. // Compile all patterns to regular expressions
  80. for (var patternName in patterns) if (patterns.hasOwnProperty(patternName)) patterns[patternName] = new RegExp('^' + patterns[patternName])
  81. // Names beginning "with-" and "without-" are commonly
  82. // used as statement macro
  83. patterns['keyword'] = [/^with(?:out)?-[-_a-zA-Z?!*@<>$%]+/]
  84. var styles = {}
  85. styles['keyword'] = 'keyword'
  86. styles['definition'] = 'def'
  87. styles['simpleDefinition'] = 'def'
  88. styles['signalingCalls'] = 'builtin'
  89. // protected words lookup table
  90. var wordLookup = {}
  91. var styleLookup = {}
  92. forEach(['keyword', 'definition', 'simpleDefinition', 'signalingCalls'], function (type) {
  93. forEach(words[type], function (word) {
  94. wordLookup[word] = type
  95. styleLookup[word] = styles[type]
  96. })
  97. })
  98. function chain(stream, state, f) {
  99. state.tokenize = f
  100. return f(stream, state)
  101. }
  102. function tokenBase(stream, state) {
  103. // String
  104. var ch = stream.peek()
  105. if (ch == "'" || ch == '"') {
  106. stream.next()
  107. return chain(stream, state, tokenString(ch, 'string'))
  108. }
  109. // Comment
  110. else if (ch == '/') {
  111. stream.next()
  112. if (stream.eat('*')) {
  113. return chain(stream, state, tokenComment)
  114. } else if (stream.eat('/')) {
  115. stream.skipToEnd()
  116. return 'comment'
  117. }
  118. stream.backUp(1)
  119. }
  120. // Decimal
  121. else if (/[+\-\d\.]/.test(ch)) {
  122. if (stream.match(/^[+-]?[0-9]*\.[0-9]*([esdx][+-]?[0-9]+)?/i) || stream.match(/^[+-]?[0-9]+([esdx][+-]?[0-9]+)/i) || stream.match(/^[+-]?\d+/)) {
  123. return 'number'
  124. }
  125. }
  126. // Hash
  127. else if (ch == '#') {
  128. stream.next()
  129. // Symbol with string syntax
  130. ch = stream.peek()
  131. if (ch == '"') {
  132. stream.next()
  133. return chain(stream, state, tokenString('"', 'string'))
  134. }
  135. // Binary number
  136. else if (ch == 'b') {
  137. stream.next()
  138. stream.eatWhile(/[01]/)
  139. return 'number'
  140. }
  141. // Hex number
  142. else if (ch == 'x') {
  143. stream.next()
  144. stream.eatWhile(/[\da-f]/i)
  145. return 'number'
  146. }
  147. // Octal number
  148. else if (ch == 'o') {
  149. stream.next()
  150. stream.eatWhile(/[0-7]/)
  151. return 'number'
  152. }
  153. // Token concatenation in macros
  154. else if (ch == '#') {
  155. stream.next()
  156. return 'punctuation'
  157. }
  158. // Sequence literals
  159. else if (ch == '[' || ch == '(') {
  160. stream.next()
  161. return 'bracket'
  162. // Hash symbol
  163. } else if (stream.match(/f|t|all-keys|include|key|next|rest/i)) {
  164. return 'atom'
  165. } else {
  166. stream.eatWhile(/[-a-zA-Z]/)
  167. return 'error'
  168. }
  169. } else if (ch == '~') {
  170. stream.next()
  171. ch = stream.peek()
  172. if (ch == '=') {
  173. stream.next()
  174. ch = stream.peek()
  175. if (ch == '=') {
  176. stream.next()
  177. return 'operator'
  178. }
  179. return 'operator'
  180. }
  181. return 'operator'
  182. } else if (ch == ':') {
  183. stream.next()
  184. ch = stream.peek()
  185. if (ch == '=') {
  186. stream.next()
  187. return 'operator'
  188. } else if (ch == ':') {
  189. stream.next()
  190. return 'punctuation'
  191. }
  192. } else if ('[](){}'.indexOf(ch) != -1) {
  193. stream.next()
  194. return 'bracket'
  195. } else if ('.,'.indexOf(ch) != -1) {
  196. stream.next()
  197. return 'punctuation'
  198. } else if (stream.match('end')) {
  199. return 'keyword'
  200. }
  201. for (var name in patterns) {
  202. if (patterns.hasOwnProperty(name)) {
  203. var pattern = patterns[name]
  204. if (
  205. (pattern instanceof Array &&
  206. some(pattern, function (p) {
  207. return stream.match(p)
  208. })) ||
  209. stream.match(pattern)
  210. )
  211. return patternStyles[name]
  212. }
  213. }
  214. if (/[+\-*\/^=<>&|]/.test(ch)) {
  215. stream.next()
  216. return 'operator'
  217. }
  218. if (stream.match('define')) {
  219. return 'def'
  220. } else {
  221. stream.eatWhile(/[\w\-]/)
  222. // Keyword
  223. if (wordLookup.hasOwnProperty(stream.current())) {
  224. return styleLookup[stream.current()]
  225. } else if (stream.current().match(symbol)) {
  226. return 'variable'
  227. } else {
  228. stream.next()
  229. return 'variable-2'
  230. }
  231. }
  232. }
  233. function tokenComment(stream, state) {
  234. var maybeEnd = false,
  235. maybeNested = false,
  236. nestedCount = 0,
  237. ch
  238. while ((ch = stream.next())) {
  239. if (ch == '/' && maybeEnd) {
  240. if (nestedCount > 0) {
  241. nestedCount--
  242. } else {
  243. state.tokenize = tokenBase
  244. break
  245. }
  246. } else if (ch == '*' && maybeNested) {
  247. nestedCount++
  248. }
  249. maybeEnd = ch == '*'
  250. maybeNested = ch == '/'
  251. }
  252. return 'comment'
  253. }
  254. function tokenString(quote, style) {
  255. return function (stream, state) {
  256. var escaped = false,
  257. next,
  258. end = false
  259. while ((next = stream.next()) != null) {
  260. if (next == quote && !escaped) {
  261. end = true
  262. break
  263. }
  264. escaped = !escaped && next == '\\'
  265. }
  266. if (end || !escaped) {
  267. state.tokenize = tokenBase
  268. }
  269. return style
  270. }
  271. }
  272. // Interface
  273. return {
  274. startState: function () {
  275. return {
  276. tokenize: tokenBase,
  277. currentIndent: 0,
  278. }
  279. },
  280. token: function (stream, state) {
  281. if (stream.eatSpace()) return null
  282. var style = state.tokenize(stream, state)
  283. return style
  284. },
  285. blockCommentStart: '/*',
  286. blockCommentEnd: '*/',
  287. }
  288. })
  289. CodeMirror.defineMIME('text/x-dylan', 'dylan')
  290. })