"Fossies" - the Fresh Open Source Software Archive

Member "groovy-3.0.9/src/antlr/GroovyLexer.g4" (3 Sep 2021, 22788 Bytes) of package /linux/misc/apache-groovy-src-3.0.9.zip:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "GroovyLexer.g4": 3.0.9_vs_4.0.0-rc-1.

    1 /*
    2  * This file is adapted from the Antlr4 Java grammar which has the following license
    3  *
    4  *  Copyright (c) 2013 Terence Parr, Sam Harwell
    5  *  All rights reserved.
    6  *  [The "BSD licence"]
    7  *
    8  *    http://www.opensource.org/licenses/bsd-license.php
    9  *
   10  * Subsequent modifications by the Groovy community have been done under the Apache License v2:
   11  *
   12  *  Licensed to the Apache Software Foundation (ASF) under one
   13  *  or more contributor license agreements.  See the NOTICE file
   14  *  distributed with this work for additional information
   15  *  regarding copyright ownership.  The ASF licenses this file
   16  *  to you under the Apache License, Version 2.0 (the
   17  *  "License"); you may not use this file except in compliance
   18  *  with the License.  You may obtain a copy of the License at
   19  *
   20  *    http://www.apache.org/licenses/LICENSE-2.0
   21  *
   22  *  Unless required by applicable law or agreed to in writing,
   23  *  software distributed under the License is distributed on an
   24  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   25  *  KIND, either express or implied.  See the License for the
   26  *  specific language governing permissions and limitations
   27  *  under the License.
   28  */
   29 
   30 /**
   31  * The Groovy grammar is based on the official grammar for Java:
   32  * https://github.com/antlr/grammars-v4/blob/master/java/Java.g4
   33  */
   34 lexer grammar GroovyLexer;
   35 
   36 options {
   37     superClass = AbstractLexer;
   38 }
   39 
   40 @header {
   41     import java.util.Deque;
   42     import java.util.ArrayDeque;
   43     import java.util.Map;
   44     import java.util.HashMap;
   45     import java.util.Set;
   46     import java.util.HashSet;
   47     import java.util.Collections;
   48     import java.util.Arrays;
   49     import java.util.stream.IntStream;
   50     import java.util.logging.Logger;
   51     import java.util.logging.Level;
   52     import java.util.EmptyStackException;
   53     import org.apache.groovy.util.Maps;
   54     import static org.apache.groovy.parser.antlr4.SemanticPredicates.*;
   55 }
   56 
   57 @members {
   58     private static final Logger LOGGER = Logger.getLogger(GroovyLexer.class.getName());
   59 
   60     private boolean errorIgnored;
   61     private long tokenIndex;
   62     private int  lastTokenType;
   63     private int  invalidDigitCount;
   64 
   65     /**
   66      * Record the index and token type of the current token while emitting tokens.
   67      */
   68     @Override
   69     public void emit(Token token) {
   70         this.tokenIndex++;
   71 
   72         int tokenType = token.getType();
   73         if (Token.DEFAULT_CHANNEL == token.getChannel()) {
   74             this.lastTokenType = tokenType;
   75         }
   76 
   77         if (RollBackOne == tokenType) {
   78             this.rollbackOneChar();
   79         }
   80 
   81         super.emit(token);
   82     }
   83 
   84     private static final int[] REGEX_CHECK_ARRAY = {
   85         DEC,
   86         INC,
   87         THIS,
   88         RBRACE,
   89         RBRACK,
   90         RPAREN,
   91         GStringEnd,
   92         NullLiteral,
   93         StringLiteral,
   94         BooleanLiteral,
   95         IntegerLiteral,
   96         FloatingPointLiteral,
   97         Identifier, CapitalizedIdentifier
   98     };
   99     static {
  100         Arrays.sort(REGEX_CHECK_ARRAY);
  101     }
  102 
  103     private boolean isRegexAllowed() {
  104         return (Arrays.binarySearch(REGEX_CHECK_ARRAY, this.lastTokenType) < 0);
  105     }
  106 
  107     /**
  108      * just a hook, which will be overrided by GroovyLangLexer
  109      */
  110     protected void rollbackOneChar() {}
  111 
  112     private static class Paren {
  113         private String text;
  114         private int lastTokenType;
  115         private int line;
  116         private int column;
  117 
  118         public Paren(String text, int lastTokenType, int line, int column) {
  119             this.text = text;
  120             this.lastTokenType = lastTokenType;
  121             this.line = line;
  122             this.column = column;
  123         }
  124 
  125         public String getText() {
  126             return this.text;
  127         }
  128 
  129         public int getLastTokenType() {
  130             return this.lastTokenType;
  131         }
  132 
  133         public int getLine() {
  134             return line;
  135         }
  136 
  137         public int getColumn() {
  138             return column;
  139         }
  140 
  141         @Override
  142         public int hashCode() {
  143             return (int) (text.hashCode() * line + column);
  144         }
  145 
  146         @Override
  147         public boolean equals(Object obj) {
  148             if (!(obj instanceof Paren)) {
  149                 return false;
  150             }
  151 
  152             Paren other = (Paren) obj;
  153 
  154             return this.text.equals(other.text) && (this.line == other.line && this.column == other.column);
  155         }
  156     }
  157 
  158     protected void enterParenCallback(String text) {}
  159 
  160     protected void exitParenCallback(String text) {}
  161 
  162     private final Deque<Paren> parenStack = new ArrayDeque<>(32);
  163 
  164     private void enterParen() {
  165         String text = getText();
  166         enterParenCallback(text);
  167 
  168         parenStack.push(new Paren(text, this.lastTokenType, getLine(), getCharPositionInLine()));
  169     }
  170 
  171     private void exitParen() {
  172         String text = getText();
  173         exitParenCallback(text);
  174 
  175         Paren paren = parenStack.peek();
  176         if (null == paren) return;
  177         parenStack.pop();
  178     }
  179     private boolean isInsideParens() {
  180         Paren paren = parenStack.peek();
  181 
  182         // We just care about "(" and "[", inside which the new lines will be ignored.
  183         // Notice: the new lines between "{" and "}" can not be ignored.
  184         if (null == paren) {
  185             return false;
  186         }
  187 
  188         return ("(".equals(paren.getText()) && TRY != paren.getLastTokenType()) // we don't treat try-paren(i.e. try (....)) as parenthesis
  189                     || "[".equals(paren.getText());
  190     }
  191     private void ignoreTokenInsideParens() {
  192         if (!this.isInsideParens()) {
  193             return;
  194         }
  195 
  196         this.setChannel(Token.HIDDEN_CHANNEL);
  197     }
  198     private void ignoreMultiLineCommentConditionally() {
  199         if (!this.isInsideParens() && isFollowedByWhiteSpaces(_input)) {
  200             return;
  201         }
  202 
  203         this.setChannel(Token.HIDDEN_CHANNEL);
  204     }
  205 
  206     @Override
  207     public int getSyntaxErrorSource() {
  208         return GroovySyntaxError.LEXER;
  209     }
  210 
  211     @Override
  212     public int getErrorLine() {
  213         return getLine();
  214     }
  215 
  216     @Override
  217     public int getErrorColumn() {
  218         return getCharPositionInLine() + 1;
  219     }
  220 
  221     @Override
  222     public int popMode() {
  223         try {
  224             return super.popMode();
  225         } catch (EmptyStackException ignored) { // raised when parens are unmatched: too many ), ], or }
  226             if (LOGGER.isLoggable(Level.FINEST)) {
  227                 LOGGER.finest(org.codehaus.groovy.runtime.DefaultGroovyMethods.asString(ignored));
  228             }
  229         }
  230 
  231         return Integer.MIN_VALUE;
  232     }
  233 
  234     private static boolean isJavaIdentifierStartAndNotIdentifierIgnorable(int codePoint) {
  235         return Character.isJavaIdentifierStart(codePoint) && !Character.isIdentifierIgnorable(codePoint);
  236     }
  237 
  238     private static boolean isJavaIdentifierPartAndNotIdentifierIgnorable(int codePoint) {
  239         return Character.isJavaIdentifierPart(codePoint) && !Character.isIdentifierIgnorable(codePoint);
  240     }
  241 
  242     public boolean isErrorIgnored() {
  243         return errorIgnored;
  244     }
  245 
  246     public void setErrorIgnored(boolean errorIgnored) {
  247         this.errorIgnored = errorIgnored;
  248     }
  249 }
  250 
  251 
  252 // §3.10.5 String Literals
  253 StringLiteral
  254     :   GStringQuotationMark  DqStringCharacter*  GStringQuotationMark
  255     |   SqStringQuotationMark  SqStringCharacter*  SqStringQuotationMark
  256     |   Slash { this.isRegexAllowed() && _input.LA(1) != '*' }?  SlashyStringCharacter+  Slash
  257 
  258     |   TdqStringQuotationMark  TdqStringCharacter*  TdqStringQuotationMark
  259     |   TsqStringQuotationMark  TsqStringCharacter*  TsqStringQuotationMark
  260     |   DollarSlashyGStringQuotationMarkBegin  DollarSlashyStringCharacter+  DollarSlashyGStringQuotationMarkEnd
  261     ;
  262 
  263 GStringBegin
  264     :   GStringQuotationMark DqStringCharacter* Dollar -> pushMode(DQ_GSTRING_MODE), pushMode(GSTRING_TYPE_SELECTOR_MODE)
  265     ;
  266 TdqGStringBegin
  267     :   TdqStringQuotationMark   TdqStringCharacter* Dollar -> type(GStringBegin), pushMode(TDQ_GSTRING_MODE), pushMode(GSTRING_TYPE_SELECTOR_MODE)
  268     ;
  269 SlashyGStringBegin
  270     :   Slash { this.isRegexAllowed() && _input.LA(1) != '*' }? SlashyStringCharacter* Dollar { isFollowedByJavaLetterInGString(_input) }? -> type(GStringBegin), pushMode(SLASHY_GSTRING_MODE), pushMode(GSTRING_TYPE_SELECTOR_MODE)
  271     ;
  272 DollarSlashyGStringBegin
  273     :   DollarSlashyGStringQuotationMarkBegin DollarSlashyStringCharacter* Dollar { isFollowedByJavaLetterInGString(_input) }? -> type(GStringBegin), pushMode(DOLLAR_SLASHY_GSTRING_MODE), pushMode(GSTRING_TYPE_SELECTOR_MODE)
  274     ;
  275 
  276 mode DQ_GSTRING_MODE;
  277 GStringEnd
  278     :   GStringQuotationMark     -> popMode
  279     ;
  280 GStringPart
  281     :   Dollar  -> pushMode(GSTRING_TYPE_SELECTOR_MODE)
  282     ;
  283 GStringCharacter
  284     :   DqStringCharacter -> more
  285     ;
  286 
  287 mode TDQ_GSTRING_MODE;
  288 TdqGStringEnd
  289     :   TdqStringQuotationMark    -> type(GStringEnd), popMode
  290     ;
  291 TdqGStringPart
  292     :   Dollar   -> type(GStringPart), pushMode(GSTRING_TYPE_SELECTOR_MODE)
  293     ;
  294 TdqGStringCharacter
  295     :   TdqStringCharacter -> more
  296     ;
  297 
  298 mode SLASHY_GSTRING_MODE;
  299 SlashyGStringEnd
  300     :   Dollar? Slash  -> type(GStringEnd), popMode
  301     ;
  302 SlashyGStringPart
  303     :   Dollar { isFollowedByJavaLetterInGString(_input) }?   -> type(GStringPart), pushMode(GSTRING_TYPE_SELECTOR_MODE)
  304     ;
  305 SlashyGStringCharacter
  306     :   SlashyStringCharacter -> more
  307     ;
  308 
  309 mode DOLLAR_SLASHY_GSTRING_MODE;
  310 DollarSlashyGStringEnd
  311     :   DollarSlashyGStringQuotationMarkEnd      -> type(GStringEnd), popMode
  312     ;
  313 DollarSlashyGStringPart
  314     :   Dollar { isFollowedByJavaLetterInGString(_input) }?   -> type(GStringPart), pushMode(GSTRING_TYPE_SELECTOR_MODE)
  315     ;
  316 DollarSlashyGStringCharacter
  317     :   DollarSlashyStringCharacter -> more
  318     ;
  319 
  320 mode GSTRING_TYPE_SELECTOR_MODE;
  321 GStringLBrace
  322     :   '{' { this.enterParen();  } -> type(LBRACE), popMode, pushMode(DEFAULT_MODE)
  323     ;
  324 GStringIdentifier
  325     :   IdentifierInGString -> type(Identifier), popMode, pushMode(GSTRING_PATH_MODE)
  326     ;
  327 
  328 
  329 mode GSTRING_PATH_MODE;
  330 GStringPathPart
  331     :   Dot IdentifierInGString
  332     ;
  333 RollBackOne
  334     :   . {
  335             // a trick to handle GStrings followed by EOF properly
  336             int readChar = _input.LA(-1);
  337             if (EOF == _input.LA(1) && ('"' == readChar || '/' == readChar)) {
  338                 setType(GStringEnd);
  339             } else {
  340                 setChannel(HIDDEN);
  341             }
  342           } -> popMode
  343     ;
  344 
  345 
  346 mode DEFAULT_MODE;
  347 // character in the double quotation string. e.g. "a"
  348 fragment
  349 DqStringCharacter
  350     :   ~["\r\n\\$]
  351     |   EscapeSequence
  352     ;
  353 
  354 // character in the single quotation string. e.g. 'a'
  355 fragment
  356 SqStringCharacter
  357     :   ~['\r\n\\]
  358     |   EscapeSequence
  359     ;
  360 
  361 // character in the triple double quotation string. e.g. """a"""
  362 fragment TdqStringCharacter
  363     :   ~["\\$]
  364     |   GStringQuotationMark { _input.LA(1) != '"' || _input.LA(2) != '"' || _input.LA(3) == '"' && (_input.LA(4) != '"' || _input.LA(5) != '"') }?
  365     |   EscapeSequence
  366     ;
  367 
  368 // character in the triple single quotation string. e.g. '''a'''
  369 fragment TsqStringCharacter
  370     :   ~['\\]
  371     |   SqStringQuotationMark { _input.LA(1) != '\'' || _input.LA(2) != '\'' || _input.LA(3) == '\'' && (_input.LA(4) != '\'' || _input.LA(5) != '\'') }?
  372     |   EscapeSequence
  373     ;
  374 
  375 // character in the slashy string. e.g. /a/
  376 fragment SlashyStringCharacter
  377     :   SlashEscape
  378     |   Dollar { !isFollowedByJavaLetterInGString(_input) }?
  379     |   ~[/$\u0000]
  380     ;
  381 
  382 // character in the dollar slashy string. e.g. $/a/$
  383 fragment DollarSlashyStringCharacter
  384     :   DollarSlashEscape | DollarDollarEscape
  385     |   Slash { _input.LA(1) != '$' }?
  386     |   Dollar { !isFollowedByJavaLetterInGString(_input) }?
  387     |   ~[/$\u0000]
  388     ;
  389 
  390 // Groovy keywords
  391 AS              : 'as';
  392 DEF             : 'def';
  393 IN              : 'in';
  394 TRAIT           : 'trait';
  395 THREADSAFE      : 'threadsafe'; // reserved keyword
  396 
  397 // the reserved type name of Java10
  398 VAR             : 'var';
  399 
  400 // §3.9 Keywords
  401 BuiltInPrimitiveType
  402     :   BOOLEAN
  403     |   CHAR
  404     |   BYTE
  405     |   SHORT
  406     |   INT
  407     |   LONG
  408     |   FLOAT
  409     |   DOUBLE
  410     ;
  411 
  412 ABSTRACT      : 'abstract';
  413 ASSERT        : 'assert';
  414 
  415 fragment
  416 BOOLEAN       : 'boolean';
  417 
  418 BREAK         : 'break';
  419 
  420 fragment
  421 BYTE          : 'byte';
  422 
  423 CASE          : 'case';
  424 CATCH         : 'catch';
  425 
  426 fragment
  427 CHAR          : 'char';
  428 
  429 CLASS         : 'class';
  430 CONST         : 'const';
  431 CONTINUE      : 'continue';
  432 DEFAULT       : 'default';
  433 DO            : 'do';
  434 
  435 fragment
  436 DOUBLE        : 'double';
  437 
  438 ELSE          : 'else';
  439 ENUM          : 'enum';
  440 EXTENDS       : 'extends';
  441 FINAL         : 'final';
  442 FINALLY       : 'finally';
  443 
  444 fragment
  445 FLOAT         : 'float';
  446 
  447 
  448 FOR           : 'for';
  449 IF            : 'if';
  450 GOTO          : 'goto';
  451 IMPLEMENTS    : 'implements';
  452 IMPORT        : 'import';
  453 INSTANCEOF    : 'instanceof';
  454 
  455 fragment
  456 INT           : 'int';
  457 
  458 INTERFACE     : 'interface';
  459 
  460 fragment
  461 LONG          : 'long';
  462 
  463 NATIVE        : 'native';
  464 NEW           : 'new';
  465 PACKAGE       : 'package';
  466 PRIVATE       : 'private';
  467 PROTECTED     : 'protected';
  468 PUBLIC        : 'public';
  469 RETURN        : 'return';
  470 
  471 fragment
  472 SHORT         : 'short';
  473 
  474 
  475 STATIC        : 'static';
  476 STRICTFP      : 'strictfp';
  477 SUPER         : 'super';
  478 SWITCH        : 'switch';
  479 SYNCHRONIZED  : 'synchronized';
  480 THIS          : 'this';
  481 THROW         : 'throw';
  482 THROWS        : 'throws';
  483 TRANSIENT     : 'transient';
  484 TRY           : 'try';
  485 VOID          : 'void';
  486 VOLATILE      : 'volatile';
  487 WHILE         : 'while';
  488 
  489 
  490 // §3.10.1 Integer Literals
  491 
  492 IntegerLiteral
  493     :   (   DecimalIntegerLiteral
  494         |   HexIntegerLiteral
  495         |   OctalIntegerLiteral
  496         |   BinaryIntegerLiteral
  497         ) (Underscore { require(errorIgnored, "Number ending with underscores is invalid", -1, true); })?
  498 
  499     // !!! Error Alternative !!!
  500     |   Zero ([0-9] { invalidDigitCount++; })+ { require(errorIgnored, "Invalid octal number", -(invalidDigitCount + 1), true); } IntegerTypeSuffix?
  501     ;
  502 
  503 fragment
  504 Zero
  505     :   '0'
  506     ;
  507 
  508 fragment
  509 DecimalIntegerLiteral
  510     :   DecimalNumeral IntegerTypeSuffix?
  511     ;
  512 
  513 fragment
  514 HexIntegerLiteral
  515     :   HexNumeral IntegerTypeSuffix?
  516     ;
  517 
  518 fragment
  519 OctalIntegerLiteral
  520     :   OctalNumeral IntegerTypeSuffix?
  521     ;
  522 
  523 fragment
  524 BinaryIntegerLiteral
  525     :   BinaryNumeral IntegerTypeSuffix?
  526     ;
  527 
  528 fragment
  529 IntegerTypeSuffix
  530     :   [lLiIgG]
  531     ;
  532 
  533 fragment
  534 DecimalNumeral
  535     :   Zero
  536     |   NonZeroDigit (Digits? | Underscores Digits)
  537     ;
  538 
  539 fragment
  540 Digits
  541     :   Digit (DigitOrUnderscore* Digit)?
  542     ;
  543 
  544 fragment
  545 Digit
  546     :   Zero
  547     |   NonZeroDigit
  548     ;
  549 
  550 fragment
  551 NonZeroDigit
  552     :   [1-9]
  553     ;
  554 
  555 fragment
  556 DigitOrUnderscore
  557     :   Digit
  558     |   Underscore
  559     ;
  560 
  561 fragment
  562 Underscores
  563     :   Underscore+
  564     ;
  565 
  566 fragment
  567 Underscore
  568     :   '_'
  569     ;
  570 
  571 fragment
  572 HexNumeral
  573     :   Zero [xX] HexDigits
  574     ;
  575 
  576 fragment
  577 HexDigits
  578     :   HexDigit (HexDigitOrUnderscore* HexDigit)?
  579     ;
  580 
  581 fragment
  582 HexDigit
  583     :   [0-9a-fA-F]
  584     ;
  585 
  586 fragment
  587 HexDigitOrUnderscore
  588     :   HexDigit
  589     |   Underscore
  590     ;
  591 
  592 fragment
  593 OctalNumeral
  594     :   Zero Underscores? OctalDigits
  595     ;
  596 
  597 fragment
  598 OctalDigits
  599     :   OctalDigit (OctalDigitOrUnderscore* OctalDigit)?
  600     ;
  601 
  602 fragment
  603 OctalDigit
  604     :   [0-7]
  605     ;
  606 
  607 fragment
  608 OctalDigitOrUnderscore
  609     :   OctalDigit
  610     |   Underscore
  611     ;
  612 
  613 fragment
  614 BinaryNumeral
  615     :   Zero [bB] BinaryDigits
  616     ;
  617 
  618 fragment
  619 BinaryDigits
  620     :   BinaryDigit (BinaryDigitOrUnderscore* BinaryDigit)?
  621     ;
  622 
  623 fragment
  624 BinaryDigit
  625     :   [01]
  626     ;
  627 
  628 fragment
  629 BinaryDigitOrUnderscore
  630     :   BinaryDigit
  631     |   Underscore
  632     ;
  633 
  634 // §3.10.2 Floating-Point Literals
  635 
  636 FloatingPointLiteral
  637     :   (   DecimalFloatingPointLiteral
  638         |   HexadecimalFloatingPointLiteral
  639         ) (Underscore { require(errorIgnored, "Number ending with underscores is invalid", -1, true); })?
  640     ;
  641 
  642 fragment
  643 DecimalFloatingPointLiteral
  644     :   Digits? Dot Digits ExponentPart? FloatTypeSuffix?
  645     |   Digits ExponentPart FloatTypeSuffix?
  646     |   Digits FloatTypeSuffix
  647     ;
  648 
  649 fragment
  650 ExponentPart
  651     :   ExponentIndicator SignedInteger
  652     ;
  653 
  654 fragment
  655 ExponentIndicator
  656     :   [eE]
  657     ;
  658 
  659 fragment
  660 SignedInteger
  661     :   Sign? Digits
  662     ;
  663 
  664 fragment
  665 Sign
  666     :   [+\-]
  667     ;
  668 
  669 fragment
  670 FloatTypeSuffix
  671     :   [fFdDgG]
  672     ;
  673 
  674 fragment
  675 HexadecimalFloatingPointLiteral
  676     :   HexSignificand BinaryExponent FloatTypeSuffix?
  677     ;
  678 
  679 fragment
  680 HexSignificand
  681     :   HexNumeral Dot?
  682     |   Zero [xX] HexDigits? Dot HexDigits
  683     ;
  684 
  685 fragment
  686 BinaryExponent
  687     :   BinaryExponentIndicator SignedInteger
  688     ;
  689 
  690 fragment
  691 BinaryExponentIndicator
  692     :   [pP]
  693     ;
  694 
  695 fragment
  696 Dot :   '.'
  697     ;
  698 
  699 // §3.10.3 Boolean Literals
  700 
  701 BooleanLiteral
  702     :   'true'
  703     |   'false'
  704     ;
  705 
  706 
  707 // §3.10.6 Escape Sequences for Character and String Literals
  708 
  709 fragment
  710 EscapeSequence
  711     :   Backslash [btnfrs"'\\]
  712     |   OctalEscape
  713     |   UnicodeEscape
  714     |   DollarEscape
  715     |   LineEscape
  716     ;
  717 
  718 
  719 fragment
  720 OctalEscape
  721     :   Backslash OctalDigit
  722     |   Backslash OctalDigit OctalDigit
  723     |   Backslash ZeroToThree OctalDigit OctalDigit
  724     ;
  725 
  726 // Groovy allows 1 or more u's after the backslash
  727 fragment
  728 UnicodeEscape
  729     :   Backslash 'u' HexDigit HexDigit HexDigit HexDigit
  730     ;
  731 
  732 fragment
  733 ZeroToThree
  734     :   [0-3]
  735     ;
  736 
  737 // Groovy Escape Sequences
  738 
  739 fragment
  740 DollarEscape
  741     :   Backslash Dollar
  742     ;
  743 
  744 fragment
  745 LineEscape
  746     :   Backslash LineTerminator
  747     ;
  748 
  749 fragment
  750 LineTerminator
  751     :   '\r'? '\n' | '\r'
  752     ;
  753 
  754 fragment
  755 SlashEscape
  756     :   Backslash Slash
  757     ;
  758 
  759 fragment
  760 Backslash
  761     :   '\\'
  762     ;
  763 
  764 fragment
  765 Slash
  766     :   '/'
  767     ;
  768 
  769 fragment
  770 Dollar
  771     :   '$'
  772     ;
  773 
  774 fragment
  775 GStringQuotationMark
  776     :   '"'
  777     ;
  778 
  779 fragment
  780 SqStringQuotationMark
  781     :   '\''
  782     ;
  783 
  784 fragment
  785 TdqStringQuotationMark
  786     :   '"""'
  787     ;
  788 
  789 fragment
  790 TsqStringQuotationMark
  791     :   '\'\'\''
  792     ;
  793 
  794 fragment
  795 DollarSlashyGStringQuotationMarkBegin
  796     :   '$/'
  797     ;
  798 
  799 fragment
  800 DollarSlashyGStringQuotationMarkEnd
  801     :   '/$'
  802     ;
  803 
  804 fragment
  805 DollarSlashEscape
  806     :   '$/'
  807     ;
  808 
  809 fragment
  810 DollarDollarEscape
  811     :   '$$'
  812     ;
  813 
  814 // §3.10.7 The Null Literal
  815 NullLiteral
  816     :   'null'
  817     ;
  818 
  819 // Groovy Operators
  820 
  821 RANGE_INCLUSIVE     : '..';
  822 RANGE_EXCLUSIVE     : '..<';
  823 SPREAD_DOT          : '*.';
  824 SAFE_DOT            : '?.';
  825 SAFE_CHAIN_DOT      : '??.';
  826 ELVIS               : '?:';
  827 METHOD_POINTER      : '.&';
  828 METHOD_REFERENCE    : '::';
  829 REGEX_FIND          : '=~';
  830 REGEX_MATCH         : '==~';
  831 POWER               : '**';
  832 POWER_ASSIGN        : '**=';
  833 SPACESHIP           : '<=>';
  834 IDENTICAL           : '===';
  835 NOT_IDENTICAL       : '!==';
  836 ARROW               : '->';
  837 
  838 // !internalPromise will be parsed as !in ternalPromise, so semantic predicates are necessary
  839 NOT_INSTANCEOF      : '!instanceof' { isFollowedBy(_input, ' ', '\t', '\r', '\n') }?;
  840 NOT_IN              : '!in'         { isFollowedBy(_input, ' ', '\t', '\r', '\n', '[', '(', '{') }?;
  841 
  842 
  843 // §3.11 Separators
  844 
  845 LPAREN          : '('  { this.enterParen();     } -> pushMode(DEFAULT_MODE);
  846 RPAREN          : ')'  { this.exitParen();      } -> popMode;
  847 
  848 LBRACE          : '{'  { this.enterParen();     } -> pushMode(DEFAULT_MODE);
  849 RBRACE          : '}'  { this.exitParen();      } -> popMode;
  850 
  851 LBRACK          : '['  { this.enterParen();     } -> pushMode(DEFAULT_MODE);
  852 RBRACK          : ']'  { this.exitParen();      } -> popMode;
  853 
  854 SEMI            : ';';
  855 COMMA           : ',';
  856 DOT             : Dot;
  857 
  858 // §3.12 Operators
  859 
  860 ASSIGN          : '=';
  861 GT              : '>';
  862 LT              : '<';
  863 NOT             : '!';
  864 BITNOT          : '~';
  865 QUESTION        : '?';
  866 COLON           : ':';
  867 EQUAL           : '==';
  868 LE              : '<=';
  869 GE              : '>=';
  870 NOTEQUAL        : '!=';
  871 AND             : '&&';
  872 OR              : '||';
  873 INC             : '++';
  874 DEC             : '--';
  875 ADD             : '+';
  876 SUB             : '-';
  877 MUL             : '*';
  878 DIV             : Slash;
  879 BITAND          : '&';
  880 BITOR           : '|';
  881 XOR             : '^';
  882 MOD             : '%';
  883 
  884 
  885 ADD_ASSIGN      : '+=';
  886 SUB_ASSIGN      : '-=';
  887 MUL_ASSIGN      : '*=';
  888 DIV_ASSIGN      : '/=';
  889 AND_ASSIGN      : '&=';
  890 OR_ASSIGN       : '|=';
  891 XOR_ASSIGN      : '^=';
  892 MOD_ASSIGN      : '%=';
  893 LSHIFT_ASSIGN   : '<<=';
  894 RSHIFT_ASSIGN   : '>>=';
  895 URSHIFT_ASSIGN  : '>>>=';
  896 ELVIS_ASSIGN    : '?=';
  897 
  898 
  899 // §3.8 Identifiers (must appear after all keywords in the grammar)
  900 CapitalizedIdentifier
  901     :   JavaLetter {Character.isUpperCase(_input.LA(-1))}? JavaLetterOrDigit*
  902     ;
  903 
  904 Identifier
  905     :   JavaLetter JavaLetterOrDigit*
  906     ;
  907 
  908 fragment
  909 IdentifierInGString
  910     :   JavaLetterInGString JavaLetterOrDigitInGString*
  911     ;
  912 
  913 fragment
  914 JavaLetter
  915     :   [a-zA-Z$_] // these are the "java letters" below 0x7F
  916     |   // covers all characters above 0x7F which are not a surrogate
  917         ~[\u0000-\u007F\uD800-\uDBFF]
  918         { isJavaIdentifierStartAndNotIdentifierIgnorable(_input.LA(-1)) }?
  919     |   // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF
  920         [\uD800-\uDBFF] [\uDC00-\uDFFF]
  921         { Character.isJavaIdentifierStart(Character.toCodePoint((char) _input.LA(-2), (char) _input.LA(-1))) }?
  922     ;
  923 
  924 fragment
  925 JavaLetterInGString
  926     :   JavaLetter { _input.LA(-1) != '$' }?
  927     ;
  928 
  929 fragment
  930 JavaLetterOrDigit
  931     :   [a-zA-Z0-9$_] // these are the "java letters or digits" below 0x7F
  932     |   // covers all characters above 0x7F which are not a surrogate
  933         ~[\u0000-\u007F\uD800-\uDBFF]
  934         { isJavaIdentifierPartAndNotIdentifierIgnorable(_input.LA(-1)) }?
  935     |   // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF
  936         [\uD800-\uDBFF] [\uDC00-\uDFFF]
  937         { Character.isJavaIdentifierPart(Character.toCodePoint((char) _input.LA(-2), (char) _input.LA(-1))) }?
  938     ;
  939 
  940 fragment
  941 JavaLetterOrDigitInGString
  942     :   JavaLetterOrDigit  { _input.LA(-1) != '$' }?
  943     ;
  944 
  945 fragment
  946 ShCommand
  947     :   ~[\r\n\uFFFF]*
  948     ;
  949 
  950 //
  951 // Additional symbols not defined in the lexical specification
  952 //
  953 
  954 AT : '@';
  955 ELLIPSIS : '...';
  956 
  957 //
  958 // Whitespace, line escape and comments
  959 //
  960 WS  : ([ \t]+ | LineEscape+) -> skip
  961     ;
  962 
  963 // Inside (...) and [...] but not {...}, ignore newlines.
  964 NL  : LineTerminator   { this.ignoreTokenInsideParens(); }
  965     ;
  966 
  967 // Multiple-line comments (including groovydoc comments)
  968 ML_COMMENT
  969     :   '/*' .*? '*/'       { this.ignoreMultiLineCommentConditionally(); } -> type(NL)
  970     ;
  971 
  972 // Single-line comments
  973 SL_COMMENT
  974     :   '//' ~[\r\n\uFFFF]* { this.ignoreTokenInsideParens(); }             -> type(NL)
  975     ;
  976 
  977 // Script-header comments.
  978 // The very first characters of the file may be "#!".  If so, ignore the first line.
  979 SH_COMMENT
  980     :   '#!' { require(errorIgnored || 0 == this.tokenIndex, "Shebang comment should appear at the first line", -2, true); } ShCommand (LineTerminator '#!' ShCommand)* -> skip
  981     ;
  982 
  983 // Unexpected characters will be handled by groovy parser later.
  984 UNEXPECTED_CHAR
  985     :   . { require(errorIgnored, "Unexpected character: '" + getText().replace("'", "\\'") + "'", -1, false); }
  986     ;