1 // CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08)
2 // This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com)
3 CodeMirror.defineMode("perl",function(){
4 // http://perldoc.perl.org
5 var PERL={ // null - magic touch
10 // 5 - variable-2 (predefined)
11 // [x,y] - x=1,2,3; y=must be defined if x{...}
17 // ! ~ \ and unary + and -
29 // named unary operators
62 // list operators (rightward)
67 // 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?;)
89 '$LIST_SEPARATOR' : 5,
97 '$EFFECTIVE_GROUP_ID' : 5,
102 '$SUBSCRIPT_SEPARATOR' : 5,
108 '$EFFECTIVE_USER_ID' : 5,
120 '$SYSTEM_FD_MAX' : 5,
123 '${^GLOBAL_PHASE}' : 5,
143 '${^UTF8LOCALE}' : 5,
146 '${^WIN32_SLOPPY_STAT}' : 5,
147 '$EXECUTABLE_NAME' : 5,
149 '$1' : 5, // - regexp $1, $2...
159 '$LAST_PAREN_MATCH' : 5,
161 '$LAST_SUBMATCH_RESULT' : 5,
163 '@LAST_MATCH_END' : 5,
165 '%LAST_PAREN_MATCH' : 5,
167 '@LAST_MATCH_START' : 5,
169 '%LAST_MATCH_START' : 5,
171 '$LAST_REGEXP_CODE_RESULT' : 5,
173 '${^RE_DEBUG_FLAGS}' : 5,
174 '${^RE_TRIE_MAXBUF}' : 5,
179 '$OUTPUT_FIELD_SEPARATOR' : 5,
182 '$INPUT_LINE_NUMBER' : 5,
185 '$INPUT_RECORD_SEPARATOR' : 5,
188 '$OUTPUT_RECORD_SEPARATOR' : 5,
191 '$OUTPUT_AUTOFLUSH' : 5,
195 '$FORMAT_FORMFEED' : 5,
197 '$FORMAT_PAGE_NUMBER' : 5,
199 '$FORMAT_LINES_LEFT' : 5,
201 '$FORMAT_LINE_BREAK_CHARACTERS' : 5,
203 '$FORMAT_LINES_PER_PAGE' : 5,
205 '$FORMAT_TOP_NAME' : 5,
209 '${^CHILD_ERROR_NATIVE}' : 5,
210 '$EXTENDED_OS_ERROR' : 5,
212 '$EXCEPTIONS_BEING_CAUGHT' : 5,
216 '${^WARNING_BITS}' : 5,
232 '$OLD_PERL_VERSION' : 5,
243 'abs' :1, // - absolute value function
244 accept :1, // - accept an incoming socket connect
245 alarm :1, // - schedule a SIGALRM
246 'atan2' :1, // - arctangent of Y/X in the range -PI to PI
247 bind :1, // - binds an address to a socket
248 binmode :1, // - prepare binary files for I/O
249 bless :1, // - create an object
251 'break' :1, // - break out of a "given" block
252 caller :1, // - get context of the current subroutine call
253 chdir :1, // - change your current working directory
254 chmod :1, // - changes the permissions on a list of files
255 chomp :1, // - remove a trailing record separator from a string
256 chop :1, // - remove the last character from a string
257 chown :1, // - change the owership on a list of files
258 chr :1, // - get character this number represents
259 chroot :1, // - make directory new root for path lookups
260 close :1, // - close file (or pipe or socket) handle
261 closedir :1, // - close directory handle
262 connect :1, // - connect to a remote socket
263 'continue' :[1,1], // - optional trailing block in a while or foreach
264 'cos' :1, // - cosine function
265 crypt :1, // - one-way passwd-style encryption
266 dbmclose :1, // - breaks binding on a tied dbm file
267 dbmopen :1, // - create binding on a tied dbm file
269 defined :1, // - test whether a value, variable, or function is defined
270 'delete' :1, // - deletes a value from a hash
271 die :1, // - raise an exception or bail out
272 'do' :1, // - turn a BLOCK into a TERM
273 dump :1, // - create an immediate core dump
274 each :1, // - retrieve the next key/value pair from a hash
275 endgrent :1, // - be done using group file
276 endhostent :1, // - be done using hosts file
277 endnetent :1, // - be done using networks file
278 endprotoent :1, // - be done using protocols file
279 endpwent :1, // - be done using passwd file
280 endservent :1, // - be done using services file
281 eof :1, // - test a filehandle for its end
282 'eval' :1, // - catch exceptions or compile and run code
283 'exec' :1, // - abandon this program to run another
284 exists :1, // - test whether a hash key is present
285 exit :1, // - terminate this program
286 'exp' :1, // - raise I to a power
287 fcntl :1, // - file control system call
288 fileno :1, // - return file descriptor from filehandle
289 flock :1, // - lock an entire file with an advisory lock
290 fork :1, // - create a new process just like this one
291 format :1, // - declare a picture format with use by the write() function
292 formline :1, // - internal function used for formats
293 getc :1, // - get the next character from the filehandle
294 getgrent :1, // - get next group record
295 getgrgid :1, // - get group record given group user ID
296 getgrnam :1, // - get group record given group name
297 gethostbyaddr :1, // - get host record given its address
298 gethostbyname :1, // - get host record given name
299 gethostent :1, // - get next hosts record
300 getlogin :1, // - return who logged in at this tty
301 getnetbyaddr :1, // - get network record given its address
302 getnetbyname :1, // - get networks record given name
303 getnetent :1, // - get next networks record
304 getpeername :1, // - find the other end of a socket connection
305 getpgrp :1, // - get process group
306 getppid :1, // - get parent process ID
307 getpriority :1, // - get current nice value
308 getprotobyname :1, // - get protocol record given name
309 getprotobynumber :1, // - get protocol record numeric protocol
310 getprotoent :1, // - get next protocols record
311 getpwent :1, // - get next passwd record
312 getpwnam :1, // - get passwd record given user login name
313 getpwuid :1, // - get passwd record given user ID
314 getservbyname :1, // - get services record given its name
315 getservbyport :1, // - get services record given numeric port
316 getservent :1, // - get next services record
317 getsockname :1, // - retrieve the sockaddr for a given socket
318 getsockopt :1, // - get socket options on a given socket
320 glob :1, // - expand filenames using wildcards
321 gmtime :1, // - convert UNIX time into record or string using Greenwich time
322 'goto' :1, // - create spaghetti code
323 grep :1, // - locate elements in a list test true against a given criterion
324 hex :1, // - convert a string to a hexadecimal number
325 'import' :1, // - patch a module's namespace into your own
326 index :1, // - find a substring within a string
327 'int' :1, // - get the integer portion of a number
328 ioctl :1, // - system-dependent device control system call
329 'join' :1, // - join a list into a string using a separator
330 keys :1, // - retrieve list of indices from a hash
331 kill :1, // - send a signal to a process or process group
332 last :1, // - exit a block prematurely
333 lc :1, // - return lower-case version of a string
334 lcfirst :1, // - return a string with just the next letter in lower case
335 length :1, // - return the number of bytes in a string
336 'link' :1, // - create a hard link in the filesytem
337 listen :1, // - register your socket as a server
338 local : 2, // - create a temporary value for a global variable (dynamic scoping)
339 localtime :1, // - convert UNIX time into record or string using local time
340 lock :1, // - get a thread lock on a variable, subroutine, or method
341 'log' :1, // - retrieve the natural logarithm for a number
342 lstat :1, // - stat a symbolic link
343 m :null, // - match a string with a regular expression pattern
344 map :1, // - apply a change to a list to get back a new list with the changes
345 mkdir :1, // - create a directory
346 msgctl :1, // - SysV IPC message control operations
347 msgget :1, // - get SysV IPC message queue
348 msgrcv :1, // - receive a SysV IPC message from a message queue
349 msgsnd :1, // - send a SysV IPC message to a message queue
350 my : 2, // - declare and assign a local variable (lexical scoping)
352 next :1, // - iterate a block prematurely
353 no :1, // - unimport some module symbols or semantics at compile time
354 oct :1, // - convert a string to an octal number
355 open :1, // - open a file, pipe, or descriptor
356 opendir :1, // - open a directory
357 ord :1, // - find a character's numeric representation
358 our : 2, // - declare and assign a package variable (lexical scoping)
359 pack :1, // - convert a list into a binary representation
360 'package' :1, // - declare a separate global namespace
361 pipe :1, // - open a pair of connected filehandles
362 pop :1, // - remove the last element from an array and return it
363 pos :1, // - find or set the offset for the last/next m//g search
364 print :1, // - output a list to a filehandle
365 printf :1, // - output a formatted list to a filehandle
366 prototype :1, // - get the prototype (if any) of a subroutine
367 push :1, // - append one or more elements to an array
368 q :null, // - singly quote a string
369 qq :null, // - doubly quote a string
370 qr :null, // - Compile pattern
371 quotemeta :null, // - quote regular expression magic characters
372 qw :null, // - quote a list of words
373 qx :null, // - backquote quote a string
374 rand :1, // - retrieve the next pseudorandom number
375 read :1, // - fixed-length buffered input from a filehandle
376 readdir :1, // - get a directory from a directory handle
377 readline :1, // - fetch a record from a file
378 readlink :1, // - determine where a symbolic link is pointing
379 readpipe :1, // - execute a system command and collect standard output
380 recv :1, // - receive a message over a Socket
381 redo :1, // - start this loop iteration over again
382 ref :1, // - find out the type of thing being referenced
383 rename :1, // - change a filename
384 require :1, // - load in external functions from a library at runtime
385 reset :1, // - clear all variables of a given name
386 'return' :1, // - get out of a function early
387 reverse :1, // - flip a string or a list
388 rewinddir :1, // - reset directory handle
389 rindex :1, // - right-to-left substring search
390 rmdir :1, // - remove a directory
391 s :null, // - replace a pattern with a string
392 say :1, // - print with newline
393 scalar :1, // - force a scalar context
394 seek :1, // - reposition file pointer for random-access I/O
395 seekdir :1, // - reposition directory pointer
396 select :1, // - reset default output or do I/O multiplexing
397 semctl :1, // - SysV semaphore control operations
398 semget :1, // - get set of SysV semaphores
399 semop :1, // - SysV semaphore operations
400 send :1, // - send a message over a socket
401 setgrent :1, // - prepare group file for use
402 sethostent :1, // - prepare hosts file for use
403 setnetent :1, // - prepare networks file for use
404 setpgrp :1, // - set the process group of a process
405 setpriority :1, // - set a process's nice value
406 setprotoent :1, // - prepare protocols file for use
407 setpwent :1, // - prepare passwd file for use
408 setservent :1, // - prepare services file for use
409 setsockopt :1, // - set some socket options
410 shift :1, // - remove the first element of an array, and return it
411 shmctl :1, // - SysV shared memory operations
412 shmget :1, // - get SysV shared memory segment identifier
413 shmread :1, // - read SysV shared memory
414 shmwrite :1, // - write SysV shared memory
415 shutdown :1, // - close down just half of a socket connection
416 'sin' :1, // - return the sine of a number
417 sleep :1, // - block for some number of seconds
418 socket :1, // - create a socket
419 socketpair :1, // - create a pair of sockets
420 'sort' :1, // - sort a list of values
421 splice :1, // - add or remove elements anywhere in an array
422 'split' :1, // - split up a string using a regexp delimiter
423 sprintf :1, // - formatted print into a string
424 'sqrt' :1, // - square root function
425 srand :1, // - seed the random number generator
426 stat :1, // - get a file's status information
427 state :1, // - declare and assign a state variable (persistent lexical scoping)
428 study :1, // - optimize input data for repeated searches
429 'sub' :1, // - declare a subroutine, possibly anonymously
430 'substr' :1, // - get or alter a portion of a stirng
431 symlink :1, // - create a symbolic link to a file
432 syscall :1, // - execute an arbitrary system call
433 sysopen :1, // - open a file, pipe, or descriptor
434 sysread :1, // - fixed-length unbuffered input from a filehandle
435 sysseek :1, // - position I/O pointer on handle used with sysread and syswrite
436 system :1, // - run a separate program
437 syswrite :1, // - fixed-length unbuffered output to a filehandle
438 tell :1, // - get current seekpointer on a filehandle
439 telldir :1, // - get current seekpointer on a directory handle
440 tie :1, // - bind a variable to an object class
441 tied :1, // - get a reference to the object underlying a tied variable
442 time :1, // - return number of seconds since 1970
443 times :1, // - return elapsed time for self and child processes
444 tr :null, // - transliterate a string
445 truncate :1, // - shorten a file
446 uc :1, // - return upper-case version of a string
447 ucfirst :1, // - return a string with just the next letter in upper case
448 umask :1, // - set file creation mode mask
449 undef :1, // - remove a variable or function definition
450 unlink :1, // - remove one link to a file
451 unpack :1, // - convert binary structure into normal perl variables
452 unshift :1, // - prepend more elements to the beginning of a list
453 untie :1, // - break a tie binding to a variable
454 use :1, // - load in a module at compile time
455 utime :1, // - set a file's last access and modify times
456 values :1, // - return a list of the values in a hash
457 vec :1, // - test or set particular bits in a string
458 wait :1, // - wait for any child process to die
459 waitpid :1, // - wait for a particular child process to die
460 wantarray :1, // - get void vs scalar vs list context of current subroutine call
461 warn :1, // - print debugging info
463 write :1, // - print a picture record
464 y :null}; // - transliterate a string
466 var RXstyle="string-2";
467 var RXmodifiers=/[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type
469 function tokenChain(stream,state,chain,style,tail){ // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;)
470 state.chain=null; // 12 3tail
473 state.tokenize=function(stream,state){
475 while(c=stream.next()){
476 if(c===chain[i]&&!e){
477 if(chain[++i]!==undefined){
478 state.chain=chain[i];
482 stream.eatWhile(tail);
483 state.tokenize=tokenPerl;
487 return state.tokenize(stream,state);}
489 function tokenSOMETHING(stream,state,string){
490 state.tokenize=function(stream,state){
491 if(stream.string==string)
492 state.tokenize=tokenPerl;
495 return state.tokenize(stream,state);}
497 function tokenPerl(stream,state){
498 if(stream.eatSpace())
501 return tokenChain(stream,state,state.chain,state.style,state.tail);
502 if(stream.match(/^\-?[\d\.]/,false))
503 if(stream.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/))
505 if(stream.match(/^<<(?=\w)/)){ // NOTE: <<SOMETHING\n...\nSOMETHING\n
506 stream.eatWhile(/\w/);
507 return tokenSOMETHING(stream,state,stream.current().substr(2));}
508 if(stream.sol()&&stream.match(/^\=item(?!\w)/)){// NOTE: \n=item...\n=cut\n
509 return tokenSOMETHING(stream,state,'=cut');}
510 var ch=stream.next();
511 if(ch=='"'||ch=="'"){ // NOTE: ' or " or <<'SOMETHING'\n...\nSOMETHING\n or <<"SOMETHING"\n...\nSOMETHING\n
512 if(stream.prefix(3)=="<<"+ch){
514 stream.eatWhile(/\w/);
515 var n=stream.current().substr(1);
516 if(n&&stream.eat(ch))
517 return tokenSOMETHING(stream,state,n);
519 return tokenChain(stream,state,[ch],"string");}
521 var c=stream.look(-2);
522 if(!(c&&/\w/.test(c))){
528 return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
531 return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
534 return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
537 return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}
538 if(/[\^'"!~\/]/.test(c)){
540 return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}
545 return tokenChain(stream,state,[")"],"string");}
548 return tokenChain(stream,state,["]"],"string");}
551 return tokenChain(stream,state,["}"],"string");}
554 return tokenChain(stream,state,[">"],"string");}
555 if(/[\^'"!~\/]/.test(c)){
557 return tokenChain(stream,state,[stream.eat(c)],"string");}}
562 return tokenChain(stream,state,[")"],"bracket");}
565 return tokenChain(stream,state,["]"],"bracket");}
568 return tokenChain(stream,state,["}"],"bracket");}
571 return tokenChain(stream,state,[">"],"bracket");}
572 if(/[\^'"!~\/]/.test(c)){
574 return tokenChain(stream,state,[stream.eat(c)],"bracket");}}
579 return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
582 return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
585 return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
588 return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}
589 if(/[\^'"!~\/]/.test(c)){
591 return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}}
592 else if(/[\^'"!~\/(\[{<]/.test(c)){
595 return tokenChain(stream,state,[")"],"string");}
598 return tokenChain(stream,state,["]"],"string");}
601 return tokenChain(stream,state,["}"],"string");}
604 return tokenChain(stream,state,[">"],"string");}
605 if(/[\^'"!~\/]/.test(c)){
606 return tokenChain(stream,state,[stream.eat(c)],"string");}}}}
608 var c=stream.look(-2);
609 if(!(c&&/\w/.test(c))){
610 c=stream.eat(/[(\[{<\^'"!~\/]/);
612 if(/[\^'"!~\/]/.test(c)){
613 return tokenChain(stream,state,[c],RXstyle,RXmodifiers);}
615 return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);}
617 return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);}
619 return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);}
621 return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}}}}
623 var c=/[\/>\]})\w]/.test(stream.look(-2));
625 c=stream.eat(/[(\[{<\^'"!~\/]/);
628 return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
630 return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
632 return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
634 return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
635 return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}
637 var c=/[\/>\]})\w]/.test(stream.look(-2));
639 c=stream.eat(/[(\[{<\^'"!~\/]/);
642 return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
644 return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
646 return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
648 return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
649 return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}
651 var c=/[\/>\]})\w]/.test(stream.look(-2));
653 c=stream.eat("r");if(c){
654 c=stream.eat(/[(\[{<\^'"!~\/]/);
657 return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers);
659 return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers);
661 return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers);
663 return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers);
664 return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}}
666 return tokenChain(stream,state,[ch],"variable-2");}
668 if(!/~\s*$/.test(stream.prefix()))
671 return tokenChain(stream,state,[ch],RXstyle,RXmodifiers);}
674 if(stream.eatWhile(/\d/)||stream.eat("{")&&stream.eatWhile(/\d/)&&stream.eat("}"))
678 if(/[$@%]/.test(ch)){
680 if(stream.eat("^")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(stream.look(-2))&&stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){
681 var c=stream.current();
683 return "variable-2";}
685 if(/[$@%&]/.test(ch)){
686 if(stream.eatWhile(/[\w$\[\]]/)||stream.eat("{")&&stream.eatWhile(/[\w$\[\]]/)&&stream.eat("}")){
687 var c=stream.current();
693 if(stream.look(-2)!="$"){
696 if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)){
698 stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/);
699 if(PERL[stream.current()])
705 if(stream.suffix(6)=="_END__"){
706 return tokenChain(stream,state,['\0'],"comment");}
707 else if(stream.suffix(7)=="_DATA__"){
708 return tokenChain(stream,state,['\0'],"variable-2");}
709 else if(stream.suffix(7)=="_C__"){
710 return tokenChain(stream,state,['\0'],"string");}}}
713 if(stream.look(-2)=="{"&&(stream.look(0)=="}"||stream.eatWhile(/\w/)&&stream.look(0)=="}"))
717 if(/[A-Z]/.test(ch)){
718 var l=stream.look(-2);
720 stream.eatWhile(/[A-Z_]/);
721 if(/[\da-z]/.test(stream.look(0))){
724 var c=PERL[stream.current()];
744 if(/[a-zA-Z_]/.test(ch)){
745 var l=stream.look(-2);
746 stream.eatWhile(/\w/);
747 var c=PERL[stream.current()];
770 startState:function(){
776 token:function(stream,state){
777 return (state.tokenize||tokenPerl)(stream,state);},
778 electricChars:"{}"};});
780 CodeMirror.defineMIME("text/x-perl", "perl");
782 // it's like "peek", but need for look-ahead or look-behind if index < 0
783 CodeMirror.StringStream.prototype.look=function(c){
784 return this.string.charAt(this.pos+(c||0));};
786 // return a part of prefix of current stream from current position
787 CodeMirror.StringStream.prototype.prefix=function(c){
790 return this.string.substr((x>=0?x:0),c);}
792 return this.string.substr(0,this.pos-1);}};
794 // return a part of suffix of current stream from current position
795 CodeMirror.StringStream.prototype.suffix=function(c){
796 var y=this.string.length;
798 return this.string.substr(this.pos,(c&&c<y?c:x));};
800 // return a part of suffix of current stream from current position and change current position
801 CodeMirror.StringStream.prototype.nsuffix=function(c){
803 var l=c||(this.string.length-this.pos+1);
805 return this.string.substr(p,l);};
807 // eating and vomiting a part of stream from current position
808 CodeMirror.StringStream.prototype.eatSuffix=function(c){
813 else if(x>=(y=this.string.length-1))