| 1 skipped line |
| 2 | | 2 | | /** @file LexPerl.cxx |
|
| 3 | | 3 | | ** Lexer for subset of Perl. |
|
|
| 5 | | // Lexical analysis fixes by Kein-Hong Man <mkh@pl.jaring.my> 2003-2004 | | 5 | | // Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org> |
| 6 | | // Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org> | | 6 | | // Lexical analysis fixes by Kein-Hong Man <mkh@pl.jaring.my> |
| 7 | | 7 | | // The License.txt file describes the conditions under which this software may be distributed. |
|
|
|
| 10 skipped lines |
| 20 | | 20 | | #include "Scintilla.h" |
|
| 21 | | 21 | | #include "SciLexer.h" |
|
|
| 23 | | #define PERLNUM_DECIMAL 1 | | 23 | | #define PERLNUM_BINARY 1 // order is significant: 1-4 cannot have a dot |
| 24 | | #define PERLNUM_NON_DEC 2 | | 24 | | #define PERLNUM_HEX 2 |
| 25 | | #define PERLNUM_FLOAT 3 | | 25 | | #define PERLNUM_OCTAL 3 |
| 26 | | #define PERLNUM_VECTOR 4 | | 26 | | #define PERLNUM_FLOAT 4 // actually exponent part |
| | | 27 | | #define PERLNUM_DECIMAL 5 // 1-5 are numbers; 6-7 are strings |
| | | 28 | | #define PERLNUM_VECTOR 6 |
| 27 | | #define PERLNUM_V_VECTOR 5 | | 29 | | #define PERLNUM_V_VECTOR 7 |
| | | 30 | | #define PERLNUM_BAD 8 |
| | | 31 | | |
| | | 32 | | #define BACK_NONE 0 // lookback state for bareword disambiguation: |
| | | 33 | | #define BACK_OPERATOR 1 // whitespace/comments are insignificant |
| | | 34 | | #define BACK_KEYWORD 2 // operators/keywords are needed for disambiguation |
|
| 29 | | 36 | | #define HERE_DELIM_MAX 256 |
|
|
| 13 skipped lines |
| 44 | | 51 | | ch == '(' || ch == ')' || ch == '-' || ch == '+' || |
|
| 45 | | 52 | | ch == '=' || ch == '|' || ch == '{' || ch == '}' || |
|
| 46 | | 53 | | ch == '[' || ch == ']' || ch == ':' || ch == ';' || |
|
| 47 | | ch == '>' || ch == ',' || | | 54 | | ch == '>' || ch == ',' || |
| 48 | | 55 | | ch == '?' || ch == '!' || ch == '.' || ch == '~') |
|
|
| 50 | | 57 | | // these chars are already tested before this call |
|
| 1 skipped line |
|
|
|
| 55 | | static int classifyWordPerl(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) { | | 62 | | static bool isPerlKeyword(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) { |
|
| 57 | | for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) { | | 64 | | unsigned int i, len = end - start; |
| | | 65 | | if (len > 30) { len = 30; } |
| 58 | | s[i] = styler[start + i]; | | 66 | | for (i = 0; i < len; i++, start++) s[i] = styler[start]; |
| 59 | | s[i + 1] = '\0'; | | 67 | | s[i] = '\0'; |
| 60 | | } | | |
| 61 | | char chAttr = SCE_PL_IDENTIFIER; | | |
| 62 | | if (keywords.InList(s)) | | 68 | | return keywords.InList(s); |
| 63 | | chAttr = SCE_PL_WORD; | | |
| 64 | | styler.ColourTo(end, chAttr); | | |
| 65 | | return chAttr; | | |
|
|
| 68 | | 71 | | static inline bool isEndVar(char ch) { |
|
| 7 skipped lines |
|
|
| 78 | | 81 | | static inline char actualNumStyle(int numberStyle) { |
|
| 79 | | switch (numberStyle) { | | |
| 80 | | case PERLNUM_VECTOR: | | |
| 81 | | case PERLNUM_V_VECTOR: | | 82 | | if (numberStyle == PERLNUM_VECTOR || numberStyle == PERLNUM_V_VECTOR) { |
| 82 | | return SCE_PL_STRING; | | 83 | | return SCE_PL_STRING; |
| 83 | | case PERLNUM_DECIMAL: | | |
| 84 | | case PERLNUM_NON_DEC: | | 84 | | } else if (numberStyle == PERLNUM_BAD) { |
| 85 | | case PERLNUM_FLOAT: | | 85 | | return SCE_PL_ERROR; |
| 86 | | default: | | 86 | | } |
| 87 | | return SCE_PL_NUMBER; | | 87 | | return SCE_PL_NUMBER; |
| 88 | | } | | |
|
|
| 91 | | 90 | | static bool isMatch(Accessor &styler, int lengthDoc, int pos, const char *val) { |
|
| 41 skipped lines |
| 133 | | 132 | | char *Delimiter;// the Delimiter, 256: sizeof PL_tokenbuf |
|
|
|
| | | 135 | | Quote = 0; |
| | | 136 | | Quoted = false; |
| 136 | | 137 | | DelimiterLength = 0; |
|
| 137 | | 138 | | Delimiter = new char[HERE_DELIM_MAX]; |
|
| 138 | | 139 | | Delimiter[0] = '\0'; |
|
| 57 skipped lines |
| 196 | | 197 | | || state == SCE_PL_CHARACTER |
|
| 197 | | 198 | | || state == SCE_PL_NUMBER |
|
| 198 | | 199 | | || state == SCE_PL_IDENTIFIER |
|
| | | 200 | | || state == SCE_PL_ERROR |
|
| 200 | | 202 | | while ((startPos > 1) && (styler.StyleAt(startPos - 1) == state)) { |
|
|
| 1 skipped line |
| 203 | | 205 | | state = SCE_PL_DEFAULT; |
|
|
|
| | | 208 | | // lookback at start of lexing to set proper state for backflag |
| | | 209 | | // after this, they are updated when elements are lexed |
| | | 210 | | int backflag = BACK_NONE; |
| | | 211 | | unsigned int backPos = startPos; |
| | | 212 | | if (backPos > 0) { |
| 6 skipped lines |
| | | 219 | | backflag = BACK_OPERATOR; |
| | | 220 | | else if (sty == SCE_PL_WORD) |
| | | 221 | | backflag = BACK_KEYWORD; |
| | | 222 | | } |
| | | 223 | | |
| 206 | | 224 | | styler.StartAt(startPos); |
|
| 207 | | 225 | | char chPrev = styler.SafeGetCharAt(startPos - 1); |
|
| 208 | | 226 | | if (startPos == 0) |
|
| 60 skipped lines |
| 269 | | 287 | | if (isdigit(ch) || (isdigit(chNext) && |
|
| 270 | | 288 | | (ch == '.' || ch == 'v'))) { |
|
| 271 | | 289 | | state = SCE_PL_NUMBER; |
|
| | | 290 | | backflag = BACK_NONE; |
| 272 | | 291 | | numState = PERLNUM_DECIMAL; |
|
|
| 274 | | 293 | | if (ch == '0') {// hex,bin,octal |
|
| | | 294 | | if (chNext == 'x') { |
| | | 295 | | numState = PERLNUM_HEX; |
| | | 296 | | } else if (chNext == 'b') { |
| | | 297 | | numState = PERLNUM_BINARY; |
| 275 | | if (chNext == 'x' || chNext == 'b' || isdigit(chNext)) { | | 298 | | } else if (isdigit(chNext)) { |
| 276 | | numState = PERLNUM_NON_DEC; | | 299 | | numState = PERLNUM_OCTAL; |
| | | 300 | | } |
| | | 301 | | if (numState != PERLNUM_DECIMAL) { |
| | | 302 | | i++; |
| | | 303 | | ch = chNext; |
| | | 304 | | chNext = chNext2; |
| 277 | | } | | 305 | | } |
| 278 | | 306 | | } else if (ch == 'v') { // vector |
|
| 279 | | 307 | | numState = PERLNUM_V_VECTOR; |
|
|
| 281 | | 309 | | } else if (iswordstart(ch)) { |
|
| | | 310 | | // if immediately prefixed by '::', always a bareword |
| | | 311 | | state = SCE_PL_WORD; |
| 282 | | if (chPrev == '>' && styler.SafeGetCharAt(i - 2) == '-') { | | 312 | | if (chPrev == ':' && styler.SafeGetCharAt(i - 2) == ':') { |
| 283 | | state = SCE_PL_IDENTIFIER; // part of "->" expr | | 313 | | state = SCE_PL_IDENTIFIER; |
| 284 | | if ((!iswordchar(chNext) && chNext != '\'') | | 314 | | } |
| 285 | | || (chNext == '.' && chNext2 == '.')) { | | 315 | | unsigned int kw = i + 1; |
| 286 | | // We need that if length of word == 1! | | 316 | | // first check for possible quote-like delimiter |
| 287 | | styler.ColourTo(i, SCE_PL_IDENTIFIER); | | |
| 288 | | state = SCE_PL_DEFAULT; | | |
| 289 | | } | | |
| 290 | | } else if (ch == 's' && !isNonQuote(chNext)) { | | 317 | | if (ch == 's' && !isNonQuote(chNext)) { |
| 291 | | 318 | | state = SCE_PL_REGSUBST; |
|
|
| 293 | | 320 | | } else if (ch == 'm' && !isNonQuote(chNext)) { |
|
| 8 skipped lines |
| 302 | | 329 | | } else if (ch == 't' && chNext == 'r' && !isNonQuote(chNext2)) { |
|
| 303 | | 330 | | state = SCE_PL_REGSUBST; |
|
|
| 305 | | i++; | | 332 | | kw++; |
| 306 | | chNext = chNext2; | | |
| 307 | | 333 | | } else if (ch == 'q' && (chNext == 'q' || chNext == 'r' || chNext == 'w' || chNext == 'x') && !isNonQuote(chNext2)) { |
|
| 308 | | 334 | | if (chNext == 'q') state = SCE_PL_STRING_QQ; |
|
| 309 | | 335 | | else if (chNext == 'x') state = SCE_PL_STRING_QX; |
|
| 310 | | 336 | | else if (chNext == 'r') state = SCE_PL_STRING_QR; |
|
| 311 | | 337 | | else if (chNext == 'w') state = SCE_PL_STRING_QW; |
|
| 312 | | i++; | | |
| 313 | | chNext = chNext2; | | |
|
| | | 339 | | kw++; |
| 315 | | 340 | | } else if (ch == 'x' && (chNext == '=' || // repetition |
|
| 316 | | (chNext != '_' && !isalnum(chNext)) || | | 341 | | (chNext != '_' && !isalnum(chNext)) || |
| 317 | | (isdigit(chPrev) && isdigit(chNext)))) { | | 342 | | (isdigit(chPrev) && isdigit(chNext)))) { |
| 318 | | styler.ColourTo(i, SCE_PL_OPERATOR); | | 343 | | state = SCE_PL_OPERATOR; |
| 319 | | } else { | | 344 | | } |
| 320 | | state = SCE_PL_WORD; | | 345 | | // if potentially a keyword, scan forward and grab word, then check |
| 321 | | if ((!iswordchar(chNext) && chNext != '\'') | | 346 | | // if it's really one; if yes, disambiguation test is performed |
| 322 | | || (chNext == '.' && chNext2 == '.')) { | | 347 | | // otherwise it is always a bareword and we skip a lot of scanning |
| 323 | | // We need that if length of word == 1! | | 348 | | // note: keywords assumed to be limited to [_a-zA-Z] only |
| 324 | | // This test is copied from the SCE_PL_WORD handler. | | 349 | | if (state == SCE_PL_WORD) { |
| | | 350 | | while (iswordstart(styler.SafeGetCharAt(kw))) kw++; |
| 325 | | classifyWordPerl(styler.GetStartSegment(), i, keywords, styler); | | 351 | | if (!isPerlKeyword(styler.GetStartSegment(), kw, keywords, styler)) { |
| 326 | | state = SCE_PL_DEFAULT; | | 352 | | state = SCE_PL_IDENTIFIER; |
| 327 | | } | | 353 | | } |
| | | 354 | | } |
| | | 355 | | // if already SCE_PL_IDENTIFIER, then no ambiguity, skip this |
| | | 356 | | // for quote-like delimiters/keywords, attempt to disambiguate |
| | | 357 | | // to select for bareword, change state -> SCE_PL_IDENTIFIER |
| | | 358 | | if (state != SCE_PL_IDENTIFIER && i > 0) { |
| | | 359 | | unsigned int j = i; |
| | | 360 | | bool moreback = false; // true if passed newline/comments |
| | | 361 | | bool brace = false; // true if opening brace found |
| | | 362 | | char ch2; |
| | | 363 | | // first look backwards past whitespace/comments for EOLs |
| 63 skipped lines |
| | | 427 | | ch = styler.SafeGetCharAt(i); |
| | | 428 | | chNext = styler.SafeGetCharAt(i + 1); |
| | | 429 | | // a repetition operator 'x' |
| | | 430 | | } else if (state == SCE_PL_OPERATOR) { |
| | | 431 | | styler.ColourTo(i, SCE_PL_OPERATOR); |
| | | 432 | | state = SCE_PL_DEFAULT; |
| | | 433 | | // quote-like delimiter, skip one char if double-char delimiter |
| | | 434 | | } else { |
| | | 435 | | i = kw - 1; |
| | | 436 | | chNext = styler.SafeGetCharAt(i + 1); |
| 328 | | } | | 437 | | } |
| 329 | | 438 | | } else if (ch == '#') { |
|
| 330 | | 439 | | state = SCE_PL_COMMENTLINE; |
|
| 331 | | 440 | | } else if (ch == '\"') { |
|
| 332 | | 441 | | state = SCE_PL_STRING; |
|
|
|
| | | 444 | | backflag = BACK_NONE; |
| 335 | | 445 | | } else if (ch == '\'') { |
|
| 336 | | 446 | | if (chPrev == '&') { |
|
|
| 3 skipped lines |
|
|
|
| | | 454 | | backflag = BACK_NONE; |
| 344 | | 455 | | } else if (ch == '`') { |
|
| 345 | | 456 | | state = SCE_PL_BACKTICKS; |
|
|
|
| | | 459 | | backflag = BACK_NONE; |
| 348 | | 460 | | } else if (ch == '$') { |
|
| 349 | | 461 | | if ((chNext == '{') || isspacechar(chNext)) { |
|
| 350 | | 462 | | styler.ColourTo(i, SCE_PL_SCALAR); |
|
| 9 skipped lines |
| 360 | | 472 | | chNext = chNext2; |
|
|
|
| | | 475 | | backflag = BACK_NONE; |
| 363 | | 476 | | } else if (ch == '@') { |
|
| 364 | | 477 | | if (isalpha(chNext) || chNext == '#' || chNext == '$' |
|
| 365 | | || chNext == '_' || chNext == '+') { | | 478 | | || chNext == '_' || chNext == '+' || chNext == '-') { |
| 366 | | 479 | | state = SCE_PL_ARRAY; |
|
| 367 | | 480 | | } else if (chNext != '{' && chNext != '[') { |
|
| 368 | | 481 | | styler.ColourTo(i, SCE_PL_ARRAY); |
|
| 369 | | i++; | | |
| 370 | | ch = ' '; | | |
|
| 372 | | 483 | | styler.ColourTo(i, SCE_PL_ARRAY); |
|
|
| | | 485 | | backflag = BACK_NONE; |
| 374 | | 486 | | } else if (ch == '%') { |
|
| 375 | | if (isalpha(chNext) || chNext == '#' || chNext == '$' || chNext == '_') { | | 487 | | if (isalpha(chNext) || chNext == '#' || chNext == '$' |
| | | 488 | | || chNext == '_' || chNext == '!' || chNext == '^') { |
| 376 | | 489 | | state = SCE_PL_HASH; |
|
| | | 490 | | i++; |
| | | 491 | | ch = chNext; |
| | | 492 | | chNext = chNext2; |
| 377 | | 493 | | } else if (chNext == '{') { |
|
| 378 | | 494 | | styler.ColourTo(i, SCE_PL_HASH); |
|
|
| 380 | | 496 | | styler.ColourTo(i, SCE_PL_OPERATOR); |
|
|
| | | 498 | | backflag = BACK_NONE; |
| 382 | | 499 | | } else if (ch == '*') { |
|
| | | 500 | | char strch[2]; |
| | | 501 | | strch[0] = chNext; |
| | | 502 | | strch[1] = '\0'; |
| 383 | | if (isalpha(chNext) || chNext == '_' || chNext == '{') { | | 503 | | if (isalpha(chNext) || chNext == '_' || |
| | | 504 | | NULL != strstr("^/|,\\\";#%^:?<>)[]", strch)) { |
| 384 | | 505 | | state = SCE_PL_SYMBOLTABLE; |
|
| | | 506 | | i++; |
| | | 507 | | ch = chNext; |
| | | 508 | | chNext = chNext2; |
| | | 509 | | } else if (chNext == '{') { |
| | | 510 | | styler.ColourTo(i, SCE_PL_SYMBOLTABLE); |
|
| 386 | | 512 | | if (chNext == '*') {// exponentiation |
|
|
| 2 skipped lines |
|
| 391 | | 517 | | styler.ColourTo(i, SCE_PL_OPERATOR); |
|
|
| | | 519 | | backflag = BACK_NONE; |
| 393 | | } else if (ch == '/') { | | 520 | | } else if (ch == '/' || (ch == '<' && chNext == '<')) { |
| 394 | | 521 | | // Explicit backward peeking to set a consistent preferRE for |
|
| 395 | | 522 | | // any slash found, so no longer need to track preferRE state. |
|
| 396 | | 523 | | // Find first previous significant lexed element and interpret. |
|
| | | 524 | | // Test for HERE doc start '<<' shares this code, helps to |
| | | 525 | | // determine if it should be an operator. |
| 397 | | 526 | | bool preferRE = false; |
|
| | | 527 | | bool isHereDoc = (ch == '<'); |
| | | 528 | | bool hereDocSpace = false; // these are for corner case: |
| | | 529 | | bool hereDocScalar = false; // SCALAR [whitespace] '<<' |
| 398 | | 530 | | unsigned int bk = (i > 0)? i - 1: 0; |
|
|
|
| | | 533 | | if (styler.StyleAt(bk) == SCE_PL_DEFAULT) |
| | | 534 | | hereDocSpace = true; |
| 401 | | 535 | | while ((bk > 0) && (styler.StyleAt(bk) == SCE_PL_DEFAULT || |
|
| 402 | | 536 | | styler.StyleAt(bk) == SCE_PL_COMMENTLINE)) { |
|
|
| 90 skipped lines |
|
|
|
| | | 631 | | case SCE_PL_SCALAR: // for $var<< case |
| | | 632 | | hereDocScalar = true; |
| | | 633 | | break; |
| 497 | | 634 | | // other styles uses the default, preferRE=false |
|
| 498 | | 635 | | case SCE_PL_WORD: |
|
|
| | | 637 | | case SCE_PL_POD_VERB: |
| 500 | | 638 | | case SCE_PL_HERE_Q: |
|
| 501 | | 639 | | case SCE_PL_HERE_QQ: |
|
| 502 | | 640 | | case SCE_PL_HERE_QX: |
|
| 1 skipped line |
|
|
|
| | | 645 | | if (isHereDoc) { // handle HERE doc |
| | | 646 | | // if SCALAR whitespace '<<', *always* a HERE doc |
| 507 | | if (preferRE) { | | 647 | | if (preferRE || (hereDocSpace && hereDocScalar)) { |
| 508 | | state = SCE_PL_REGEX; | | 648 | | state = SCE_PL_HERE_DELIM; |
| 509 | | Quote.New(1); | | 649 | | HereDoc.State = 0; |
| 510 | | Quote.Open(ch); | | |
| 511 | | } else { | | 650 | | } else { // << operator |
| | | 651 | | i++; |
| | | 652 | | ch = chNext; |
| | | 653 | | chNext = chNext2; |
| 512 | | styler.ColourTo(i, SCE_PL_OPERATOR); | | 654 | | styler.ColourTo(i, SCE_PL_OPERATOR); |
| 513 | | } | | 655 | | } |
| 514 | | } else if (ch == '<' && chNext == '<') { | | 656 | | } else { // handle regexp |
| | | 657 | | if (preferRE) { |
| 515 | | state = SCE_PL_HERE_DELIM; | | 658 | | state = SCE_PL_REGEX; |
| | | 659 | | Quote.New(1); |
| | | 660 | | Quote.Open(ch); |
| | | 661 | | } else { // / operator |
| | | 662 | | styler.ColourTo(i, SCE_PL_OPERATOR); |
| | | 663 | | } |
| | | 664 | | } |
| 516 | | HereDoc.State = 0; | | 665 | | backflag = BACK_NONE; |
| 517 | | 666 | | } else if (ch == '<') { |
|
| 518 | | 667 | | // looks forward for matching > on same line |
|
| 519 | | 668 | | unsigned int fw = i + 1; |
|
| 520 | | 669 | | while (fw < lengthDoc) { |
|
| 521 | | 670 | | char fwch = styler.SafeGetCharAt(fw); |
|
| | | 671 | | if (fwch == ' ') { |
| | | 672 | | if (styler.SafeGetCharAt(fw-1) != '\\' || |
| | | 673 | | styler.SafeGetCharAt(fw-2) != '\\') |
| | | 674 | | break; |
| 522 | | if (isEOLChar(fwch) || isspacechar(fwch)) | | 675 | | } else if (isEOLChar(fwch) || isspacechar(fwch)) { |
|
| 524 | | else if (fwch == '>') { | | 677 | | } else if (fwch == '>') { |
| 525 | | 678 | | if ((fw - i) == 2 &&// '<=>' case |
|
| 526 | | 679 | | styler.SafeGetCharAt(fw-1) == '=') { |
|
| 527 | | 680 | | styler.ColourTo(fw, SCE_PL_OPERATOR); |
|
| 7 skipped lines |
|
|
| 537 | | 690 | | styler.ColourTo(i, SCE_PL_OPERATOR); |
|
| | | 691 | | backflag = BACK_NONE; |
| 538 | | 692 | | } else if (ch == '='// POD |
|
| 539 | | 693 | | && isalpha(chNext) |
|
| 540 | | 694 | | && (isEOLChar(chPrev))) { |
|
| 541 | | 695 | | state = SCE_PL_POD; |
|
| | | 696 | | backflag = BACK_NONE; |
|
| 543 | | 698 | | //sooked[sookedpos] = '\0'; |
|
| 544 | | 699 | | } else if (ch == '-'// file test operators |
|
| 4 skipped lines |
|
|
| 551 | | 706 | | chNext = chNext2; |
|
| | | 707 | | backflag = BACK_NONE; |
| 552 | | 708 | | } else if (isPerlOperator(ch)) { |
|
| 553 | | 709 | | if (ch == '.' && chNext == '.') { // .. and ... |
|
|
| 3 skipped lines |
| 558 | | 714 | | chNext = styler.SafeGetCharAt(i + 1); |
|
|
| 560 | | 716 | | styler.ColourTo(i, SCE_PL_OPERATOR); |
|
| | | 717 | | backflag = BACK_OPERATOR; |
| | | 718 | | backPos = i; |
|
| 562 | | 720 | | // keep colouring defaults to make restart easier |
|
| 563 | | 721 | | styler.ColourTo(i, SCE_PL_DEFAULT); |
|
| 3 skipped lines |
| 567 | | 725 | | if (chNext == '.') { |
|
| 568 | | 726 | | // double dot is always an operator |
|
|
| 570 | | } else if (numState == PERLNUM_NON_DEC || numState == PERLNUM_FLOAT) { | | 728 | | } else if (numState <= PERLNUM_FLOAT) { |
| 571 | | 729 | | // non-decimal number or float exponent, consume next dot |
|
| 572 | | 730 | | styler.ColourTo(i - 1, SCE_PL_NUMBER); |
|
| 573 | | 731 | | styler.ColourTo(i, SCE_PL_OPERATOR); |
|
| 20 skipped lines |
| 594 | | 752 | | if (numState == PERLNUM_VECTOR || numState == PERLNUM_V_VECTOR) { |
|
| 595 | | 753 | | if (isalpha(ch)) { |
|
| 596 | | 754 | | if (dotCount == 0) { // change to word |
|
| 597 | | state = SCE_PL_WORD; | | 755 | | state = SCE_PL_IDENTIFIER; |
| 598 | | 756 | | } else { // vector then word |
|
|
|
| 13 skipped lines |
| 614 | | 772 | | if (!isdigit(ch)) { // float then word |
|
|
|
| | | 775 | | } else if (numState == PERLNUM_OCTAL) { |
| | | 776 | | if (!isdigit(ch)) |
| | | 777 | | goto numAtEnd; |
| | | 778 | | else if (ch > '7') |
| | | 779 | | numState = PERLNUM_BAD; |
| 617 | | } else {// (numState == PERLNUM_NON_DEC) | | 780 | | } else if (numState == PERLNUM_BINARY) { |
| 618 | | // allow alphanum for bin,hex,oct for now | | 781 | | if (!isdigit(ch)) |
| 619 | | } | | 782 | | goto numAtEnd; |
| | | 783 | | else if (ch > '1') |
| | | 784 | | numState = PERLNUM_BAD; |
| | | 785 | | } else if (numState == PERLNUM_HEX) { |
| | | 786 | | int ch2 = toupper(ch); |
| | | 787 | | if (!isdigit(ch) && !(ch2 >= 'A' && ch2 <= 'F')) |
| | | 788 | | goto numAtEnd; |
| | | 789 | | } else {//(numState == PERLNUM_BAD) { |
| | | 790 | | if (!isdigit(ch)) |
| | | 791 | | goto numAtEnd; |
| | | 792 | | } |
|
| 621 | | 794 | | // complete current number or vector |
|
|
| 1 skipped line |
| 624 | | 797 | | state = SCE_PL_DEFAULT; |
|
| 625 | | 798 | | goto restartLexer; |
|
|
| 627 | | } else if (state == SCE_PL_WORD) { | | |
| 628 | | if ((!iswordchar(chNext) && chNext != '\'') | | |
| 629 | | || chNext == '.') { | | |
| 630 | | // ".." is always an operator if preceded by a SCE_PL_WORD. | | |
| 631 | | // "." never used in Perl variable names | | |
| 6 skipped lines |
| 638 | | classifyWordPerl(styler.GetStartSegment(), i, keywords, styler); | | |
| 639 | | state = SCE_PL_DEFAULT; | | |
| 640 | | ch = ' '; | | |
| 641 | | } | | |
| 642 | | } | | |
| 643 | | 800 | | } else if (state == SCE_PL_IDENTIFIER) { |
|
| 644 | | if ((!iswordchar(chNext) && chNext != '\'') | | 801 | | if (!iswordstart(chNext) && chNext != '\'') { |
| 645 | | || chNext == '.') { | | |
| 646 | | 802 | | styler.ColourTo(i, SCE_PL_IDENTIFIER); |
|
| 647 | | 803 | | state = SCE_PL_DEFAULT; |
|
|
| 36 skipped lines |
| 685 | | 841 | | // Whitespace acceptable after <<[-] operator. |
|
|
| 687 | | 843 | | if (HereDoc.State == 0) { // '<<' encountered |
|
| | | 844 | | bool gotspace = false; |
| | | 845 | | unsigned int oldi = i; |
| | | 846 | | if (chNext == ' ' || chNext == '\t') { |
| | | 847 | | // skip whitespace; legal for quoted delimiters |
| | | 848 | | gotspace = true; |
| | | 849 | | do { |
| | | 850 | | i++; |
| | | 851 | | chNext = styler.SafeGetCharAt(i + 1); |
| | | 852 | | } while ((i + 1 < lengthDoc) && (chNext == ' ' || chNext == '\t')); |
| | | 853 | | chNext2 = styler.SafeGetCharAt(i + 2); |
| | | 854 | | } |
| 688 | | 855 | | HereDoc.State = 1; |
|
| 689 | | 856 | | HereDoc.Quote = chNext; |
|
| 690 | | 857 | | HereDoc.Quoted = false; |
|
| 691 | | 858 | | HereDoc.DelimiterLength = 0; |
|
| 692 | | 859 | | HereDoc.Delimiter[HereDoc.DelimiterLength] = '\0'; |
|
| 693 | | if (chNext == '\'' || chNext == '"' || chNext == '`') { // a quoted here-doc delimiter | | 860 | | if (chNext == '\'' || chNext == '"' || chNext == '`') { |
| | | 861 | | // a quoted here-doc delimiter |
|
|
| 696 | | 864 | | chNext = chNext2; |
|
| 697 | | 865 | | HereDoc.Quoted = true; |
|
| 698 | | } else if (isalpha(chNext) || chNext == '_') { | | |
| 699 | | // an unquoted here-doc delimiter, no special handling | | |
| 700 | | 866 | | } else if (isspacechar(chNext) || isdigit(chNext) || chNext == '\\' |
|
| 701 | | || chNext == '=' || chNext == '$' || chNext == '@') { | | 867 | | || chNext == '=' || chNext == '$' || chNext == '@' |
| | | 868 | | || ((isalpha(chNext) || chNext == '_') && gotspace)) { |
| 702 | | 869 | | // left shift << or <<= operator cases |
|
| | | 870 | | // restore position if operator |
| | | 871 | | i = oldi; |
| 703 | | 872 | | styler.ColourTo(i, SCE_PL_OPERATOR); |
|
| 704 | | 873 | | state = SCE_PL_DEFAULT; |
|
| 705 | | 874 | | HereDoc.State = 0; |
|
| | | 875 | | goto restartLexer; |
|
| | | 877 | | // an unquoted here-doc delimiter, no special handling |
| | | 878 | | // (cannot be prefixed by spaces/tabs), or |
| 707 | | 879 | | // symbols terminates; deprecated zero-length delimiter |
|
|
|
| 710 | | 882 | | } else if (HereDoc.State == 1) { // collect the delimiter |
|
| | | 883 | | backflag = BACK_NONE; |
| 711 | | 884 | | if (HereDoc.Quoted) { // a quoted here-doc delimiter |
|
| 712 | | 885 | | if (ch == HereDoc.Quote) { // closing quote => end of delimiter |
|
| 713 | | 886 | | styler.ColourTo(i, state); |
|
| 32 skipped lines |
| 746 | | 919 | | if (isEOLChar(ch)) { |
|
| 747 | | 920 | | styler.ColourTo(i - 1, state); |
|
| 748 | | 921 | | state = SCE_PL_DEFAULT; |
|
| | | 922 | | backflag = BACK_NONE; |
| 749 | | 923 | | HereDoc.State = 0; |
|
| 750 | | 924 | | goto restartLexer; |
|
|
| 752 | | 926 | | chNext = styler.SafeGetCharAt(i + 1); |
|
|
| 754 | | } else if (state == SCE_PL_POD) { | | 928 | | } else if (state == SCE_PL_POD |
| | | 929 | | || state == SCE_PL_POD_VERB) { |
| | | 930 | | if (isEOLChar(chPrev)) { |
| 755 | | if (ch == '=' && isEOLChar(chPrev)) { | | 931 | | if (ch == ' ' || ch == '\t') { |
| | | 932 | | styler.ColourTo(i - 1, state); |
| | | 933 | | state = SCE_PL_POD_VERB; |
| | | 934 | | } else { |
| | | 935 | | styler.ColourTo(i - 1, state); |
| | | 936 | | state = SCE_PL_POD; |
| | | 937 | | if (ch == '=') { |
| 756 | | if (isMatch(styler, lengthDoc, i, "=cut")) { | | 938 | | if (isMatch(styler, lengthDoc, i, "=cut")) { |
| 757 | | styler.ColourTo(i - 1 + 4, state); | | 939 | | styler.ColourTo(i - 1 + 4, state); |
| 758 | | i += 4; | | 940 | | i += 4; |
| 759 | | state = SCE_PL_DEFAULT; | | 941 | | state = SCE_PL_DEFAULT; |
| 760 | | ch = styler.SafeGetCharAt(i); | | 942 | | ch = styler.SafeGetCharAt(i); |
| 761 | | //chNext = styler.SafeGetCharAt(i + 1); | | 943 | | //chNext = styler.SafeGetCharAt(i + 1); |
| 762 | | goto restartLexer; | | 944 | | goto restartLexer; |
| | | 945 | | } |
| | | 946 | | } |
|
|
| 765 | | 949 | | } else if (state == SCE_PL_SCALAR // variable names |
|
| 6 skipped lines |
| 772 | | 956 | | chNext = chNext2; |
|
|
| 774 | | 958 | | else if (isEndVar(ch)) { |
|
| 775 | | if ((state == SCE_PL_SCALAR || state == SCE_PL_ARRAY) | | |
| 776 | | && i == (styler.GetStartSegment() + 1)) { | | 959 | | if (i == (styler.GetStartSegment() + 1)) { |
| 777 | | 960 | | // Special variable: $(, $_ etc. |
|
| 778 | | 961 | | styler.ColourTo(i, state); |
|
| 779 | | 962 | | state = SCE_PL_DEFAULT; |
|
| 137 skipped lines |
| 917 | | 1100 | | styler.ColourTo(lengthDoc - 1, state); |
|
|
|
| | | 1103 | | static bool IsCommentLine(int line, Accessor &styler) { |
| | | 1104 | | int pos = styler.LineStart(line); |
| | | 1105 | | int eol_pos = styler.LineStart(line + 1) - 1; |
| | | 1106 | | for (int i = pos; i < eol_pos; i++) { |
| | | 1107 | | char ch = styler[i]; |
| 4 skipped lines |
| | | 1112 | | return false; |
| | | 1113 | | } |
| | | 1114 | | return false; |
| | | 1115 | | } |
| | | 1116 | | |
| 920 | | 1117 | | static void FoldPerlDoc(unsigned int startPos, int length, int, WordList *[], |
|
| 921 | | 1118 | | Accessor &styler) { |
|
| 922 | | 1119 | | bool foldComment = styler.GetPropertyInt("fold.comment") != 0; |
|
| 923 | | 1120 | | bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; |
|
| | | 1121 | | // Custom folding of POD and packages |
| | | 1122 | | bool foldPOD = styler.GetPropertyInt("fold.perl.pod", 1) != 0; |
| | | 1123 | | bool foldPackage = styler.GetPropertyInt("fold.perl.package", 1) != 0; |
| 924 | | 1124 | | unsigned int endPos = startPos + length; |
|
| 925 | | 1125 | | int visibleChars = 0; |
|
| 926 | | 1126 | | int lineCurrent = styler.GetLine(startPos); |
|
| | | 1127 | | int levelPrev = SC_FOLDLEVELBASE; |
| | | 1128 | | if (lineCurrent > 0) |
| 927 | | int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; | | 1129 | | levelPrev = styler.LevelAt(lineCurrent - 1) >> 16; |
| 928 | | 1130 | | int levelCurrent = levelPrev; |
|
| 929 | | 1131 | | char chNext = styler[startPos]; |
|
| | | 1132 | | char chPrev = styler.SafeGetCharAt(startPos - 1); |
| 930 | | 1133 | | int styleNext = styler.StyleAt(startPos); |
|
| | | 1134 | | // Used at end of line to determine if the line was a package definition |
| | | 1135 | | bool isPackageLine = false; |
| | | 1136 | | bool isPodHeading = false; |
| 931 | | 1137 | | for (unsigned int i = startPos; i < endPos; i++) { |
|
| 932 | | 1138 | | char ch = chNext; |
|
| 933 | | 1139 | | chNext = styler.SafeGetCharAt(i + 1); |
|
| 934 | | 1140 | | int style = styleNext; |
|
| 935 | | 1141 | | styleNext = styler.StyleAt(i + 1); |
|
| 936 | | 1142 | | bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); |
|
| 937 | | if (foldComment && (style == SCE_PL_COMMENTLINE)) { | | 1143 | | bool atLineStart = isEOLChar(chPrev) || i == 0; |
| | | 1144 | | // Comment folding |
| 938 | | if ((ch == '/') && (chNext == '/')) { | | 1145 | | if (foldComment && atEOL && IsCommentLine(lineCurrent, styler)) |
| 939 | | char chNext2 = styler.SafeGetCharAt(i + 2); | | 1146 | | { |
| 940 | | if (chNext2 == '{') { | | 1147 | | if (!IsCommentLine(lineCurrent - 1, styler) |
| | | 1148 | | && IsCommentLine(lineCurrent + 1, styler)) |
| 941 | | levelCurrent++; | | 1149 | | levelCurrent++; |
| 942 | | } else if (chNext2 == '}') { | | 1150 | | else if (IsCommentLine(lineCurrent - 1, styler) |
| | | 1151 | | && !IsCommentLine(lineCurrent+1, styler)) |
| 943 | | levelCurrent--; | | 1152 | | levelCurrent--; |
| 944 | | } | | |
| 945 | | } | | |
| 946 | | } | | 1153 | | } |
| 947 | | 1154 | | if (style == SCE_C_OPERATOR) { |
|
| 948 | | 1155 | | if (ch == '{') { |
|
|
| 1 skipped line |
|
|
|
| | | 1161 | | // Custom POD folding |
| | | 1162 | | if (foldPOD && atLineStart) { |
| | | 1163 | | int stylePrevCh = (i) ? styler.StyleAt(i - 1):SCE_PL_DEFAULT; |
| | | 1164 | | if (style == SCE_PL_POD) { |
| | | 1165 | | if (stylePrevCh != SCE_PL_POD && stylePrevCh != SCE_PL_POD_VERB) |
| 20 skipped lines |
| | | 1186 | | if (style == SCE_PL_WORD && styler.Match(i, "package")) { |
| | | 1187 | | isPackageLine = true; |
| | | 1188 | | } |
| | | 1189 | | } |
| | | 1190 | | |
|
| 955 | | 1192 | | int lev = levelPrev; |
|
| | | 1193 | | if (isPodHeading) { |
| | | 1194 | | lev = levelPrev - 1; |
| | | 1195 | | lev |= SC_FOLDLEVELHEADERFLAG; |
| | | 1196 | | isPodHeading = false; |
| | | 1197 | | } |
| 3 skipped lines |
| | | 1201 | | lev = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG; |
| | | 1202 | | levelCurrent = SC_FOLDLEVELBASE + 1; |
| | | 1203 | | isPackageLine = false; |
| | | 1204 | | } |
| | | 1205 | | lev |= levelCurrent << 16; |
| 956 | | 1206 | | if (visibleChars == 0 && foldCompact) |
|
| 957 | | 1207 | | lev |= SC_FOLDLEVELWHITEFLAG; |
|
| 958 | | 1208 | | if ((levelCurrent > levelPrev) && (visibleChars > 0)) |
|
| 7 skipped lines |
|
| 967 | | 1217 | | if (!isspacechar(ch)) |
|
|
| | | 1219 | | chPrev = ch; |
|
| 970 | | 1221 | | // Fill in the real level of the next line, keeping the current flags as they will be filled in later |
|
| 971 | | 1222 | | int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; |
|
| 11 skipped lines |