Skip to content

Commit

Permalink
enh(clojure) Adds global definitions with class name title (#2419)
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

Original PR work by Alexandre Grison. 

Co-authored-by: Alexandre Grison <a.grison@gmail.com>
  • Loading branch information
joshgoebel and agrison committed Mar 3, 2020
1 parent 361c546 commit 484de97
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 32 deletions.
1 change: 1 addition & 0 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,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>
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Core Changes:

Language Improvements:

- enh(clojure) Add support for global definitions name (#2347) [Alexandre Grison][]
- enh(fortran) Support Fortran 77 style comments (#2416) [Josh Goebel][]
- (csharp) add support for `@identifier` style identifiers (#2414) [Josh Goebel][]
- fix(elixir) Support function names with a slash (#2406) [Josh Goebel][]
Expand Down Expand Up @@ -45,6 +46,7 @@ Developer Tools:

- added Dockerfile for optionally developing with a container

[Alexandre Grison]: https://github.com/agrison
[Josh Goebel]: https://github.com/yyyc514
[Sam Miller]: https://github.com/smillerc
[Robert Riebisch]: https://github.com/bttrx
Expand Down
76 changes: 46 additions & 30 deletions src/languages/clojure.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,44 @@
Language: Clojure
Description: Clojure syntax (based on lisp.js)
Author: mfornos
Contributors: Martin Clausen <martin.clausene@gmail.com>
Website: https://clojure.org
Category: lisp
*/

export default 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 +92,22 @@ export default 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|"|:|\\{|\\)|\\(|$)',
contains: [
{
className: 'title',
begin: SYMBOL_RE,
relevance: 0,
excludeEnd: true,
// we can only have a single title
endsParent: true
},
].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 @@ -101,5 +117,5 @@ export default 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
Original file line number Diff line number Diff line change
@@ -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-string">"foo"</span>)

<span class="hljs-comment">; private function</span>
(<span class="hljs-keyword">defn</span><span class="hljs-title">-</span> add [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> class)
(<span class="hljs-keyword">defmethod</span> <span class="hljs-title">area</span> Circle [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> Square [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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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 484de97

Please sign in to comment.