clojure.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. Language: Clojure
  3. Description: Clojure syntax (based on lisp.js)
  4. Author: mfornos
  5. Website: https://clojure.org
  6. Category: lisp
  7. */
  8. /** @type LanguageFn */
  9. function clojure(hljs) {
  10. const SYMBOLSTART = 'a-zA-Z_\\-!.?+*=<>&\'';
  11. const SYMBOL_RE = '[#]?[' + SYMBOLSTART + '][' + SYMBOLSTART + '0-9/;:$#]*';
  12. const globals = 'def defonce defprotocol defstruct defmulti defmethod defn- defn defmacro deftype defrecord';
  13. const keywords = {
  14. $pattern: SYMBOL_RE,
  15. built_in:
  16. // Clojure keywords
  17. globals + ' '
  18. + 'cond apply if-not if-let if not not= =|0 <|0 >|0 <=|0 >=|0 ==|0 +|0 /|0 *|0 -|0 rem '
  19. + 'quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? '
  20. + 'set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? '
  21. + 'class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? '
  22. + 'string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . '
  23. + 'inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last '
  24. + 'drop-while while intern condp case reduced cycle split-at split-with repeat replicate '
  25. + 'iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext '
  26. + 'nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends '
  27. + 'add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler '
  28. + 'set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter '
  29. + 'monitor-exit macroexpand macroexpand-1 for dosync and or '
  30. + 'when when-not when-let comp juxt partial sequence memoize constantly complement identity assert '
  31. + 'peek pop doto proxy first rest cons cast coll last butlast '
  32. + 'sigs reify second ffirst fnext nfirst nnext meta with-meta ns in-ns create-ns import '
  33. + 'refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! '
  34. + 'assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger '
  35. + 'bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline '
  36. + 'flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking '
  37. + 'assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! '
  38. + 'reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! '
  39. + 'new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty '
  40. + 'hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list '
  41. + 'disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer '
  42. + 'chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate '
  43. + 'unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta '
  44. + 'lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize'
  45. };
  46. const SYMBOL = {
  47. begin: SYMBOL_RE,
  48. relevance: 0
  49. };
  50. const NUMBER = {
  51. scope: 'number',
  52. relevance: 0,
  53. variants: [
  54. { match: /[-+]?0[xX][0-9a-fA-F]+N?/ }, // hexadecimal // 0x2a
  55. { match: /[-+]?0[0-7]+N?/ }, // octal // 052
  56. { match: /[-+]?[1-9][0-9]?[rR][0-9a-zA-Z]+N?/ }, // variable radix from 2 to 36 // 2r101010, 8r52, 36r16
  57. { match: /[-+]?[0-9]+\/[0-9]+N?/ }, // ratio // 1/2
  58. { match: /[-+]?[0-9]+((\.[0-9]*([eE][+-]?[0-9]+)?M?)|([eE][+-]?[0-9]+M?|M))/ }, // float // 0.42 4.2E-1M 42E1 42M
  59. { match: /[-+]?([1-9][0-9]*|0)N?/ }, // int (don't match leading 0) // 42 42N
  60. ]
  61. };
  62. const CHARACTER = {
  63. scope: 'character',
  64. variants: [
  65. { match: /\\o[0-3]?[0-7]{1,2}/ }, // Unicode Octal 0 - 377
  66. { match: /\\u[0-9a-fA-F]{4}/ }, // Unicode Hex 0000 - FFFF
  67. { match: /\\(newline|space|tab|formfeed|backspace|return)/ }, // special characters
  68. {
  69. match: /\\\S/,
  70. relevance: 0
  71. } // any non-whitespace char
  72. ]
  73. };
  74. const REGEX = {
  75. scope: 'regex',
  76. begin: /#"/,
  77. end: /"/,
  78. contains: [ hljs.BACKSLASH_ESCAPE ]
  79. };
  80. const STRING = hljs.inherit(hljs.QUOTE_STRING_MODE, { illegal: null });
  81. const COMMA = {
  82. scope: 'punctuation',
  83. match: /,/,
  84. relevance: 0
  85. };
  86. const COMMENT = hljs.COMMENT(
  87. ';',
  88. '$',
  89. { relevance: 0 }
  90. );
  91. const LITERAL = {
  92. className: 'literal',
  93. begin: /\b(true|false|nil)\b/
  94. };
  95. const COLLECTION = {
  96. begin: "\\[|(#::?" + SYMBOL_RE + ")?\\{",
  97. end: '[\\]\\}]',
  98. relevance: 0
  99. };
  100. const KEY = {
  101. className: 'symbol',
  102. begin: '[:]{1,2}' + SYMBOL_RE
  103. };
  104. const LIST = {
  105. begin: '\\(',
  106. end: '\\)'
  107. };
  108. const BODY = {
  109. endsWithParent: true,
  110. relevance: 0
  111. };
  112. const NAME = {
  113. keywords: keywords,
  114. className: 'name',
  115. begin: SYMBOL_RE,
  116. relevance: 0,
  117. starts: BODY
  118. };
  119. const DEFAULT_CONTAINS = [
  120. COMMA,
  121. LIST,
  122. CHARACTER,
  123. REGEX,
  124. STRING,
  125. COMMENT,
  126. KEY,
  127. COLLECTION,
  128. NUMBER,
  129. LITERAL,
  130. SYMBOL
  131. ];
  132. const GLOBAL = {
  133. beginKeywords: globals,
  134. keywords: {
  135. $pattern: SYMBOL_RE,
  136. keyword: globals
  137. },
  138. end: '(\\[|#|\\d|"|:|\\{|\\)|\\(|$)',
  139. contains: [
  140. {
  141. className: 'title',
  142. begin: SYMBOL_RE,
  143. relevance: 0,
  144. excludeEnd: true,
  145. // we can only have a single title
  146. endsParent: true
  147. }
  148. ].concat(DEFAULT_CONTAINS)
  149. };
  150. LIST.contains = [
  151. GLOBAL,
  152. NAME,
  153. BODY
  154. ];
  155. BODY.contains = DEFAULT_CONTAINS;
  156. COLLECTION.contains = DEFAULT_CONTAINS;
  157. return {
  158. name: 'Clojure',
  159. aliases: [
  160. 'clj',
  161. 'edn'
  162. ],
  163. illegal: /\S/,
  164. contains: [
  165. COMMA,
  166. LIST,
  167. CHARACTER,
  168. REGEX,
  169. STRING,
  170. COMMENT,
  171. KEY,
  172. COLLECTION,
  173. NUMBER,
  174. LITERAL
  175. ]
  176. };
  177. }
  178. export { clojure as default };