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.

836 lines
55 KiB

2 months ago
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/5/LICENSE
  3. // CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08)
  4. // This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com)
  5. (function(mod) {
  6. if (typeof exports == "object" && typeof module == "object") // CommonJS
  7. mod(require("../../lib/codemirror"));
  8. else if (typeof define == "function" && define.amd) // AMD
  9. define(["../../lib/codemirror"], mod);
  10. else // Plain browser env
  11. mod(CodeMirror);
  12. })(function(CodeMirror) {
  13. "use strict";
  14. CodeMirror.defineMode("perl",function(){
  15. // http://perldoc.perl.org
  16. var PERL={ // null - magic touch
  17. // 1 - keyword
  18. // 2 - def
  19. // 3 - atom
  20. // 4 - operator
  21. // 5 - variable-2 (predefined)
  22. // [x,y] - x=1,2,3; y=must be defined if x{...}
  23. // PERL operators
  24. '->' : 4,
  25. '++' : 4,
  26. '--' : 4,
  27. '**' : 4,
  28. // ! ~ \ and unary + and -
  29. '=~' : 4,
  30. '!~' : 4,
  31. '*' : 4,
  32. '/' : 4,
  33. '%' : 4,
  34. 'x' : 4,
  35. '+' : 4,
  36. '-' : 4,
  37. '.' : 4,
  38. '<<' : 4,
  39. '>>' : 4,
  40. // named unary operators
  41. '<' : 4,
  42. '>' : 4,
  43. '<=' : 4,
  44. '>=' : 4,
  45. 'lt' : 4,
  46. 'gt' : 4,
  47. 'le' : 4,
  48. 'ge' : 4,
  49. '==' : 4,
  50. '!=' : 4,
  51. '<=>' : 4,
  52. 'eq' : 4,
  53. 'ne' : 4,
  54. 'cmp' : 4,
  55. '~~' : 4,
  56. '&' : 4,
  57. '|' : 4,
  58. '^' : 4,
  59. '&&' : 4,
  60. '||' : 4,
  61. '//' : 4,
  62. '..' : 4,
  63. '...' : 4,
  64. '?' : 4,
  65. ':' : 4,
  66. '=' : 4,
  67. '+=' : 4,
  68. '-=' : 4,
  69. '*=' : 4, // etc. ???
  70. ',' : 4,
  71. '=>' : 4,
  72. '::' : 4,
  73. // list operators (rightward)
  74. 'not' : 4,
  75. 'and' : 4,
  76. 'or' : 4,
  77. 'xor' : 4,
  78. // PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;)
  79. 'BEGIN' : [5,1],
  80. 'END' : [5,1],
  81. 'PRINT' : [5,1],
  82. 'PRINTF' : [5,1],
  83. 'GETC' : [5,1],
  84. 'READ' : [5,1],
  85. 'READLINE' : [5,1],
  86. 'DESTROY' : [5,1],
  87. 'TIE' : [5,1],
  88. 'TIEHANDLE' : [5,1],
  89. 'UNTIE' : [5,1],
  90. 'STDIN' : 5,
  91. 'STDIN_TOP' : 5,
  92. 'STDOUT' : 5,
  93. 'STDOUT_TOP' : 5,
  94. 'STDERR' : 5,
  95. 'STDERR_TOP' : 5,
  96. '$ARG' : 5,
  97. '$_' : 5,
  98. '@ARG' : 5,
  99. '@_' : 5,
  100. '$LIST_SEPARATOR' : 5,
  101. '$"' : 5,
  102. '$PROCESS_ID' : 5,
  103. '$PID' : 5,
  104. '$$' : 5,
  105. '$REAL_GROUP_ID' : 5,
  106. '$GID' : 5,
  107. '$(' : 5,
  108. '$EFFECTIVE_GROUP_ID' : 5,
  109. '$EGID' : 5,
  110. '$)' : 5,
  111. '$PROGRAM_NAME' : 5,
  112. '$0' : 5,
  113. '$SUBSCRIPT_SEPARATOR' : 5,
  114. '$SUBSEP' : 5,
  115. '$;' : 5,
  116. '$REAL_USER_ID' : 5,
  117. '$UID' : 5,
  118. '$<' : 5,
  119. '$EFFECTIVE_USER_ID' : 5,
  120. '$EUID' : 5,
  121. '$>' : 5,
  122. '$a' : 5,
  123. '$b' : 5,
  124. '$COMPILING' : 5,
  125. '$^C' : 5,
  126. '$DEBUGGING' : 5,
  127. '$^D' : 5,
  128. '${^ENCODING}' : 5,
  129. '$ENV' : 5,
  130. '%ENV' : 5,
  131. '$SYSTEM_FD_MAX' : 5,
  132. '$^F' : 5,
  133. '@F' : 5,
  134. '${^GLOBAL_PHASE}' : 5,
  135. '$^H' : 5,
  136. '%^H' : 5,
  137. '@INC' : 5,
  138. '%INC' : 5,
  139. '$INPLACE_EDIT' : 5,
  140. '$^I' : 5,
  141. '$^M' : 5,
  142. '$OSNAME' : 5,
  143. '$^O' : 5,
  144. '${^OPEN}' : 5,
  145. '$PERLDB' : 5,
  146. '$^P' : 5,
  147. '$SIG' : 5,
  148. '%SIG' : 5,
  149. '$BASETIME' : 5,
  150. '$^T' : 5,
  151. '${^TAINT}' : 5,
  152. '${^UNICODE}' : 5,
  153. '${^UTF8CACHE}' : 5,
  154. '${^UTF8LOCALE}' : 5,
  155. '$PERL_VERSION' : 5,
  156. '$^V' : 5,
  157. '${^WIN32_SLOPPY_STAT}' : 5,
  158. '$EXECUTABLE_NAME' : 5,
  159. '$^X' : 5,
  160. '$1' : 5, // - regexp $1, $2...
  161. '$MATCH' : 5,
  162. '$&' : 5,
  163. '${^MATCH}' : 5,
  164. '$PREMATCH' : 5,
  165. '$`' : 5,
  166. '${^PREMATCH}' : 5,
  167. '$POSTMATCH' : 5,
  168. "$'" : 5,
  169. '${^POSTMATCH}' : 5,
  170. '$LAST_PAREN_MATCH' : 5,
  171. '$+' : 5,
  172. '$LAST_SUBMATCH_RESULT' : 5,
  173. '$^N' : 5,
  174. '@LAST_MATCH_END' : 5,
  175. '@+' : 5,
  176. '%LAST_PAREN_MATCH' : 5,
  177. '%+' : 5,
  178. '@LAST_MATCH_START' : 5,
  179. '@-' : 5,
  180. '%LAST_MATCH_START' : 5,
  181. '%-' : 5,
  182. '$LAST_REGEXP_CODE_RESULT' : 5,
  183. '$^R' : 5,
  184. '${^RE_DEBUG_FLAGS}' : 5,
  185. '${^RE_TRIE_MAXBUF}' : 5,
  186. '$ARGV' : 5,
  187. '@ARGV' : 5,
  188. 'ARGV' : 5,
  189. 'ARGVOUT' : 5,
  190. '$OUTPUT_FIELD_SEPARATOR' : 5,
  191. '$OFS' : 5,
  192. '$,' : 5,
  193. '$INPUT_LINE_NUMBER' : 5,
  194. '$NR' : 5,
  195. '$.' : 5,
  196. '$INPUT_RECORD_SEPARATOR' : 5,
  197. '$RS' : 5,
  198. '$/' : 5,
  199. '$OUTPUT_RECORD_SEPARATOR' : 5,
  200. '$ORS' : 5,
  201. '$\\' : 5,
  202. '$OUTPUT_AUTOFLUSH' : 5,
  203. '$|' : 5,
  204. '$ACCUMULATOR' : 5,
  205. '$^A' : 5,
  206. '$FORMAT_FORMFEED' : 5,
  207. '$^L' : 5,
  208. '$FORMAT_PAGE_NUMBER' : 5,
  209. '$%' : 5,
  210. '$FORMAT_LINES_LEFT' : 5,
  211. '$-' : 5,
  212. '$FORMAT_LINE_BREAK_CHARACTERS' : 5,
  213. '$:' : 5,
  214. '$FORMAT_LINES_PER_PAGE' : 5,
  215. '$=' : 5,
  216. '$FORMAT_TOP_NAME' : 5,
  217. '$^' : 5,
  218. '$FORMAT_NAME' : 5,
  219. '$~' : 5,
  220. '${^CHILD_ERROR_NATIVE}' : 5,
  221. '$EXTENDED_OS_ERROR' : 5,
  222. '$^E' : 5,
  223. '$EXCEPTIONS_BEING_CAUGHT' : 5,
  224. '$^S' : 5,
  225. '$WARNING' : 5,
  226. '$^W' : 5,
  227. '${^WARNING_BITS}' : 5,
  228. '$OS_ERROR' : 5,
  229. '$ERRNO' : 5,
  230. '$!' : 5,
  231. '%OS_ERROR' : 5,
  232. '%ERRNO' : 5,
  233. '%!' : 5,
  234. '$CHILD_ERROR' : 5,
  235. '$?' : 5,
  236. '$EVAL_ERROR' : 5,
  237. '$@' : 5,
  238. '$OFMT' : 5,
  239. '$#' : 5,
  240. '$*' : 5,
  241. '$ARRAY_BASE' : 5,
  242. '$[' : 5,
  243. '$OLD_PERL_VERSION' : 5,
  244. '$]' : 5,
  245. // PERL blocks
  246. 'if' :[1,1],
  247. elsif :[1,1],
  248. 'else' :[1,1],
  249. 'while' :[1,1],
  250. unless :[1,1],
  251. 'for' :[1,1],
  252. foreach :[1,1],
  253. // PERL functions
  254. 'abs' :1, // - absolute value function
  255. accept :1, // - accept an incoming socket connect
  256. alarm :1, // - schedule a SIGALRM
  257. 'atan2' :1, // - arctangent of Y/X in the range -PI to PI
  258. bind :1, // - binds an address to a socket
  259. binmode :1, // - prepare binary files for I/O
  260. bless :1, // - create an object
  261. bootstrap :1, //
  262. 'break' :1, // - break out of a "given" block
  263. caller :1, // - get context of the current subroutine call
  264. chdir :1, // - change your current working directory
  265. chmod :1, // - changes the permissions on a list of files
  266. chomp :1, // - remove a trailing record separator from a string
  267. chop :1, // - remove the last character from a string
  268. chown :1, // - change the ownership on a list of files
  269. chr :1, // - get character this number represents
  270. chroot :1, // - make directory new root for path lookups
  271. close :1, // - close file (or pipe or socket) handle
  272. closedir :1, // - close directory handle
  273. connect :1, // - connect to a remote socket
  274. 'continue' :[1,1], // - optional trailing block in a while or foreach
  275. 'cos' :1, // - cosine function
  276. crypt :1, // - one-way passwd-style encryption
  277. dbmclose :1, // - breaks binding on a tied dbm file
  278. dbmopen :1, // - create binding on a tied dbm file
  279. 'default' :1, //
  280. defined :1, // - test whether a value, variable, or function is defined
  281. 'delete' :1, // - deletes a value from a hash
  282. die :1, // - raise an exception or bail out
  283. 'do' :1, // - turn a BLOCK into a TERM
  284. dump :1, // - create an immediate core dump
  285. each :1, // - retrieve the next key/value pair from a hash
  286. endgrent :1, // - be done using group file
  287. endhostent :1, // - be done using hosts file
  288. endnetent :1, // - be done using networks file
  289. endprotoent :1, // - be done using protocols file
  290. endpwent :1, // - be done using passwd file
  291. endservent :1, // - be done using services file
  292. eof :1, // - test a filehandle for its end
  293. 'eval' :1, // - catch exceptions or compile and run code
  294. 'exec' :1, // - abandon this program to run another
  295. exists :1, // - test whether a hash key is present
  296. exit :1, // - terminate this program
  297. 'exp' :1, // - raise I to a power
  298. fcntl :1, // - file control system call
  299. fileno :1, // - return file descriptor from filehandle
  300. flock :1, // - lock an entire file with an advisory lock
  301. fork :1, // - create a new process just like this one
  302. format :1, // - declare a picture format with use by the write() function
  303. formline :1, // - internal function used for formats
  304. getc :1, // - get the next character from the filehandle
  305. getgrent :1, // - get next group record
  306. getgrgid :1, // - get group record given group user ID
  307. getgrnam :1, // - get group record given group name
  308. gethostbyaddr :1, // - get host record given its address
  309. gethostbyname :1, // - get host record given name
  310. gethostent :1, // - get next hosts record
  311. getlogin :1, // - return who logged in at this tty
  312. getnetbyaddr :1, // - get network record given its address
  313. getnetbyname :1, // - get networks record given name
  314. getnetent :1, // - get next networks record
  315. getpeername :1, // - find the other end of a socket connection
  316. getpgrp :1, // - get process group
  317. getppid :1, // - get parent process ID
  318. getpriority :1, // - get current nice value
  319. getprotobyname :1, // - get protocol record given name
  320. getprotobynumber :1, // - get protocol record numeric protocol
  321. getprotoent :1, // - get next protocols record
  322. getpwent :1, // - get next passwd record
  323. getpwnam :1, // - get passwd record given user login name
  324. getpwuid :1, // - get passwd record given user ID
  325. getservbyname :1, // - get services record given its name
  326. getservbyport :1, // - get services record given numeric port
  327. getservent :1, // - get next services record
  328. getsockname :1, // - retrieve the sockaddr for a given socket
  329. getsockopt :1, // - get socket options on a given socket
  330. given :1, //
  331. glob :1, // - expand filenames using wildcards
  332. gmtime :1, // - convert UNIX time into record or string using Greenwich time
  333. 'goto' :1, // - create spaghetti code
  334. grep :1, // - locate elements in a list test true against a given criterion
  335. hex :1, // - convert a string to a hexadecimal number
  336. 'import' :1, // - patch a module's namespace into your own
  337. index :1, // - find a substring within a string
  338. 'int' :1, // - get the integer portion of a number
  339. ioctl :1, // - system-dependent device control system call
  340. 'join' :1, // - join a list into a string using a separator
  341. keys :1, // - retrieve list of indices from a hash
  342. kill :1, // - send a signal to a process or process group
  343. last :1, // - exit a block prematurely
  344. lc :1, // - return lower-case version of a string
  345. lcfirst :1, // - return a string with just the next letter in lower case
  346. length :1, // - return the number of bytes in a string
  347. 'link' :1, // - create a hard link in the filesystem
  348. listen :1, // - register your socket as a server
  349. local : 2, // - create a temporary value for a global variable (dynamic scoping)
  350. localtime :1, // - convert UNIX time into record or string using local time
  351. lock :1, // - get a thread lock on a variable, subroutine, or method
  352. 'log' :1, // - retrieve the natural logarithm for a number
  353. lstat :1, // - stat a symbolic link
  354. m :null, // - match a string with a regular expression pattern
  355. map :1, // - apply a change to a list to get back a new list with the changes
  356. mkdir :1, // - create a directory
  357. msgctl :1, // - SysV IPC message control operations
  358. msgget :1, // - get SysV IPC message queue
  359. msgrcv :1, // - receive a SysV IPC message from a message queue
  360. msgsnd :1, // - send a SysV IPC message to a message queue
  361. my : 2, // - declare and assign a local variable (lexical scoping)
  362. 'new' :1, //
  363. next :1, // - iterate a block prematurely
  364. no :1, // - unimport some module symbols or semantics at compile time
  365. oct :1, // - convert a string to an octal number
  366. open :1, // - open a file, pipe, or descriptor
  367. opendir :1, // - open a directory
  368. ord :1, // - find a character's numeric representation
  369. our : 2, // - declare and assign a package variable (lexical scoping)
  370. pack :1, // - convert a list into a binary representation
  371. 'package' :1, // - declare a separate global namespace
  372. pipe :1, // - open a pair of connected filehandles
  373. pop :1, // - remove the last element from an array and return it
  374. pos :1, // - find or set the offset for the last/next m//g search
  375. print :1, // - output a list to a filehandle
  376. printf :1, // - output a formatted list to a filehandle
  377. prototype :1, // - get the prototype (if any) of a subroutine
  378. push :1, // - append one or more elements to an array
  379. q :null, // - singly quote a string
  380. qq :null, // - doubly quote a string
  381. qr :null, // - Compile pattern
  382. quotemeta :null, // - quote regular expression magic characters
  383. qw :null, // - quote a list of words
  384. qx :null, // - backquote quote a string
  385. rand :1, // - retrieve the next pseudorandom number
  386. read :1, // - fixed-length buffered input from a filehandle
  387. readdir :1, // - get a directory from a directory handle
  388. readline :1, // - fetch a record from a file
  389. readlink :1, // - determine where a symbolic link is pointing
  390. readpipe :1, // - execute a system command and collect standard output
  391. recv :1, // - receive a message over a Socket
  392. redo :1, // - start this loop iteration over again
  393. ref :1, // - find out the type of thing being referenced
  394. rename :1, // - change a filename
  395. require :1, // - load in external functions from a library at runtime
  396. reset :1, // - clear all variables of a given name
  397. 'return' :1, // - get out of a function early
  398. reverse :1, // - flip a string or a list
  399. rewinddir :1, // - reset directory handle
  400. rindex :1, // - right-to-left substring search
  401. rmdir :1, // - remove a directory
  402. s :null, // - replace a pattern with a string
  403. say :1, // - print with newline
  404. scalar :1, // - force a scalar context
  405. seek :1, // - reposition file pointer for random-access I/O
  406. seekdir :1, // - reposition directory pointer
  407. select :1, // - reset default output or do I/O multiplexing
  408. semctl :1, // - SysV semaphore control operations
  409. semget :1, // - get set of SysV semaphores
  410. semop :1, // - SysV semaphore operations
  411. send :1, // - send a message over a socket
  412. setgrent :1, // - prepare group file for use
  413. sethostent :1, // - prepare hosts file for use
  414. setnetent :1, // - prepare networks file for use
  415. setpgrp :1, // - set the process group of a process
  416. setpriority :1, // - set a process's nice value
  417. setprotoent :1, // - prepare protocols file for use
  418. setpwent :1, // - prepare passwd file for use
  419. setservent :1, // - prepare services file for use
  420. setsockopt :1, // - set some socket options
  421. shift :1, // - remove the first element of an array, and return it
  422. shmctl :1, // - SysV shared memory operations
  423. shmget :1, // - get SysV shared memory segment identifier
  424. shmread :1, // - read SysV shared memory
  425. shmwrite :1, // - write SysV shared memory
  426. shutdown :1, // - close down just half of a socket connection
  427. 'sin' :1, // - return the sine of a number
  428. sleep :1, // - block for some number of seconds
  429. socket :1, // - create a socket
  430. socketpair :1, // - create a pair of sockets
  431. 'sort' :1, // - sort a list of values
  432. splice :1, // - add or remove elements anywhere in an array
  433. 'split' :1, // - split up a string using a regexp delimiter
  434. sprintf :1, // - formatted print into a string
  435. 'sqrt' :1, // - square root function
  436. srand :1, // - seed the random number generator
  437. stat :1, // - get a file's status information
  438. state :1, // - declare and assign a state variable (persistent lexical scoping)
  439. study :1, // - optimize input data for repeated searches
  440. 'sub' :1, // - declare a subroutine, possibly anonymously
  441. 'substr' :1, // - get or alter a portion of a string
  442. symlink :1, // - create a symbolic link to a file
  443. syscall :1, // - execute an arbitrary system call
  444. sysopen :1, // - open a file, pipe, or descriptor
  445. sysread :1, // - fixed-length unbuffered input from a filehandle
  446. sysseek :1, // - position I/O pointer on handle used with sysread and syswrite
  447. system :1, // - run a separate program
  448. syswrite :1, // - fixed-length unbuffered output to a filehandle
  449. tell :1, // - get current seekpointer on a filehandle
  450. telldir :1, // - get current seekpointer on a directory handle
  451. tie :1, // - bind a variable to an object class
  452. tied :1, // - get a reference to the object underlying a tied variable
  453. time :1, // - return number of seconds since 1970
  454. times :1, // - return elapsed time for self and child processes
  455. tr :null, // - transliterate a string
  456. truncate :1, // - shorten a file
  457. uc :1, // - return upper-case version of a string
  458. ucfirst :1, // - return a string with just the next letter in upper case
  459. umask :1, // - set file creation mode mask
  460. undef :1, // - remove a variable or function definition
  461. unlink :1, // - remove one link to a file
  462. unpack :1, // - convert binary structure into normal perl variables
  463. unshift :1, // - prepend more elements to the beginning of a list
  464. untie :1, // - break a tie binding to a variable
  465. use :1, // - load in a module at compile time
  466. utime :1, // - set a file's last access and modify times
  467. values :1, // - return a list of the values in a hash
  468. vec :1, // - test or set particular bits in a string
  469. wait :1, // - wait for any child process to die
  470. waitpid :1, // - wait for a particular child process to die
  471. wantarray :1, // - get void vs scalar vs list context of current subroutine call
  472. warn :1, // - print debugging info
  473. when :1, //
  474. write :1, // - print a picture record
  475. y :null}; // - transliterate a string
  476. var RXstyle="string-2";
  477. var RXmodifiers=/[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type
  478. function tokenChain(stream,state,chain,style,tail){ // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;)
  479. state.chain=null; // 12 3tail
  480. state.style=null;
  481. state.tail=null;
  482. state.tokenize=function(stream,state){
  483. var e=false,c,i=0;
  484. while(c=stream.next()){
  485. if(c===chain[i]&&!e){
  486. if(chain[++i]!==undefined){
  487. state.chain=chain[i];
  488. state.style=style;
  489. state.tail=tail;}
  490. else if(tail)
  491. stream.eatWhile(tail);
  492. state.tokenize=tokenPerl;
  493. return style;}
  494. e=!e&&c=="\\";}
  495. return style;};
  496. return state.tokenize(stream,state);}
  497. function tokenSOMETHING(stream,state,string){
  498. state.tokenize=function(stream,state){
  499. if(stream.string==string)
  500. state.tokenize=tokenPerl;
  501. stream.skipToEnd();
  502. return "string";};
  503. return state.tokenize(stream,state);}
  504. function tokenPerl(stream,state){
  505. if(stream.eatSpace())
  506. return null;
  507. if(state.chain)
  508. return tokenChain(stream,state,state.chain,state.style,state.tail);
  509. if(stream.match(/^(\-?((\d[\d_]*)?\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F_]+|0b[01_]+|\d[\d_]*(e[+-]?\d+)?)/))
  510. return 'number';
  511. if(stream.match(/^<<(?=[_a-zA-Z])/)){ // NOTE: <<SOMETHING\n...\nSOMETHING\n
  512. stream.eatWhile(/\w/);
  513. return tokenSOMETHING(stream,state,stream.current().substr(2));}
  514. if(stream.sol()&&stream.match(/^\=item(?!\w)/)){// NOTE: \n=item...\n=cut\n
  515. return tokenSOMETHING(stream,state,'=cut');}
  516. var ch=stream.next();
  517. if(ch=='"'||ch=="'"){ // NOTE: ' or " or <<'SOMETHING'\n...\nSOMETHING\n or <<"SOMETHING"\n...\nSOMETHING\n
  518. if(prefix(stream, 3)=="<<"+ch){
  519. var p=stream.pos;
  520. stream.eatWhile(/\w/);
  521. var n=stream.current().substr(1);
  522. if(n&&stream.eat(ch))
  523. return tokenSOMETHING(stream,state,n);
  524. stream.pos=p;}
  525. return tokenChain(stream,state,[ch],"string");}
  526. if(ch=="q"){
  527. var c=look(stream, -2);
  528. if(!(c&&/\w/.test(c))){
  529. c=look(stream, 0);
  530. if(c=="x"){
  531. c=look(stream, 1);
  532. if(c=="("){
  533. eatSuffix(stream, 2);
  534. return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
  535. if(c=="["){
  536. eatSuffix(stream, 2);
  537. return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
  538. if(c=="{"){
  539. eatSuffix(stream, 2);
  540. return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
  541. if(c=="<"){
  542. eatSuffix(stream, 2);
  543. return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}
  544. if(/[\^'"!~\/]/.test(c)){
  545. eatSuffix(stream, 1);
  546. return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}
  547. else if(c=="q"){
  548. c=look(stream, 1);
  549. if(c=="("){
  550. eatSuffix(stream, 2);
  551. return tokenChain(stream,state,[")"],"string");}
  552. if(c=="["){
  553. eatSuffix(stream, 2);
  554. return tokenChain(stream,state,["]"],"string");}
  555. if(c=="{"){
  556. eatSuffix(stream, 2);
  557. return tokenChain(stream,state,["}"],"string");}
  558. if(c=="<"){
  559. eatSuffix(stream, 2);
  560. return tokenChain(stream,state,[">"],"string");}
  561. if(/[\^'"!~\/]/.test(c)){
  562. eatSuffix(stream, 1);
  563. return tokenChain(stream,state,[stream.eat(c)],"string");}}
  564. else if(c=="w"){
  565. c=look(stream, 1);
  566. if(c=="("){
  567. eatSuffix(stream, 2);
  568. return tokenChain(stream,state,[")"],"bracket");}
  569. if(c=="["){
  570. eatSuffix(stream, 2);
  571. return tokenChain(stream,state,["]"],"bracket");}
  572. if(c=="{"){
  573. eatSuffix(stream, 2);
  574. return tokenChain(stream,state,["}"],"bracket");}
  575. if(c=="<"){
  576. eatSuffix(stream, 2);
  577. return tokenChain(stream,state,[">"],"bracket");}
  578. if(/[\^'"!~\/]/.test(c)){
  579. eatSuffix(stream, 1);
  580. return tokenChain(stream,state,[stream.eat(c)],"bracket");}}
  581. else if(c=="r"){
  582. c=look(stream, 1);
  583. if(c=="("){
  584. eatSuffix(stream, 2);
  585. return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
  586. if(c=="["){
  587. eatSuffix(stream, 2);
  588. return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
  589. if(c=="{"){
  590. eatSuffix(stream, 2);
  591. return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
  592. if(c=="<"){
  593. eatSuffix(stream, 2);
  594. return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}
  595. if(/[\^'"!~\/]/.test(c)){
  596. eatSuffix(stream, 1);
  597. return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}
  598. else if(/[\^'"!~\/(\[{<]/.test(c)){
  599. if(c=="("){
  600. eatSuffix(stream, 1);
  601. return tokenChain(stream,state,[")"],"string");}
  602. if(c=="["){
  603. eatSuffix(stream, 1);
  604. return tokenChain(stream,state,["]"],"string");}
  605. if(c=="{"){
  606. eatSuffix(stream, 1);
  607. return tokenChain(stream,state,["}"],"string");}
  608. if(c=="<"){
  609. eatSuffix(stream, 1);
  610. return tokenChain(stream,state,[">"],"string");}
  611. if(/[\^'"!~\/]/.test(c)){
  612. return tokenChain(stream,state,[stream.eat(c)],"string");}}}}
  613. if(ch=="m"){
  614. var c=look(stream, -2);
  615. if(!(c&&/\w/.test(c))){
  616. c=stream.eat(/[(\[{<\^'"!~\/]/);
  617. if(c){
  618. if(/[\^'"!~\/]/.test(c)){
  619. return tokenChain(stream,state,[c],RXstyle,RXmodifiers);}
  620. if(c=="("){
  621. return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
  622. if(c=="["){
  623. return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
  624. if(c=="{"){
  625. return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
  626. if(c=="<"){
  627. return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}}}}
  628. if(ch=="s"){
  629. var c=/[\/>\]})\w]/.test(look(stream, -2));
  630. if(!c){
  631. c=stream.eat(/[(\[{<\^'"!~\/]/);
  632. if(c){
  633. if(c=="[")
  634. return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
  635. if(c=="{")
  636. return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
  637. if(c=="<")
  638. return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
  639. if(c=="(")
  640. return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
  641. return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}
  642. if(ch=="y"){
  643. var c=/[\/>\]})\w]/.test(look(stream, -2));
  644. if(!c){
  645. c=stream.eat(/[(\[{<\^'"!~\/]/);
  646. if(c){
  647. if(c=="[")
  648. return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
  649. if(c=="{")
  650. return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
  651. if(c=="<")
  652. return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
  653. if(c=="(")
  654. return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
  655. return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}
  656. if(ch=="t"){
  657. var c=/[\/>\]})\w]/.test(look(stream, -2));
  658. if(!c){
  659. c=stream.eat("r");if(c){
  660. c=stream.eat(/[(\[{<\^'"!~\/]/);
  661. if(c){
  662. if(c=="[")
  663. return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
  664. if(c=="{")
  665. return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
  666. if(c=="<")
  667. return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
  668. if(c=="(")
  669. return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
  670. return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}}
  671. if(ch=="`"){
  672. return tokenChain(stream,state,[ch],"variable-2");}
  673. if(ch=="/"){
  674. if(!/~\s*$/.test(prefix(stream)))
  675. return "operator";
  676. else
  677. return tokenChain(stream,state,[ch],RXstyle,RXmodifiers);}
  678. if(ch=="$"){
  679. var p=stream.pos;
  680. if(stream.eatWhile(/\d/)||stream.eat("{")&&stream.eatWhile(/\d/)&&stream.eat("}"))
  681. return "variable-2";
  682. else
  683. stream.pos=p;}
  684. if(/[$@%]/.test(ch)){
  685. var p=stream.pos;
  686. if(stream.eat("^")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(look(stream, -2))&&stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){
  687. var c=stream.current();
  688. if(PERL[c])
  689. return "variable-2";}
  690. stream.pos=p;}
  691. if(/[$@%&]/.test(ch)){
  692. if(stream.eatWhile(/[\w$]/)||stream.eat("{")&&stream.eatWhile(/[\w$]/)&&stream.eat("}")){
  693. var c=stream.current();
  694. if(PERL[c])
  695. return "variable-2";
  696. else
  697. return "variable";}}
  698. if(ch=="#"){
  699. if(look(stream, -2)!="$"){
  700. stream.skipToEnd();
  701. return "comment";}}
  702. if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)){
  703. var p=stream.pos;
  704. stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/);
  705. if(PERL[stream.current()])
  706. return "operator";
  707. else
  708. stream.pos=p;}
  709. if(ch=="_"){
  710. if(stream.pos==1){
  711. if(suffix(stream, 6)=="_END__"){
  712. return tokenChain(stream,state,['\0'],"comment");}
  713. else if(suffix(stream, 7)=="_DATA__"){
  714. return tokenChain(stream,state,['\0'],"variable-2");}
  715. else if(suffix(stream, 7)=="_C__"){
  716. return tokenChain(stream,state,['\0'],"string");}}}
  717. if(/\w/.test(ch)){
  718. var p=stream.pos;
  719. if(look(stream, -2)=="{"&&(look(stream, 0)=="}"||stream.eatWhile(/\w/)&&look(stream, 0)=="}"))
  720. return "string";
  721. else
  722. stream.pos=p;}
  723. if(/[A-Z]/.test(ch)){
  724. var l=look(stream, -2);
  725. var p=stream.pos;
  726. stream.eatWhile(/[A-Z_]/);
  727. if(/[\da-z]/.test(look(stream, 0))){
  728. stream.pos=p;}
  729. else{
  730. var c=PERL[stream.current()];
  731. if(!c)
  732. return "meta";
  733. if(c[1])
  734. c=c[0];
  735. if(l!=":"){
  736. if(c==1)
  737. return "keyword";
  738. else if(c==2)
  739. return "def";
  740. else if(c==3)
  741. return "atom";
  742. else if(c==4)
  743. return "operator";
  744. else if(c==5)
  745. return "variable-2";
  746. else
  747. return "meta";}
  748. else
  749. return "meta";}}
  750. if(/[a-zA-Z_]/.test(ch)){
  751. var l=look(stream, -2);
  752. stream.eatWhile(/\w/);
  753. var c=PERL[stream.current()];
  754. if(!c)
  755. return "meta";
  756. if(c[1])
  757. c=c[0];
  758. if(l!=":"){
  759. if(c==1)
  760. return "keyword";
  761. else if(c==2)
  762. return "def";
  763. else if(c==3)
  764. return "atom";
  765. else if(c==4)
  766. return "operator";
  767. else if(c==5)
  768. return "variable-2";
  769. else
  770. return "meta";}
  771. else
  772. return "meta";}
  773. return null;}
  774. return {
  775. startState: function() {
  776. return {
  777. tokenize: tokenPerl,
  778. chain: null,
  779. style: null,
  780. tail: null
  781. };
  782. },
  783. token: function(stream, state) {
  784. return (state.tokenize || tokenPerl)(stream, state);
  785. },
  786. lineComment: '#'
  787. };
  788. });
  789. CodeMirror.registerHelper("wordChars", "perl", /[\w$]/);
  790. CodeMirror.defineMIME("text/x-perl", "perl");
  791. // it's like "peek", but need for look-ahead or look-behind if index < 0
  792. function look(stream, c){
  793. return stream.string.charAt(stream.pos+(c||0));
  794. }
  795. // return a part of prefix of current stream from current position
  796. function prefix(stream, c){
  797. if(c){
  798. var x=stream.pos-c;
  799. return stream.string.substr((x>=0?x:0),c);}
  800. else{
  801. return stream.string.substr(0,stream.pos-1);
  802. }
  803. }
  804. // return a part of suffix of current stream from current position
  805. function suffix(stream, c){
  806. var y=stream.string.length;
  807. var x=y-stream.pos+1;
  808. return stream.string.substr(stream.pos,(c&&c<y?c:x));
  809. }
  810. // eating and vomiting a part of stream from current position
  811. function eatSuffix(stream, c){
  812. var x=stream.pos+c;
  813. var y;
  814. if(x<=0)
  815. stream.pos=0;
  816. else if(x>=(y=stream.string.length-1))
  817. stream.pos=y;
  818. else
  819. stream.pos=x;
  820. }
  821. });