perl.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /**
  2. * @param {string} value
  3. * @returns {RegExp}
  4. * */
  5. /**
  6. * @param {RegExp | string } re
  7. * @returns {string}
  8. */
  9. function source(re) {
  10. if (!re) return null;
  11. if (typeof re === "string") return re;
  12. return re.source;
  13. }
  14. /**
  15. * @param {...(RegExp | string) } args
  16. * @returns {string}
  17. */
  18. function concat(...args) {
  19. const joined = args.map((x) => source(x)).join("");
  20. return joined;
  21. }
  22. /*
  23. Language: Perl
  24. Author: Peter Leonov <gojpeg@yandex.ru>
  25. Website: https://www.perl.org
  26. Category: common
  27. */
  28. /** @type LanguageFn */
  29. function perl(hljs) {
  30. // https://perldoc.perl.org/perlre#Modifiers
  31. const REGEX_MODIFIERS = /[dualxmsipn]{0,12}/; // aa and xx are valid, making max length 12
  32. const PERL_KEYWORDS = {
  33. $pattern: /[\w.]+/,
  34. keyword: 'getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ' +
  35. 'ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime ' +
  36. 'readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qq ' +
  37. 'fileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent ' +
  38. 'shutdown dump chomp connect getsockname die socketpair close flock exists index shmget ' +
  39. 'sub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr ' +
  40. 'unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 ' +
  41. 'getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline ' +
  42. 'endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand ' +
  43. 'mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink ' +
  44. 'getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr ' +
  45. 'untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link ' +
  46. 'getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller ' +
  47. 'lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and ' +
  48. 'sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 ' +
  49. 'chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach ' +
  50. 'tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedir ' +
  51. 'ioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe ' +
  52. 'atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when'
  53. };
  54. const SUBST = {
  55. className: 'subst',
  56. begin: '[$@]\\{',
  57. end: '\\}',
  58. keywords: PERL_KEYWORDS
  59. };
  60. const METHOD = {
  61. begin: /->\{/,
  62. end: /\}/
  63. // contains defined later
  64. };
  65. const VAR = {
  66. variants: [
  67. {
  68. begin: /\$\d/
  69. },
  70. {
  71. begin: concat(
  72. /[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,
  73. // negative look-ahead tries to avoid matching patterns that are not
  74. // Perl at all like $ident$, @ident@, etc.
  75. `(?![A-Za-z])(?![@$%])`
  76. )
  77. },
  78. {
  79. begin: /[$%@][^\s\w{]/,
  80. relevance: 0
  81. }
  82. ]
  83. };
  84. const STRING_CONTAINS = [
  85. hljs.BACKSLASH_ESCAPE,
  86. SUBST,
  87. VAR
  88. ];
  89. const PERL_DEFAULT_CONTAINS = [
  90. VAR,
  91. hljs.HASH_COMMENT_MODE,
  92. hljs.COMMENT(
  93. /^=\w/,
  94. /=cut/,
  95. {
  96. endsWithParent: true
  97. }
  98. ),
  99. METHOD,
  100. {
  101. className: 'string',
  102. contains: STRING_CONTAINS,
  103. variants: [
  104. {
  105. begin: 'q[qwxr]?\\s*\\(',
  106. end: '\\)',
  107. relevance: 5
  108. },
  109. {
  110. begin: 'q[qwxr]?\\s*\\[',
  111. end: '\\]',
  112. relevance: 5
  113. },
  114. {
  115. begin: 'q[qwxr]?\\s*\\{',
  116. end: '\\}',
  117. relevance: 5
  118. },
  119. {
  120. begin: 'q[qwxr]?\\s*\\|',
  121. end: '\\|',
  122. relevance: 5
  123. },
  124. {
  125. begin: 'q[qwxr]?\\s*<',
  126. end: '>',
  127. relevance: 5
  128. },
  129. {
  130. begin: 'qw\\s+q',
  131. end: 'q',
  132. relevance: 5
  133. },
  134. {
  135. begin: '\'',
  136. end: '\'',
  137. contains: [ hljs.BACKSLASH_ESCAPE ]
  138. },
  139. {
  140. begin: '"',
  141. end: '"'
  142. },
  143. {
  144. begin: '`',
  145. end: '`',
  146. contains: [ hljs.BACKSLASH_ESCAPE ]
  147. },
  148. {
  149. begin: /\{\w+\}/,
  150. contains: [],
  151. relevance: 0
  152. },
  153. {
  154. begin: '-?\\w+\\s*=>',
  155. contains: [],
  156. relevance: 0
  157. }
  158. ]
  159. },
  160. {
  161. className: 'number',
  162. begin: '(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b',
  163. relevance: 0
  164. },
  165. { // regexp container
  166. begin: '(\\/\\/|' + hljs.RE_STARTERS_RE + '|\\b(split|return|print|reverse|grep)\\b)\\s*',
  167. keywords: 'split return print reverse grep',
  168. relevance: 0,
  169. contains: [
  170. hljs.HASH_COMMENT_MODE,
  171. {
  172. className: 'regexp',
  173. begin: concat(
  174. /(s|tr|y)/,
  175. /\//,
  176. /(\\.|[^\\\/])*/,
  177. /\//,
  178. /(\\.|[^\\\/])*/,
  179. /\//,
  180. REGEX_MODIFIERS
  181. ),
  182. relevance: 10
  183. },
  184. {
  185. className: 'regexp',
  186. begin: /(m|qr)?\//,
  187. end: concat(
  188. /\//,
  189. REGEX_MODIFIERS
  190. ),
  191. contains: [ hljs.BACKSLASH_ESCAPE ],
  192. relevance: 0 // allows empty "//" which is a common comment delimiter in other languages
  193. }
  194. ]
  195. },
  196. {
  197. className: 'function',
  198. beginKeywords: 'sub',
  199. end: '(\\s*\\(.*?\\))?[;{]',
  200. excludeEnd: true,
  201. relevance: 5,
  202. contains: [ hljs.TITLE_MODE ]
  203. },
  204. {
  205. begin: '-\\w\\b',
  206. relevance: 0
  207. },
  208. {
  209. begin: "^__DATA__$",
  210. end: "^__END__$",
  211. subLanguage: 'mojolicious',
  212. contains: [
  213. {
  214. begin: "^@@.*",
  215. end: "$",
  216. className: "comment"
  217. }
  218. ]
  219. }
  220. ];
  221. SUBST.contains = PERL_DEFAULT_CONTAINS;
  222. METHOD.contains = PERL_DEFAULT_CONTAINS;
  223. return {
  224. name: 'Perl',
  225. aliases: [
  226. 'pl',
  227. 'pm'
  228. ],
  229. keywords: PERL_KEYWORDS,
  230. contains: PERL_DEFAULT_CONTAINS
  231. };
  232. }
  233. module.exports = perl;