Skip to content

Commit

Permalink
(clojure) Add support for global definitions
Browse files Browse the repository at this point in the history
Adds support for Clojure global definitions with class name `title`, including:

* def
* defonce
* defprotocol
* defstruct
* defmulti
* defmethod
* defn
* defn-
* defmacro
* deftype
* defrecord
  • Loading branch information
agrison committed Jan 9, 2020
1 parent 42f1df4 commit 19e2c19
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 32 deletions.
1 change: 1 addition & 0 deletions AUTHORS.en.txt
Expand Up @@ -284,3 +284,4 @@ Contributors:
- Thomas Reichel <tom.p.reichel@gmail.com>
- G8t Guy <g8tguy@g8tguy.com>
- Samia Ali <samiaab1990@gmail.com>
- Alexandre Grison <a.grison@gmail.com>
75 changes: 45 additions & 30 deletions src/languages/clojure.js
Expand Up @@ -2,43 +2,45 @@
Language: Clojure
Description: Clojure syntax (based on lisp.js)
Author: mfornos
Contributors: Martin Clausen <martin.clausene@gmail.com>
Contributors: Martin Clausen <martin.clausene@gmail.com>; Alexandre Grison <a.grison@gmail.com>
Website: https://clojure.org
Category: lisp
*/

function(hljs) {
var globals = 'def defonce defprotocol defstruct defmulti defmethod defn defn- defmacro deftype defrecord';
var keywords = {
'builtin-name':
// Clojure keywords
'def defonce cond apply if-not if-let if not not= = < > <= >= == + / * - rem '+
'quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? '+
'set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? '+
'class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? '+
'string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . '+
'inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last '+
'drop-while while intern condp case reduced cycle split-at split-with repeat replicate '+
'iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext '+
'nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends '+
'add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler '+
'set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter '+
'monitor-exit defmacro defn defn- macroexpand macroexpand-1 for dosync and or '+
'when when-not when-let comp juxt partial sequence memoize constantly complement identity assert '+
'peek pop doto proxy defstruct first rest cons defprotocol cast coll deftype defrecord last butlast '+
'sigs reify second ffirst fnext nfirst nnext defmulti defmethod meta with-meta ns in-ns create-ns import '+
'refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! '+
'assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger '+
'bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline '+
'flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking '+
'assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! '+
'reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! '+
'new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty '+
'hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list '+
'disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer '+
'chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate '+
'unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta '+
globals +
'cond apply if-not if-let if not not= = < > <= >= == + / * - rem ' +
'quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? ' +
'set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? ' +
'class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? ' +
'string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . ' +
'inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last ' +
'drop-while while intern condp case reduced cycle split-at split-with repeat replicate ' +
'iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext ' +
'nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends ' +
'add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler ' +
'set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter ' +
'monitor-exit macroexpand macroexpand-1 for dosync and or ' +
'when when-not when-let comp juxt partial sequence memoize constantly complement identity assert ' +
'peek pop doto proxy first rest cons cast coll last butlast ' +
'sigs reify second ffirst fnext nfirst nnext meta with-meta ns in-ns create-ns import ' +
'refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! ' +
'assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger ' +
'bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline ' +
'flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking ' +
'assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! ' +
'reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! ' +
'new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty ' +
'hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list ' +
'disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer ' +
'chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate ' +
'unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta ' +
'lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize'
};
};

var SYMBOLSTART = 'a-zA-Z_\\-!.?+*=<>&#\'';
var SYMBOL_RE = '[' + SYMBOLSTART + '][' + SYMBOLSTART + '0-9/;:]*';
Expand Down Expand Up @@ -91,7 +93,20 @@ function(hljs) {
};
var DEFAULT_CONTAINS = [LIST, STRING, HINT, HINT_COL, COMMENT, KEY, COLLECTION, NUMBER, LITERAL, SYMBOL];

LIST.contains = [hljs.COMMENT('comment', ''), NAME, BODY];
var GLOBAL = {
beginKeywords: globals,
end: '(\\[|\\#|\\d|"|:|\\{|\\)|\\(|$)',
excludeEnd: true,
contains: [
{
className: 'title',
begin: SYMBOL_RE,
relevance: 0
},
].concat(DEFAULT_CONTAINS)
};

LIST.contains = [hljs.COMMENT('comment', ''), GLOBAL, NAME, BODY];
BODY.contains = DEFAULT_CONTAINS;
COLLECTION.contains = DEFAULT_CONTAINS;
HINT_COL.contains = [COLLECTION];
Expand All @@ -100,5 +115,5 @@ function(hljs) {
aliases: ['clj'],
illegal: /\S/,
contains: [LIST, STRING, HINT, HINT_COL, COMMENT, KEY, COLLECTION, NUMBER, LITERAL]
}
};
}
61 changes: 61 additions & 0 deletions test/markup/clojure/globals_definition.expect.txt
@@ -0,0 +1,61 @@
(<span class="hljs-name"><span class="hljs-builtin-name">ns</span></span> playground
(<span class="hljs-symbol">:require</span>
[clojure.string <span class="hljs-symbol">:as</span> str]))

<span class="hljs-comment">; function</span>
(<span class="hljs-keyword">defn</span> <span class="hljs-title">clojure-function</span> [args]
(<span class="hljs-name"><span class="hljs-builtin-name">let</span></span> [string <span class="hljs-string">"multiline\nstring"</span>
regexp #<span class="hljs-string">"regexp"</span>
number <span class="hljs-number">100</span>,<span class="hljs-number">000</span>
booleans [<span class="hljs-literal">false</span> <span class="hljs-literal">true</span>]
keyword <span class="hljs-symbol">::the-keyword</span>]
<span class="hljs-comment">;; this is comment</span>
(<span class="hljs-name"><span class="hljs-builtin-name">if</span></span> <span class="hljs-literal">true</span>
(<span class="hljs-name"><span class="hljs-builtin-name">-&gt;&gt;</span></span>
(<span class="hljs-name"><span class="hljs-builtin-name">list</span></span> [vector] {<span class="hljs-symbol">:map</span> map} #{'set})))))

<span class="hljs-comment">; global</span>
(<span class="hljs-keyword">def</span> <span class="hljs-title">some-var</span>)
<span class="hljs-comment">; another one</span>
(<span class="hljs-keyword">def</span> <span class="hljs-title">alternative-var</span> <span class="hljs-string">"132"</span>)
<span class="hljs-comment">; defonce</span>
(<span class="hljs-keyword">defonce</span> ^<span class="hljs-symbol">:private</span> <span class="hljs-title">another-var</span> <span class="hljs-title">#</span><span class="hljs-string">"foo"</span>)

<span class="hljs-comment">; private function</span>
(<span class="hljs-keyword">defn</span><span class="hljs-title">-</span> <span class="hljs-title">add</span> [x y] (<span class="hljs-name"><span class="hljs-builtin-name">+</span></span> x y))

<span class="hljs-comment">; protocols</span>
(<span class="hljs-keyword">defprotocol</span> <span class="hljs-title">Fly</span>
<span class="hljs-string">"A simple protocol for flying"</span>
(<span class="hljs-name">fly</span> [this] <span class="hljs-string">"Method to fly"</span>))

(<span class="hljs-keyword">defrecord</span> <span class="hljs-title">Bird</span> [name species]
Fly
(<span class="hljs-name">fly</span> [this] (<span class="hljs-name"><span class="hljs-builtin-name">str</span></span> (<span class="hljs-symbol">:name</span> this) <span class="hljs-string">" flies..."</span>)))

<span class="hljs-comment">; multimethods</span>
(<span class="hljs-keyword">defmulti</span> <span class="hljs-title">service-charge</span> (<span class="hljs-name"><span class="hljs-builtin-name">fn</span></span> [acct] [(<span class="hljs-name">account-level</span> acct) (<span class="hljs-symbol">:tag</span> acct)]))
(<span class="hljs-keyword">defmethod</span> <span class="hljs-title">service-charge</span> [<span class="hljs-symbol">::acc/Basic</span> <span class="hljs-symbol">::acc/Checking</span>] [_] <span class="hljs-number">25</span>)
(<span class="hljs-keyword">defmethod</span> <span class="hljs-title">service-charge</span> [<span class="hljs-symbol">::acc/Basic</span> <span class="hljs-symbol">::acc/Savings</span>] [_] <span class="hljs-number">10</span>)
(<span class="hljs-keyword">defmethod</span> <span class="hljs-title">service-charge</span> [<span class="hljs-symbol">::acc/Premium</span> <span class="hljs-symbol">::acc/Account</span>] [_] <span class="hljs-number">0</span>)

<span class="hljs-comment">; macros</span>
(<span class="hljs-keyword">defmacro</span> <span class="hljs-title">unless</span> [pred a b]
`(<span class="hljs-name"><span class="hljs-builtin-name">if</span></span> (<span class="hljs-name"><span class="hljs-builtin-name">not</span></span> ~pred) ~a ~b))

(<span class="hljs-name">unless</span> <span class="hljs-literal">false</span> (<span class="hljs-name">println</span> <span class="hljs-string">"Will print"</span>) (<span class="hljs-name">println</span> <span class="hljs-string">"Will not print"</span>))

<span class="hljs-comment">; types</span>
(<span class="hljs-keyword">deftype</span> <span class="hljs-title">Circle</span> [radius])
(<span class="hljs-keyword">deftype</span> <span class="hljs-title">Square</span> [length width])

<span class="hljs-comment">;; multimethods again</span>
(<span class="hljs-keyword">defmulti</span> <span class="hljs-title">area</span> <span class="hljs-title">class</span>)
(<span class="hljs-keyword">defmethod</span> <span class="hljs-title">area</span> <span class="hljs-title">Circle</span> [c]
(<span class="hljs-name"><span class="hljs-builtin-name">*</span></span> Math/PI (<span class="hljs-name"><span class="hljs-builtin-name">*</span></span> (<span class="hljs-name">.radius</span> c) (<span class="hljs-name">.radius</span> c))))
(<span class="hljs-keyword">defmethod</span> <span class="hljs-title">area</span> <span class="hljs-title">Square</span> [s]
(<span class="hljs-name"><span class="hljs-builtin-name">*</span></span> (<span class="hljs-name">.length</span> s) (<span class="hljs-name">.width</span> s)))

<span class="hljs-comment">;; create a couple shapes and get their area</span>
(<span class="hljs-keyword">def</span> <span class="hljs-title">myCircle</span> (<span class="hljs-name">Circle.</span> <span class="hljs-number">10</span>))
(<span class="hljs-keyword">def</span> <span class="hljs-title">mySquare</span> (<span class="hljs-name">Square.</span> <span class="hljs-number">5</span> <span class="hljs-number">11</span>))
61 changes: 61 additions & 0 deletions test/markup/clojure/globals_definition.txt
@@ -0,0 +1,61 @@
(ns playground
(:require
[clojure.string :as str]))

; function
(defn clojure-function [args]
(let [string "multiline\nstring"
regexp #"regexp"
number 100,000
booleans [false true]
keyword ::the-keyword]
;; this is comment
(if true
(->>
(list [vector] {:map map} #{'set})))))

; global
(def some-var)
; another one
(def alternative-var "132")
; defonce
(defonce ^:private another-var #"foo")

; private function
(defn- add [x y] (+ x y))

; protocols
(defprotocol Fly
"A simple protocol for flying"
(fly [this] "Method to fly"))

(defrecord Bird [name species]
Fly
(fly [this] (str (:name this) " flies...")))

; multimethods
(defmulti service-charge (fn [acct] [(account-level acct) (:tag acct)]))
(defmethod service-charge [::acc/Basic ::acc/Checking] [_] 25)
(defmethod service-charge [::acc/Basic ::acc/Savings] [_] 10)
(defmethod service-charge [::acc/Premium ::acc/Account] [_] 0)

; macros
(defmacro unless [pred a b]
`(if (not ~pred) ~a ~b))

(unless false (println "Will print") (println "Will not print"))

; types
(deftype Circle [radius])
(deftype Square [length width])

;; multimethods again
(defmulti area class)
(defmethod area Circle [c]
(* Math/PI (* (.radius c) (.radius c))))
(defmethod area Square [s]
(* (.length s) (.width s)))

;; create a couple shapes and get their area
(def myCircle (Circle. 10))
(def mySquare (Square. 5 11))
2 changes: 1 addition & 1 deletion test/markup/clojure/hint_col.expect.txt
Expand Up @@ -4,7 +4,7 @@
(<span class="hljs-name">definterface</span> Foo (<span class="hljs-name">foo</span> []))

<span class="hljs-comment">;; annotation on type</span>
(<span class="hljs-name"><span class="hljs-builtin-name">deftype</span></span> <span class="hljs-comment">^{Deprecated true
(<span class="hljs-keyword">deftype</span> <span class="hljs-comment">^{Deprecated true
Retention RetentionPolicy/RUNTIME
javax.annotation.processing.SupportedOptions [<span class="hljs-string">"foo"</span> <span class="hljs-string">"bar"</span> <span class="hljs-string">"baz"</span>]
javax.xml.ws.soap.Addressing {<span class="hljs-symbol">:enabled</span> <span class="hljs-literal">false</span> <span class="hljs-symbol">:required</span> <span class="hljs-literal">true</span>}
Expand Down
2 changes: 1 addition & 1 deletion test/markup/clojure/symbols-numbers.expect.txt
@@ -1 +1 @@
(<span class="hljs-name"><span class="hljs-builtin-name">def</span></span> +x [(<span class="hljs-name">a</span> <span class="hljs-number">1</span>) <span class="hljs-number">+2</span> <span class="hljs-number">-3.0</span> y-5])
(<span class="hljs-keyword">def</span> <span class="hljs-title">+x</span> [(<span class="hljs-name">a</span> <span class="hljs-number">1</span>) <span class="hljs-number">+2</span> <span class="hljs-number">-3.0</span> y-5])

0 comments on commit 19e2c19

Please sign in to comment.