Skip to content

Commit

Permalink
Add support for Lisp (#1297)
Browse files Browse the repository at this point in the history
* add emacs

* rename to elisp

* add elisp to components

* add comment test

* add heading test

* WIP string test

* update string tests

* test symbols in strings

* test arguments

* test quoted symbol

* lisp-property test

* splice test

* add keyword test

* test for declare

* test interactive

* boolean test

* test numbers

* test defvar

* fix greedy defun regex

* test defun

* test lambda

* test car

* test punctuation

* use var instead of const

* remove arrow functions

* flatten language structure

* remove unnecessary escaping

* add lisp and emacs

* add lisp

* fix template strings

* minify lisp

* add example elisp file

* simplify number

* don't mark other def as keywords

* dont mark other def as keyword in defun

* make lambda a keyword only at the beginning

* restore single quotes in components

* double quote in elisp

* minify elisp

* quote keys in components

* rename punctuation test

* add semicolons elisp

* undo prettier changes to components.js

* add lisp to components.json

* rename elisp to lisp

* fix components.json

* add minified lisp file

* rename example lisp file

* move lisp to first position

* explain null initialized properties in lisp file

* remove trailing commas

* put lisp first in example file

* add ifee for lisp file

* update lisp min file

* update show language assets

* add components index min file

* add emacs-lisp alias

* change title of lisp example file

* undo theme change

* combine regex for parens

* remove min index

* remove unneeded example html

* remove doubled string test

* capitalize lisp in components

* change string theme to match master

* build assets after adding lisp
  • Loading branch information
JuanCaicedo authored and Golmote committed Apr 5, 2018
1 parent 689227b commit 46468f8
Show file tree
Hide file tree
Showing 21 changed files with 591 additions and 1 deletion.
2 changes: 1 addition & 1 deletion components.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,11 @@
"title": "Liquid",
"owner": "cinhtau"
},
"lisp": {
"title": "Lisp",
"owner": "JuanCaicedo",
"alias": ["emacs", "elisp", "emacs-lisp"]
},
"livescript": {
"title": "LiveScript",
"owner": "Golmote"
Expand Down
197 changes: 197 additions & 0 deletions components/prism-lisp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
(function (Prism) {
// Functions to construct regular expressions
// simple form
// e.g. (interactive ... or (interactive)
function simple_form(name) {
return new RegExp('(\\()' + name + '(?=[\\s\\)])');
}
// booleans and numbers
function primitive(pattern) {
return new RegExp('([\\s([])' + pattern + '(?=[\\s)])');
}

// Patterns in regular expressions

// Symbol name. See https://www.gnu.org/software/emacs/manual/html_node/elisp/Symbol-Type.html
// & and : are excluded as they are usually used for special purposes
var symbol = '[-+*/_~!@$%^=<>{}\\w]+';
// symbol starting with & used in function arguments
var marker = '&' + symbol;
// Open parenthesis for look-behind
var par = '(\\()';
var endpar = '(?=\\))';
// End the pattern with look-ahead space
var space = '(?=\\s)';

var language = {
// Three or four semicolons are considered a heading.
// See https://www.gnu.org/software/emacs/manual/html_node/elisp/Comment-Tips.html
heading: {
pattern: /;;;.*/,
alias: ['comment', 'title']
},
comment: /;.*/,
string: {
pattern: /"(?:[^"\\]*|\\.)*"/,
greedy: true,
inside: {
argument: /[-A-Z]+(?=[.,\s])/,
symbol: new RegExp('`' + symbol + "'")
}
},
'quoted-symbol': {
pattern: new RegExp("#?'" + symbol),
alias: ['variable', 'symbol']
},
'lisp-property': {
pattern: new RegExp(':' + symbol),
alias: 'property'
},
splice: {
pattern: new RegExp(',@?' + symbol),
alias: ['symbol', 'variable']
},
keyword: [
{
pattern: new RegExp(
par +
'(?:(?:lexical-)?let\\*?|(?:cl-)?letf|if|when|while|unless|cons|cl-loop|and|or|not|cond|setq|error|message|null|require|provide|use-package)' +
space
),
lookbehind: true
},
{
pattern: new RegExp(
par + '(?:for|do|collect|return|finally|append|concat|in|by)' + space
),
lookbehind: true
},
],
declare: {
pattern: simple_form('declare'),
lookbehind: true,
alias: 'keyword'
},
interactive: {
pattern: simple_form('interactive'),
lookbehind: true,
alias: 'keyword'
},
boolean: {
pattern: primitive('(?:t|nil)'),
lookbehind: true
},
number: {
pattern: primitive('[-+]?\\d+(?:\\.\\d*)?'),
lookbehind: true
},
defvar: {
pattern: new RegExp(par + 'def(?:var|const|custom|group)\\s+' + symbol),
lookbehind: true,
inside: {
keyword: /^def[a-z]+/,
variable: new RegExp(symbol)
}
},
defun: {
pattern: new RegExp(
par +
'(?:cl-)?(?:defun\\*?|defmacro)\\s+' +
symbol +
'\\s+\\([\\s\\S]*?\\)'
),
lookbehind: true,
inside: {
keyword: /^(?:cl-)?def\S+/,
// See below, this property needs to be defined later so that it can
// reference the language object.
arguments: null,
function: {
pattern: new RegExp('(^\\s)' + symbol),
lookbehind: true
},
punctuation: /[()]/
}
},
lambda: {
pattern: new RegExp(par + 'lambda\\s+\\((?:&?' + symbol + '\\s*)*\\)'),
lookbehind: true,
inside: {
keyword: /^lambda/,
// See below, this property needs to be defined later so that it can
// reference the language object.
arguments: null,
punctuation: /[()]/
}
},
car: {
pattern: new RegExp(par + symbol),
lookbehind: true
},
punctuation: [
// open paren, brackets, and close paren
/(['`,]?\(|[)\[\]])/,
// cons
{
pattern: /(\s)\.(?=\s)/,
lookbehind: true
},
]
};

var arg = {
'lisp-marker': new RegExp(marker),
rest: {
argument: {
pattern: new RegExp(symbol),
alias: 'variable'
},
varform: {
pattern: new RegExp(par + symbol + '\\s+\\S[\\s\\S]*' + endpar),
lookbehind: true,
inside: {
string: language.string,
boolean: language.boolean,
number: language.number,
symbol: language.symbol,
punctuation: /[()]/
}
}
}
};

var forms = '\\S+(?:\\s+\\S+)*';

var arglist = {
pattern: new RegExp(par + '[\\s\\S]*' + endpar),
lookbehind: true,
inside: {
'rest-vars': {
pattern: new RegExp('&(?:rest|body)\\s+' + forms),
inside: arg
},
'other-marker-vars': {
pattern: new RegExp('&(?:optional|aux)\\s+' + forms),
inside: arg
},
keys: {
pattern: new RegExp('&key\\s+' + forms + '(?:\\s+&allow-other-keys)?'),
inside: arg
},
argument: {
pattern: new RegExp(symbol),
alias: 'variable'
},
punctuation: /[()]/
}
};

language['lambda'].inside.arguments = arglist;
language['defun'].inside.arguments = Prism.util.clone(arglist);
language['defun'].inside.arguments.inside.sublist = arglist;

Prism.languages.lisp = language;
Prism.languages.elisp = language;
Prism.languages.emacs = language;
Prism.languages['emacs-lisp'] = language;
}(Prism));
1 change: 1 addition & 0 deletions components/prism-lisp.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions examples/prism-lisp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<h2>Comments</h2>
<pre><code>;; (foo bar)</code></pre>

<h2>Strings</h2>
<pre><code>(foo "bar")</code></pre>

<h3>With nested symbols</h3>
<pre><code>(foo "A string with a `symbol ")</code></pre>

<h3>With nested arguments</h3>
<pre><code>(foo "A string with an ARGUMENT ")</code></pre>

<h2>Quoted symbols</h2>
<pre><code>(foo #'bar)</code></pre>

<h2>Lisp properties</h2>
<pre><code>(foo :bar)</code></pre>

<h2>Splices</h2>
<pre><code>(foo ,bar ,@bar)</code></pre>

<h2>Keywords</h2>
<pre><code>(let foo (bar arg))</code></pre>

<h2>Declarations</h2>
<pre><code>(declare foo)</code></pre>

<h2>Booleans</h2>
<pre><code>(foo t)</code></pre>
<pre><code>(foo nil)</code></pre>

<h2>Numbers</h2>
<pre><code>(foo 1)</code></pre>
<pre><code>(foo -1.5)</code></pre>

<h2>Definitions</h2>
<pre><code>(defvar bar 23)</code></pre>
<pre><code>(defcustom bar 23)</code></pre>

<h2>Function definitions</h2>
<pre><code>(defun multiply-by-seven (number)
"Multiply NUMBER by seven."
(* 7 number))</code></pre>

<h2>Lambda expressions</h2>
<pre><code>(lambda (number) (* 7 number))</code></pre>
17 changes: 17 additions & 0 deletions tests/languages/lisp/boolean_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
(t)
(nil)
(foo t)
[t ]

----------------------------------------------------

[
["punctuation", "("], ["boolean", "t"], ["punctuation", ")"],
["punctuation", "("], ["boolean", "nil"], ["punctuation", ")"],
["punctuation", "("], ["car", "foo"], ["boolean", "t"], ["punctuation", ")"],
["punctuation", "["], ["boolean", "t"], ["punctuation", "]"]
]

----------------------------------------------------

Checks for booleans.
13 changes: 13 additions & 0 deletions tests/languages/lisp/car_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(foo)
(foo bar)

----------------------------------------------------

[
["punctuation","("], ["car", "foo"], ["punctuation",")"],
["punctuation","("], ["car", "foo"], " bar", ["punctuation",")"]
]

----------------------------------------------------

Checks for car.
11 changes: 11 additions & 0 deletions tests/languages/lisp/comment_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
;; h1

----------------------------------------------------

[
["comment", ";; h1"]
]

----------------------------------------------------

Checks for comments.
16 changes: 16 additions & 0 deletions tests/languages/lisp/declare_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(declare)
(declare a)
(declare
a)

----------------------------------------------------

[
["punctuation", "("], ["declare", "declare"], ["punctuation", ")"],
["punctuation", "("], ["declare", "declare"], " a", ["punctuation", ")"],
["punctuation", "("], ["declare", "declare"], "\r\na", ["punctuation", ")"]
]

----------------------------------------------------

Checks for declare.
27 changes: 27 additions & 0 deletions tests/languages/lisp/defun_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
(defun foo ())
(defun foo (bar))
(defun foo (bar &body arg1) )
(defun foo (bar &rest arg1) )
(defun foo (bar &body arg1 arg2) )
(defun foo (bar &key arg1) )
(defun foo (bar &key arg1 &allow-other-keys) )
(defun foo (&optional arg1) )
(defun defabc ())

----------------------------------------------------

[
["punctuation", "("], ["defun", [ ["keyword", "defun" ], ["function", "foo"], ["punctuation", "("], ["arguments", []], ["punctuation", ")"]]], ["punctuation", ")"],
["punctuation", "("], ["defun", [ ["keyword", "defun" ], ["function", "foo"], ["punctuation", "("], ["arguments", [[ "argument", "bar" ]]], ["punctuation", ")"]]], ["punctuation", ")"],
["punctuation", "("], ["defun", [ ["keyword", "defun" ], ["function", "foo"], ["punctuation", "("], ["arguments", [[ "argument", "bar" ], ["rest-vars", [["lisp-marker", "&body" ], ["argument", "arg1"]]]]], ["punctuation", ")"]] ], ["punctuation", ")"],
["punctuation", "("], ["defun", [ ["keyword", "defun" ], ["function", "foo"], ["punctuation", "("], ["arguments", [[ "argument", "bar" ], ["rest-vars", [["lisp-marker", "&rest" ], ["argument", "arg1"]]]]], ["punctuation", ")"]] ], ["punctuation", ")"],
["punctuation", "("], ["defun", [ ["keyword", "defun" ], ["function", "foo"], ["punctuation", "("], ["arguments", [[ "argument", "bar" ], ["rest-vars", [["lisp-marker", "&body" ], ["argument", "arg1"], ["argument", "arg2"]]]]], ["punctuation", ")"]] ], ["punctuation", ")"],
["punctuation", "("], ["defun", [ ["keyword", "defun" ], ["function", "foo"], ["punctuation", "("], ["arguments", [[ "argument", "bar" ], ["keys", [["lisp-marker", "&key" ], ["argument", "arg1"]]]]], ["punctuation", ")"]] ], ["punctuation", ")"],
["punctuation", "("], ["defun", [ ["keyword", "defun" ], ["function", "foo"], ["punctuation", "("], ["arguments", [[ "argument", "bar" ], ["keys", [["lisp-marker", "&key" ], ["argument", "arg1"], ["lisp-marker", "&allow-other-keys"]]]]], ["punctuation", ")"]] ], ["punctuation", ")"],
["punctuation", "("], ["defun", [ ["keyword", "defun" ], ["function", "foo"], ["punctuation", "("], ["arguments", [["other-marker-vars", [["lisp-marker", "&optional" ], ["argument", "arg1"]]]]], ["punctuation", ")"]] ], ["punctuation", ")"],
["punctuation", "("], ["defun", [ ["keyword", "defun" ], ["function", "defabc"], ["punctuation", "("], ["arguments", []], ["punctuation", ")"]]], ["punctuation", ")"]
]

----------------------------------------------------

Checks for defun.
25 changes: 25 additions & 0 deletions tests/languages/lisp/defvar_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
(defvar foo)
(defvar foo bar)
(defvar foo)
(defvar)
(defconst foo)
(defcustom foo)
(defgroup foo)
(defvar defabc)

----------------------------------------------------

[
["punctuation", "("], ["defvar", [ ["keyword", "defvar" ], ["variable", "foo"] ]], ["punctuation", ")"],
["punctuation", "("], ["defvar", [ ["keyword", "defvar" ], ["variable", "foo"] ]], " bar", ["punctuation", ")"],
["punctuation", "("], ["defvar", [ ["keyword", "defvar" ], ["variable", "foo"] ]], ["punctuation", ")"],
["punctuation", "("], ["car", "defvar"], ["punctuation", ")"],
["punctuation", "("], ["defvar", [ ["keyword", "defconst" ], ["variable", "foo"] ]], ["punctuation", ")"],
["punctuation", "("], ["defvar", [ ["keyword", "defcustom" ], ["variable", "foo"] ]], ["punctuation", ")"],
["punctuation", "("], ["defvar", [ ["keyword", "defgroup" ], ["variable", "foo"] ]], ["punctuation", ")"],
["punctuation", "("], ["defvar", [ ["keyword", "defvar" ], ["variable", "defabc"] ]], ["punctuation", ")"]
]

----------------------------------------------------

Checks for defvar.
11 changes: 11 additions & 0 deletions tests/languages/lisp/heading_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
;;; h1

----------------------------------------------------

[
["heading", ";;; h1"]
]

----------------------------------------------------

Checks for headings.
Loading

0 comments on commit 46468f8

Please sign in to comment.