260 lines
5.3 KiB
JavaScript
260 lines
5.3 KiB
JavaScript
|
/*
|
||
|
Language: Elixir
|
||
|
Author: Josh Adams <josh@isotope11.com>
|
||
|
Description: language definition for Elixir source code files (.ex and .exs). Based on ruby language support.
|
||
|
Category: functional
|
||
|
Website: https://elixir-lang.org
|
||
|
*/
|
||
|
|
||
|
/** @type LanguageFn */
|
||
|
function elixir(hljs) {
|
||
|
const ELIXIR_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9_.]*(!|\\?)?';
|
||
|
const ELIXIR_METHOD_RE = '[a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?';
|
||
|
const ELIXIR_KEYWORDS = {
|
||
|
$pattern: ELIXIR_IDENT_RE,
|
||
|
keyword: 'and false then defined module in return redo retry end for true self when ' +
|
||
|
'next until do begin unless nil break not case cond alias while ensure or ' +
|
||
|
'include use alias fn quote require import with|0'
|
||
|
};
|
||
|
const SUBST = {
|
||
|
className: 'subst',
|
||
|
begin: /#\{/,
|
||
|
end: /\}/,
|
||
|
keywords: ELIXIR_KEYWORDS
|
||
|
};
|
||
|
const NUMBER = {
|
||
|
className: 'number',
|
||
|
begin: '(\\b0o[0-7_]+)|(\\b0b[01_]+)|(\\b0x[0-9a-fA-F_]+)|(-?\\b[1-9][0-9_]*(\\.[0-9_]+([eE][-+]?[0-9]+)?)?)',
|
||
|
relevance: 0
|
||
|
};
|
||
|
const SIGIL_DELIMITERS = '[/|([{<"\']';
|
||
|
const LOWERCASE_SIGIL = {
|
||
|
className: 'string',
|
||
|
begin: '~[a-z]' + '(?=' + SIGIL_DELIMITERS + ')',
|
||
|
contains: [
|
||
|
{
|
||
|
endsParent: true,
|
||
|
contains: [
|
||
|
{
|
||
|
contains: [
|
||
|
hljs.BACKSLASH_ESCAPE,
|
||
|
SUBST
|
||
|
],
|
||
|
variants: [
|
||
|
{
|
||
|
begin: /"/,
|
||
|
end: /"/
|
||
|
},
|
||
|
{
|
||
|
begin: /'/,
|
||
|
end: /'/
|
||
|
},
|
||
|
{
|
||
|
begin: /\//,
|
||
|
end: /\//
|
||
|
},
|
||
|
{
|
||
|
begin: /\|/,
|
||
|
end: /\|/
|
||
|
},
|
||
|
{
|
||
|
begin: /\(/,
|
||
|
end: /\)/
|
||
|
},
|
||
|
{
|
||
|
begin: /\[/,
|
||
|
end: /\]/
|
||
|
},
|
||
|
{
|
||
|
begin: /\{/,
|
||
|
end: /\}/
|
||
|
},
|
||
|
{
|
||
|
begin: /</,
|
||
|
end: />/
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
};
|
||
|
|
||
|
const UPCASE_SIGIL = {
|
||
|
className: 'string',
|
||
|
begin: '~[A-Z]' + '(?=' + SIGIL_DELIMITERS + ')',
|
||
|
contains: [
|
||
|
{
|
||
|
begin: /"/,
|
||
|
end: /"/
|
||
|
},
|
||
|
{
|
||
|
begin: /'/,
|
||
|
end: /'/
|
||
|
},
|
||
|
{
|
||
|
begin: /\//,
|
||
|
end: /\//
|
||
|
},
|
||
|
{
|
||
|
begin: /\|/,
|
||
|
end: /\|/
|
||
|
},
|
||
|
{
|
||
|
begin: /\(/,
|
||
|
end: /\)/
|
||
|
},
|
||
|
{
|
||
|
begin: /\[/,
|
||
|
end: /\]/
|
||
|
},
|
||
|
{
|
||
|
begin: /\{/,
|
||
|
end: /\}/
|
||
|
},
|
||
|
{
|
||
|
begin: /</,
|
||
|
end: />/
|
||
|
}
|
||
|
]
|
||
|
};
|
||
|
|
||
|
const STRING = {
|
||
|
className: 'string',
|
||
|
contains: [
|
||
|
hljs.BACKSLASH_ESCAPE,
|
||
|
SUBST
|
||
|
],
|
||
|
variants: [
|
||
|
{
|
||
|
begin: /"""/,
|
||
|
end: /"""/
|
||
|
},
|
||
|
{
|
||
|
begin: /'''/,
|
||
|
end: /'''/
|
||
|
},
|
||
|
{
|
||
|
begin: /~S"""/,
|
||
|
end: /"""/,
|
||
|
contains: [] // override default
|
||
|
},
|
||
|
{
|
||
|
begin: /~S"/,
|
||
|
end: /"/,
|
||
|
contains: [] // override default
|
||
|
},
|
||
|
{
|
||
|
begin: /~S'''/,
|
||
|
end: /'''/,
|
||
|
contains: [] // override default
|
||
|
},
|
||
|
{
|
||
|
begin: /~S'/,
|
||
|
end: /'/,
|
||
|
contains: [] // override default
|
||
|
},
|
||
|
{
|
||
|
begin: /'/,
|
||
|
end: /'/
|
||
|
},
|
||
|
{
|
||
|
begin: /"/,
|
||
|
end: /"/
|
||
|
}
|
||
|
]
|
||
|
};
|
||
|
const FUNCTION = {
|
||
|
className: 'function',
|
||
|
beginKeywords: 'def defp defmacro',
|
||
|
end: /\B\b/, // the mode is ended by the title
|
||
|
contains: [
|
||
|
hljs.inherit(hljs.TITLE_MODE, {
|
||
|
begin: ELIXIR_IDENT_RE,
|
||
|
endsParent: true
|
||
|
})
|
||
|
]
|
||
|
};
|
||
|
const CLASS = hljs.inherit(FUNCTION, {
|
||
|
className: 'class',
|
||
|
beginKeywords: 'defimpl defmodule defprotocol defrecord',
|
||
|
end: /\bdo\b|$|;/
|
||
|
});
|
||
|
const ELIXIR_DEFAULT_CONTAINS = [
|
||
|
STRING,
|
||
|
UPCASE_SIGIL,
|
||
|
LOWERCASE_SIGIL,
|
||
|
hljs.HASH_COMMENT_MODE,
|
||
|
CLASS,
|
||
|
FUNCTION,
|
||
|
{
|
||
|
begin: '::'
|
||
|
},
|
||
|
{
|
||
|
className: 'symbol',
|
||
|
begin: ':(?![\\s:])',
|
||
|
contains: [
|
||
|
STRING,
|
||
|
{
|
||
|
begin: ELIXIR_METHOD_RE
|
||
|
}
|
||
|
],
|
||
|
relevance: 0
|
||
|
},
|
||
|
{
|
||
|
className: 'symbol',
|
||
|
begin: ELIXIR_IDENT_RE + ':(?!:)',
|
||
|
relevance: 0
|
||
|
},
|
||
|
NUMBER,
|
||
|
{
|
||
|
className: 'variable',
|
||
|
begin: '(\\$\\W)|((\\$|@@?)(\\w+))'
|
||
|
},
|
||
|
{
|
||
|
begin: '->'
|
||
|
},
|
||
|
{ // regexp container
|
||
|
begin: '(' + hljs.RE_STARTERS_RE + ')\\s*',
|
||
|
contains: [
|
||
|
hljs.HASH_COMMENT_MODE,
|
||
|
{
|
||
|
// to prevent false regex triggers for the division function:
|
||
|
// /:
|
||
|
begin: /\/: (?=\d+\s*[,\]])/,
|
||
|
relevance: 0,
|
||
|
contains: [NUMBER]
|
||
|
},
|
||
|
{
|
||
|
className: 'regexp',
|
||
|
illegal: '\\n',
|
||
|
contains: [
|
||
|
hljs.BACKSLASH_ESCAPE,
|
||
|
SUBST
|
||
|
],
|
||
|
variants: [
|
||
|
{
|
||
|
begin: '/',
|
||
|
end: '/[a-z]*'
|
||
|
},
|
||
|
{
|
||
|
begin: '%r\\[',
|
||
|
end: '\\][a-z]*'
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
relevance: 0
|
||
|
}
|
||
|
];
|
||
|
SUBST.contains = ELIXIR_DEFAULT_CONTAINS;
|
||
|
|
||
|
return {
|
||
|
name: 'Elixir',
|
||
|
keywords: ELIXIR_KEYWORDS,
|
||
|
contains: ELIXIR_DEFAULT_CONTAINS
|
||
|
};
|
||
|
}
|
||
|
|
||
|
module.exports = elixir;
|