commonlisp.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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('commonlisp', function (config) {
  15. var specialForm =
  16. /^(block|let*|return-from|catch|load-time-value|setq|eval-when|locally|symbol-macrolet|flet|macrolet|tagbody|function|multiple-value-call|the|go|multiple-value-prog1|throw|if|progn|unwind-protect|labels|progv|let|quote)$/
  17. var assumeBody = /^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/
  18. var numLiteral = /^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/
  19. var symbol = /[^\s'`,@()\[\]";]/
  20. var type
  21. function readSym(stream) {
  22. var ch
  23. while ((ch = stream.next())) {
  24. if (ch == '\\') stream.next()
  25. else if (!symbol.test(ch)) {
  26. stream.backUp(1)
  27. break
  28. }
  29. }
  30. return stream.current()
  31. }
  32. function base(stream, state) {
  33. if (stream.eatSpace()) {
  34. type = 'ws'
  35. return null
  36. }
  37. if (stream.match(numLiteral)) return 'number'
  38. var ch = stream.next()
  39. if (ch == '\\') ch = stream.next()
  40. if (ch == '"') return (state.tokenize = inString)(stream, state)
  41. else if (ch == '(') {
  42. type = 'open'
  43. return 'bracket'
  44. } else if (ch == ')' || ch == ']') {
  45. type = 'close'
  46. return 'bracket'
  47. } else if (ch == ';') {
  48. stream.skipToEnd()
  49. type = 'ws'
  50. return 'comment'
  51. } else if (/['`,@]/.test(ch)) return null
  52. else if (ch == '|') {
  53. if (stream.skipTo('|')) {
  54. stream.next()
  55. return 'symbol'
  56. } else {
  57. stream.skipToEnd()
  58. return 'error'
  59. }
  60. } else if (ch == '#') {
  61. var ch = stream.next()
  62. if (ch == '(') {
  63. type = 'open'
  64. return 'bracket'
  65. } else if (/[+\-=\.']/.test(ch)) return null
  66. else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null
  67. else if (ch == '|') return (state.tokenize = inComment)(stream, state)
  68. else if (ch == ':') {
  69. readSym(stream)
  70. return 'meta'
  71. } else if (ch == '\\') {
  72. stream.next()
  73. readSym(stream)
  74. return 'string-2'
  75. } else return 'error'
  76. } else {
  77. var name = readSym(stream)
  78. if (name == '.') return null
  79. type = 'symbol'
  80. if (name == 'nil' || name == 't' || name.charAt(0) == ':') return 'atom'
  81. if (state.lastType == 'open' && (specialForm.test(name) || assumeBody.test(name))) return 'keyword'
  82. if (name.charAt(0) == '&') return 'variable-2'
  83. return 'variable'
  84. }
  85. }
  86. function inString(stream, state) {
  87. var escaped = false,
  88. next
  89. while ((next = stream.next())) {
  90. if (next == '"' && !escaped) {
  91. state.tokenize = base
  92. break
  93. }
  94. escaped = !escaped && next == '\\'
  95. }
  96. return 'string'
  97. }
  98. function inComment(stream, state) {
  99. var next, last
  100. while ((next = stream.next())) {
  101. if (next == '#' && last == '|') {
  102. state.tokenize = base
  103. break
  104. }
  105. last = next
  106. }
  107. type = 'ws'
  108. return 'comment'
  109. }
  110. return {
  111. startState: function () {
  112. return { ctx: { prev: null, start: 0, indentTo: 0 }, lastType: null, tokenize: base }
  113. },
  114. token: function (stream, state) {
  115. if (stream.sol() && typeof state.ctx.indentTo != 'number') state.ctx.indentTo = state.ctx.start + 1
  116. type = null
  117. var style = state.tokenize(stream, state)
  118. if (type != 'ws') {
  119. if (state.ctx.indentTo == null) {
  120. if (type == 'symbol' && assumeBody.test(stream.current())) state.ctx.indentTo = state.ctx.start + config.indentUnit
  121. else state.ctx.indentTo = 'next'
  122. } else if (state.ctx.indentTo == 'next') {
  123. state.ctx.indentTo = stream.column()
  124. }
  125. state.lastType = type
  126. }
  127. if (type == 'open') state.ctx = { prev: state.ctx, start: stream.column(), indentTo: null }
  128. else if (type == 'close') state.ctx = state.ctx.prev || state.ctx
  129. return style
  130. },
  131. indent: function (state, _textAfter) {
  132. var i = state.ctx.indentTo
  133. return typeof i == 'number' ? i : state.ctx.start + 1
  134. },
  135. closeBrackets: { pairs: '()[]{}""' },
  136. lineComment: ';;',
  137. fold: 'brace-paren',
  138. blockCommentStart: '#|',
  139. blockCommentEnd: '|#',
  140. }
  141. })
  142. CodeMirror.defineMIME('text/x-common-lisp', 'commonlisp')
  143. })