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.
515 lines
9.3 KiB
515 lines
9.3 KiB
/** |
|
* @param {string} value |
|
* @returns {RegExp} |
|
* */ |
|
|
|
/** |
|
* @param {RegExp | string } re |
|
* @returns {string} |
|
*/ |
|
function source(re) { |
|
if (!re) return null; |
|
if (typeof re === "string") return re; |
|
|
|
return re.source; |
|
} |
|
|
|
/** |
|
* @param {...(RegExp | string) } args |
|
* @returns {string} |
|
*/ |
|
function concat(...args) { |
|
const joined = args.map((x) => source(x)).join(""); |
|
return joined; |
|
} |
|
|
|
/** |
|
* Any of the passed expresssions may match |
|
* |
|
* Creates a huge this | this | that | that match |
|
* @param {(RegExp | string)[] } args |
|
* @returns {string} |
|
*/ |
|
function either(...args) { |
|
const joined = '(' + args.map((x) => source(x)).join("|") + ")"; |
|
return joined; |
|
} |
|
|
|
/* |
|
Language: Perl |
|
Author: Peter Leonov <gojpeg@yandex.ru> |
|
Website: https://www.perl.org |
|
Category: common |
|
*/ |
|
|
|
/** @type LanguageFn */ |
|
function perl(hljs) { |
|
const KEYWORDS = [ |
|
'abs', |
|
'accept', |
|
'alarm', |
|
'and', |
|
'atan2', |
|
'bind', |
|
'binmode', |
|
'bless', |
|
'break', |
|
'caller', |
|
'chdir', |
|
'chmod', |
|
'chomp', |
|
'chop', |
|
'chown', |
|
'chr', |
|
'chroot', |
|
'close', |
|
'closedir', |
|
'connect', |
|
'continue', |
|
'cos', |
|
'crypt', |
|
'dbmclose', |
|
'dbmopen', |
|
'defined', |
|
'delete', |
|
'die', |
|
'do', |
|
'dump', |
|
'each', |
|
'else', |
|
'elsif', |
|
'endgrent', |
|
'endhostent', |
|
'endnetent', |
|
'endprotoent', |
|
'endpwent', |
|
'endservent', |
|
'eof', |
|
'eval', |
|
'exec', |
|
'exists', |
|
'exit', |
|
'exp', |
|
'fcntl', |
|
'fileno', |
|
'flock', |
|
'for', |
|
'foreach', |
|
'fork', |
|
'format', |
|
'formline', |
|
'getc', |
|
'getgrent', |
|
'getgrgid', |
|
'getgrnam', |
|
'gethostbyaddr', |
|
'gethostbyname', |
|
'gethostent', |
|
'getlogin', |
|
'getnetbyaddr', |
|
'getnetbyname', |
|
'getnetent', |
|
'getpeername', |
|
'getpgrp', |
|
'getpriority', |
|
'getprotobyname', |
|
'getprotobynumber', |
|
'getprotoent', |
|
'getpwent', |
|
'getpwnam', |
|
'getpwuid', |
|
'getservbyname', |
|
'getservbyport', |
|
'getservent', |
|
'getsockname', |
|
'getsockopt', |
|
'given', |
|
'glob', |
|
'gmtime', |
|
'goto', |
|
'grep', |
|
'gt', |
|
'hex', |
|
'if', |
|
'index', |
|
'int', |
|
'ioctl', |
|
'join', |
|
'keys', |
|
'kill', |
|
'last', |
|
'lc', |
|
'lcfirst', |
|
'length', |
|
'link', |
|
'listen', |
|
'local', |
|
'localtime', |
|
'log', |
|
'lstat', |
|
'lt', |
|
'ma', |
|
'map', |
|
'mkdir', |
|
'msgctl', |
|
'msgget', |
|
'msgrcv', |
|
'msgsnd', |
|
'my', |
|
'ne', |
|
'next', |
|
'no', |
|
'not', |
|
'oct', |
|
'open', |
|
'opendir', |
|
'or', |
|
'ord', |
|
'our', |
|
'pack', |
|
'package', |
|
'pipe', |
|
'pop', |
|
'pos', |
|
'print', |
|
'printf', |
|
'prototype', |
|
'push', |
|
'q|0', |
|
'qq', |
|
'quotemeta', |
|
'qw', |
|
'qx', |
|
'rand', |
|
'read', |
|
'readdir', |
|
'readline', |
|
'readlink', |
|
'readpipe', |
|
'recv', |
|
'redo', |
|
'ref', |
|
'rename', |
|
'require', |
|
'reset', |
|
'return', |
|
'reverse', |
|
'rewinddir', |
|
'rindex', |
|
'rmdir', |
|
'say', |
|
'scalar', |
|
'seek', |
|
'seekdir', |
|
'select', |
|
'semctl', |
|
'semget', |
|
'semop', |
|
'send', |
|
'setgrent', |
|
'sethostent', |
|
'setnetent', |
|
'setpgrp', |
|
'setpriority', |
|
'setprotoent', |
|
'setpwent', |
|
'setservent', |
|
'setsockopt', |
|
'shift', |
|
'shmctl', |
|
'shmget', |
|
'shmread', |
|
'shmwrite', |
|
'shutdown', |
|
'sin', |
|
'sleep', |
|
'socket', |
|
'socketpair', |
|
'sort', |
|
'splice', |
|
'split', |
|
'sprintf', |
|
'sqrt', |
|
'srand', |
|
'stat', |
|
'state', |
|
'study', |
|
'sub', |
|
'substr', |
|
'symlink', |
|
'syscall', |
|
'sysopen', |
|
'sysread', |
|
'sysseek', |
|
'system', |
|
'syswrite', |
|
'tell', |
|
'telldir', |
|
'tie', |
|
'tied', |
|
'time', |
|
'times', |
|
'tr', |
|
'truncate', |
|
'uc', |
|
'ucfirst', |
|
'umask', |
|
'undef', |
|
'unless', |
|
'unlink', |
|
'unpack', |
|
'unshift', |
|
'untie', |
|
'until', |
|
'use', |
|
'utime', |
|
'values', |
|
'vec', |
|
'wait', |
|
'waitpid', |
|
'wantarray', |
|
'warn', |
|
'when', |
|
'while', |
|
'write', |
|
'x|0', |
|
'xor', |
|
'y|0' |
|
]; |
|
|
|
// https://perldoc.perl.org/perlre#Modifiers |
|
const REGEX_MODIFIERS = /[dualxmsipngr]{0,12}/; // aa and xx are valid, making max length 12 |
|
const PERL_KEYWORDS = { |
|
$pattern: /[\w.]+/, |
|
keyword: KEYWORDS.join(" ") |
|
}; |
|
const SUBST = { |
|
className: 'subst', |
|
begin: '[$@]\\{', |
|
end: '\\}', |
|
keywords: PERL_KEYWORDS |
|
}; |
|
const METHOD = { |
|
begin: /->\{/, |
|
end: /\}/ |
|
// contains defined later |
|
}; |
|
const VAR = { |
|
variants: [ |
|
{ |
|
begin: /\$\d/ |
|
}, |
|
{ |
|
begin: concat( |
|
/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/, |
|
// negative look-ahead tries to avoid matching patterns that are not |
|
// Perl at all like $ident$, @ident@, etc. |
|
`(?![A-Za-z])(?![@$%])` |
|
) |
|
}, |
|
{ |
|
begin: /[$%@][^\s\w{]/, |
|
relevance: 0 |
|
} |
|
] |
|
}; |
|
const STRING_CONTAINS = [ |
|
hljs.BACKSLASH_ESCAPE, |
|
SUBST, |
|
VAR |
|
]; |
|
const REGEX_DELIMS = [ |
|
/!/, |
|
/\//, |
|
/\|/, |
|
/\?/, |
|
/'/, |
|
/"/, // valid but infrequent and weird |
|
/#/ // valid but infrequent and weird |
|
]; |
|
/** |
|
* @param {string|RegExp} prefix |
|
* @param {string|RegExp} open |
|
* @param {string|RegExp} close |
|
*/ |
|
const PAIRED_DOUBLE_RE = (prefix, open, close = '\\1') => { |
|
const middle = (close === '\\1') |
|
? close |
|
: concat(close, open); |
|
return concat( |
|
concat("(?:", prefix, ")"), |
|
open, |
|
/(?:\\.|[^\\\/])*?/, |
|
middle, |
|
/(?:\\.|[^\\\/])*?/, |
|
close, |
|
REGEX_MODIFIERS |
|
); |
|
}; |
|
/** |
|
* @param {string|RegExp} prefix |
|
* @param {string|RegExp} open |
|
* @param {string|RegExp} close |
|
*/ |
|
const PAIRED_RE = (prefix, open, close) => { |
|
return concat( |
|
concat("(?:", prefix, ")"), |
|
open, |
|
/(?:\\.|[^\\\/])*?/, |
|
close, |
|
REGEX_MODIFIERS |
|
); |
|
}; |
|
const PERL_DEFAULT_CONTAINS = [ |
|
VAR, |
|
hljs.HASH_COMMENT_MODE, |
|
hljs.COMMENT( |
|
/^=\w/, |
|
/=cut/, |
|
{ |
|
endsWithParent: true |
|
} |
|
), |
|
METHOD, |
|
{ |
|
className: 'string', |
|
contains: STRING_CONTAINS, |
|
variants: [ |
|
{ |
|
begin: 'q[qwxr]?\\s*\\(', |
|
end: '\\)', |
|
relevance: 5 |
|
}, |
|
{ |
|
begin: 'q[qwxr]?\\s*\\[', |
|
end: '\\]', |
|
relevance: 5 |
|
}, |
|
{ |
|
begin: 'q[qwxr]?\\s*\\{', |
|
end: '\\}', |
|
relevance: 5 |
|
}, |
|
{ |
|
begin: 'q[qwxr]?\\s*\\|', |
|
end: '\\|', |
|
relevance: 5 |
|
}, |
|
{ |
|
begin: 'q[qwxr]?\\s*<', |
|
end: '>', |
|
relevance: 5 |
|
}, |
|
{ |
|
begin: 'qw\\s+q', |
|
end: 'q', |
|
relevance: 5 |
|
}, |
|
{ |
|
begin: '\'', |
|
end: '\'', |
|
contains: [ hljs.BACKSLASH_ESCAPE ] |
|
}, |
|
{ |
|
begin: '"', |
|
end: '"' |
|
}, |
|
{ |
|
begin: '`', |
|
end: '`', |
|
contains: [ hljs.BACKSLASH_ESCAPE ] |
|
}, |
|
{ |
|
begin: /\{\w+\}/, |
|
relevance: 0 |
|
}, |
|
{ |
|
begin: '-?\\w+\\s*=>', |
|
relevance: 0 |
|
} |
|
] |
|
}, |
|
{ |
|
className: 'number', |
|
begin: '(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b', |
|
relevance: 0 |
|
}, |
|
{ // regexp container |
|
begin: '(\\/\\/|' + hljs.RE_STARTERS_RE + '|\\b(split|return|print|reverse|grep)\\b)\\s*', |
|
keywords: 'split return print reverse grep', |
|
relevance: 0, |
|
contains: [ |
|
hljs.HASH_COMMENT_MODE, |
|
{ |
|
className: 'regexp', |
|
variants: [ |
|
// allow matching common delimiters |
|
{ begin: PAIRED_DOUBLE_RE("s|tr|y", either(...REGEX_DELIMS)) }, |
|
// and then paired delmis |
|
{ begin: PAIRED_DOUBLE_RE("s|tr|y", "\\(", "\\)") }, |
|
{ begin: PAIRED_DOUBLE_RE("s|tr|y", "\\[", "\\]") }, |
|
{ begin: PAIRED_DOUBLE_RE("s|tr|y", "\\{", "\\}") } |
|
], |
|
relevance: 2 |
|
}, |
|
{ |
|
className: 'regexp', |
|
variants: [ |
|
{ |
|
// could be a comment in many languages so do not count |
|
// as relevant |
|
begin: /(m|qr)\/\//, |
|
relevance: 0 |
|
}, |
|
// prefix is optional with /regex/ |
|
{ begin: PAIRED_RE("(?:m|qr)?", /\//, /\//)}, |
|
// allow matching common delimiters |
|
{ begin: PAIRED_RE("m|qr", either(...REGEX_DELIMS), /\1/)}, |
|
// allow common paired delmins |
|
{ begin: PAIRED_RE("m|qr", /\(/, /\)/)}, |
|
{ begin: PAIRED_RE("m|qr", /\[/, /\]/)}, |
|
{ begin: PAIRED_RE("m|qr", /\{/, /\}/)} |
|
] |
|
} |
|
] |
|
}, |
|
{ |
|
className: 'function', |
|
beginKeywords: 'sub', |
|
end: '(\\s*\\(.*?\\))?[;{]', |
|
excludeEnd: true, |
|
relevance: 5, |
|
contains: [ hljs.TITLE_MODE ] |
|
}, |
|
{ |
|
begin: '-\\w\\b', |
|
relevance: 0 |
|
}, |
|
{ |
|
begin: "^__DATA__$", |
|
end: "^__END__$", |
|
subLanguage: 'mojolicious', |
|
contains: [ |
|
{ |
|
begin: "^@@.*", |
|
end: "$", |
|
className: "comment" |
|
} |
|
] |
|
} |
|
]; |
|
SUBST.contains = PERL_DEFAULT_CONTAINS; |
|
METHOD.contains = PERL_DEFAULT_CONTAINS; |
|
|
|
return { |
|
name: 'Perl', |
|
aliases: [ |
|
'pl', |
|
'pm' |
|
], |
|
keywords: PERL_KEYWORDS, |
|
contains: PERL_DEFAULT_CONTAINS |
|
}; |
|
} |
|
|
|
module.exports = perl;
|
|
|