perl.js 38 KB

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