Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
5.2 KiB

4 years ago
/*
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: []
},
{
begin: /~S"/,
end: /"/,
contains: []
},
{
begin: /~S'''/,
end: /'''/,
contains: []
},
{
begin: /~S'/,
end: /'/,
contains: []
},
{
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;