• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Camelcade / Perl5-IDEA / #525521660

24 Aug 2025 01:28PM UTC coverage: 75.89% (-6.3%) from 82.227%
#525521660

push

github

hurricup
Migrated coverage reporting to https://github.com/nbaztec/coveralls-jacoco-gradle-plugin

See: https://github.com/kt3k/coveralls-gradle-plugin/issues/119

14751 of 22639 branches covered (65.16%)

Branch coverage included in aggregate %.

31091 of 37767 relevant lines covered (82.32%)

0.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.99
/plugin/common/src/main/java/com/perl5/lang/perl/lexer/adapters/PerlSublexingLexerAdapter.java
1
/*
2
 * Copyright 2015-2025 Alexandr Evstigneev
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package com.perl5.lang.perl.lexer.adapters;
18

19
/**
20
 * First level adapter, relexes lazy blocks if necessary
21
 *
22
 * @see com.perl5.lang.perl.lexer.adapters.PerlMergingLexerAdapter
23
 */
24

25
import com.intellij.lexer.FlexAdapter;
26
import com.intellij.lexer.Lexer;
27
import com.intellij.lexer.LexerBase;
28
import com.intellij.openapi.diagnostic.Logger;
29
import com.intellij.openapi.progress.ProgressManager;
30
import com.intellij.psi.tree.IElementType;
31
import com.perl5.lang.perl.lexer.PerlLexer;
32
import com.perl5.lang.perl.lexer.PerlLexingContext;
33
import com.perl5.lang.perl.lexer.PerlProtoLexer;
34
import org.jetbrains.annotations.NotNull;
35
import org.jetbrains.annotations.Nullable;
36

37
import java.util.HashMap;
38
import java.util.Map;
39

40
import static com.perl5.lang.perl.parser.PerlElementTypesGenerated.*;
41

42
public class PerlSublexingLexerAdapter extends LexerBase {
43
  private static final Logger LOG = Logger.getInstance(FlexAdapter.class);
1✔
44
  private static final Map<IElementType, Integer> SUBLEXINGS_MAP = new HashMap<>();
1✔
45
  private static final Map<IElementType, Integer> ENFORCED_SUBLEXINGS_MAP = new HashMap<>();
1✔
46

47
  static {
48
    SUBLEXINGS_MAP.put(LP_STRING_Q, PerlLexer.STRING_Q);
1✔
49
    SUBLEXINGS_MAP.put(LP_STRING_QQ, PerlLexer.STRING_QQ);
1✔
50
    SUBLEXINGS_MAP.put(LP_STRING_TR, PerlLexer.STRING_TR_BEGIN);
1✔
51
    SUBLEXINGS_MAP.put(LP_STRING_RE, PerlLexer.STRING_RE);
1✔
52
    SUBLEXINGS_MAP.put(LP_STRING_QX, PerlLexer.STRING_QX);
1✔
53
    SUBLEXINGS_MAP.put(LP_STRING_QQ_RESTRICTED, PerlLexer.STRING_QQ_RESTRICTED);
1✔
54
    SUBLEXINGS_MAP.put(LP_STRING_QX_RESTRICTED, PerlLexer.STRING_QX_RESTRICTED);
1✔
55
    SUBLEXINGS_MAP.put(LP_CODE_BLOCK, PerlLexer.YYINITIAL);
1✔
56
    SUBLEXINGS_MAP.put(LP_CODE_BLOCK_WITH_TRYCATCH, PerlLexer.YYINITIAL);
1✔
57
    SUBLEXINGS_MAP.put(LP_STRING_QW, PerlLexer.STRING_LIST);
1✔
58
    SUBLEXINGS_MAP.put(LP_REGEX, PerlLexer.MATCH_REGEX);
1✔
59
    SUBLEXINGS_MAP.put(LP_REGEX_X, PerlLexer.MATCH_REGEX_X);
1✔
60
    SUBLEXINGS_MAP.put(LP_REGEX_XX, PerlLexer.MATCH_REGEX_XX);
1✔
61
    SUBLEXINGS_MAP.put(LP_REGEX_SQ, PerlLexer.MATCH_REGEX_SQ);
1✔
62
    SUBLEXINGS_MAP.put(LP_REGEX_X_SQ, PerlLexer.MATCH_REGEX_X_SQ);
1✔
63
    SUBLEXINGS_MAP.put(LP_REGEX_XX_SQ, PerlLexer.MATCH_REGEX_XX_SQ);
1✔
64

65
    ENFORCED_SUBLEXINGS_MAP.put(COMMENT_ANNOTATION, PerlLexer.ANNOTATION);
1✔
66
    ENFORCED_SUBLEXINGS_MAP.put(HEREDOC, PerlLexer.STRING_Q);
1✔
67
    ENFORCED_SUBLEXINGS_MAP.put(HEREDOC_QQ, PerlLexer.STRING_QQ);
1✔
68
    ENFORCED_SUBLEXINGS_MAP.put(HEREDOC_QX, PerlLexer.STRING_QX);
1✔
69
  }
1✔
70

71
  private final @NotNull PerlProtoLexer myPerlLexer;
72
  private final @NotNull FlexAdapter myFlexAdapter;
73
  private final @NotNull PerlLexingContext myLexingContext;
74
  private boolean myIsSublexing = false;
1✔
75
  private PerlSublexingLexerAdapter mySubLexer;
76
  private int myTokenStart;
77
  private int myTokenEnd;
78
  private int myState;
79
  private IElementType myTokenType;
80
  private char mySingleOpenQuoteChar = 0;
1✔
81
  private int myAdvancesCounter = 0;
1✔
82

83
  public PerlSublexingLexerAdapter(@NotNull PerlLexingContext perlLexingContext) {
84
    this(new PerlLexer(null).withProject(perlLexingContext.getProject()), perlLexingContext);
1✔
85
  }
1✔
86

87
  public PerlSublexingLexerAdapter(@NotNull PerlProtoLexer perlLexer, @NotNull PerlLexingContext lexingContext) {
1✔
88
    myPerlLexer = perlLexer;
1✔
89
    myFlexAdapter = new FlexAdapter(perlLexer);
1✔
90
    myLexingContext = lexingContext;
1✔
91
  }
1✔
92

93
  /**
94
   * Starts lexing of single quoted string content
95
   */
96
  public void start(@NotNull CharSequence buffer,
97
                    int startOffset,
98
                    int endOffset,
99
                    int subLexingState,
100
                    char openQuoteChar) {
101
    LOG.assertTrue(subLexingState == PerlLexer.STRING_Q || subLexingState == PerlLexer.STRING_LIST);
1!
102
    start(buffer, startOffset, endOffset, subLexingState);
1✔
103
    PerlLexer perlLexer = getPerlLexer();
1✔
104
    if (perlLexer == null) {
1!
105
      LOG.error("Expected to get perl lexer, got " + myPerlLexer);
×
106
      return;
×
107
    }
108
    perlLexer.setSingleOpenQuoteChar(openQuoteChar);
1✔
109
  }
1✔
110

111
  @Override
112
  public void start(@NotNull CharSequence buffer, int startOffset, int endOffset, int initialState) {
113
    PerlLexingContext lexingContext = getLexingContext();
1✔
114
    getFlexAdapter().start(buffer, startOffset, endOffset, initialState);
1✔
115
    PerlLexer perlLexer = getPerlLexer();
1✔
116
    if (perlLexer != null) {
1✔
117
      perlLexer.setSingleOpenQuoteChar(lexingContext.getOpenChar());
1✔
118
      perlLexer.setHasTryCatch(lexingContext.isWithTryCatch());
1✔
119
    }
120
    myTokenStart = myTokenEnd = startOffset;
1✔
121
    myTokenType = null;
1✔
122
    myIsSublexing = false;
1✔
123
  }
1✔
124

125
  private @Nullable PerlLexer getPerlLexer() {
126
    return myPerlLexer instanceof PerlLexer perlLexer ? perlLexer : null;
1✔
127
  }
128

129
  private @NotNull FlexAdapter getFlexAdapter() {
130
    return myFlexAdapter;
1!
131
  }
132

133
  private @NotNull PerlLexingContext getLexingContext() {
134
    return myLexingContext;
1!
135
  }
136

137
  @Override
138
  public int getState() {
139
    locateToken();
1✔
140
    return myState;
1✔
141
  }
142

143
  @Override
144
  public IElementType getTokenType() {
145
    locateToken();
1✔
146
    return myTokenType;
1✔
147
  }
148

149
  @Override
150
  public int getTokenStart() {
151
    locateToken();
1✔
152
    return myTokenStart;
1✔
153
  }
154

155
  @Override
156
  public int getTokenEnd() {
157
    locateToken();
1✔
158
    return myTokenEnd;
1✔
159
  }
160

161
  @Override
162
  public void advance() {
163
    if (++myAdvancesCounter % PerlProgressAwareAdapter.CHECK_CANCEL_EACH_TOKEN == 0) {
1✔
164
      ProgressManager.checkCanceled();
1✔
165
    }
166
    locateToken();
1✔
167
    myTokenType = null;
1✔
168
  }
1✔
169

170
  @Override
171
  public @NotNull CharSequence getBufferSequence() {
172
    return getFlexAdapter().getBufferSequence();
1!
173
  }
174

175
  @Override
176
  public int getBufferEnd() {
177
    return getFlexAdapter().getBufferEnd();
×
178
  }
179

180
  private @NotNull PerlSublexingLexerAdapter getSubLexer() {
181
    if (mySubLexer == null) {
1✔
182
      mySubLexer = new PerlSublexingLexerAdapter(getLexingContext().withOpenChar((char)0));
1✔
183
    }
184
    return mySubLexer;
1!
185
  }
186

187
  protected void locateToken() {
188
    if (myTokenType != null) {
1✔
189
      return;
1✔
190
    }
191

192
    if (myIsSublexing) {
1✔
193
      lexToken(mySubLexer);
1✔
194

195
      if (myTokenType != null) {
1✔
196
        myState = PerlLexer.PREPARSED_ITEMS;
1✔
197
        return;
1✔
198
      }
199

200
      // sublexing finished
201
      myIsSublexing = false;
1✔
202
    }
203

204
    lexToken(getFlexAdapter());
1✔
205

206
    Integer subLexingState = SUBLEXINGS_MAP.get(myTokenType);
1✔
207

208
    boolean enforceSubLexing = getLexingContext().isEnforceSubLexing();
1✔
209
    if (subLexingState != null) {
1✔
210
      subLexCurrentToken(subLexingState);
1✔
211
    }
212
    else if (enforceSubLexing) {
1✔
213
      Integer initialState = ENFORCED_SUBLEXINGS_MAP.get(myTokenType);
1✔
214
      if (initialState != null) {
1✔
215
        subLexCurrentToken(initialState);
1✔
216
      }
217
    }
218
  }
1✔
219

220
  private void subLexCurrentToken(Integer subLexingState) {
221
    PerlSublexingLexerAdapter subLexer = getSubLexer();
1✔
222
    if (subLexingState == PerlLexer.STRING_Q || subLexingState == PerlLexer.STRING_LIST) {
1✔
223
      subLexer.start(getBufferSequence(), myTokenStart, myTokenEnd, subLexingState, mySingleOpenQuoteChar);
1✔
224
    }
225
    else {
226
      subLexer.start(getBufferSequence(), myTokenStart, myTokenEnd, subLexingState);
1✔
227
    }
228
    myIsSublexing = true;
1✔
229
    myTokenType = null;
1✔
230
    locateToken();
1✔
231
  }
1✔
232

233
  private void lexToken(Lexer lexer) {
234
    myTokenType = lexer.getTokenType();
1✔
235
    if (myTokenType == QUOTE_SINGLE_OPEN) {
1✔
236
      CharSequence tokenSequence = lexer.getTokenSequence();
1✔
237
      if (tokenSequence.length() != 1) {
1!
238
        LOG.error("Got: " + tokenSequence);
×
239
      }
240
      mySingleOpenQuoteChar = tokenSequence.charAt(0);
1✔
241
    }
1✔
242
    else if (myTokenType == QUOTE_SINGLE_CLOSE) {
1✔
243
      mySingleOpenQuoteChar = 0;
1✔
244
    }
245
    myTokenStart = lexer.getTokenStart();
1✔
246
    myState = lexer.getState();
1✔
247
    myTokenEnd = lexer.getTokenEnd();
1✔
248
    lexer.advance();
1✔
249
  }
1✔
250
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc