• 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.71
/tt2/common/src/main/java/com/perl5/lang/tt2/parser/TemplateToolkitParserUtil.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.tt2.parser;
18

19
import com.intellij.lang.LighterASTNode;
20
import com.intellij.lang.PsiBuilder;
21
import com.intellij.lang.WhitespacesBinders;
22
import com.intellij.lang.parser.GeneratedParserUtilBase;
23
import com.intellij.psi.TokenType;
24
import com.intellij.psi.tree.IElementType;
25
import com.intellij.psi.tree.TokenSet;
26
import com.perl5.lang.tt2.TemplateToolkitBundle;
27
import com.perl5.lang.tt2.elementTypes.TemplateToolkitTokenSets;
28
import com.perl5.lang.tt2.lexer.TemplateToolkitSyntaxElements;
29
import org.jetbrains.annotations.NotNull;
30

31
import static com.perl5.lang.tt2.elementTypes.TemplateToolkitElementTypes.*;
32
import static com.perl5.lang.tt2.parser.TemplateToolkitElementTypesGenerated.*;
33

34

35
@SuppressWarnings("Duplicates")
36
public class TemplateToolkitParserUtil extends GeneratedParserUtilBase {
×
37

38
  public static final TokenSet BLOCK_CONTAINERS = TokenSet.create(
1✔
39
    IF_BLOCK,
40
    UNLESS_BLOCK,
41
    FOREACH_BLOCK,
42
    FILTER_BLOCK,
43
    PERL_BLOCK,
44
    RAWPERL_BLOCK,
45
    WHILE_BLOCK,
46
    SWITCH_BLOCK,
47
    TRY_CATCH_BLOCK,
48
    WRAPPER_BLOCK,
49
    NAMED_BLOCK,
50
    ANON_BLOCK
51
  );
52

53
  @SuppressWarnings("StaticMethodOnlyUsedInOneClass")
54
  public static boolean parseIdentifier(PsiBuilder b, int ignoredL) {
55
    if (consumeToken(b, TT2_IDENTIFIER)) {
1✔
56
      return true;
1✔
57
    }
58
    else if (TemplateToolkitSyntaxElements.POSSIBLE_IDENTIFIERS.contains(b.getTokenType())) {
1✔
59
      PsiBuilder.Marker m = b.mark();
1✔
60
      b.advanceLexer();
1✔
61
      m.collapse(TT2_IDENTIFIER);
1✔
62
      return true;
1✔
63
    }
64
    return false;
1✔
65
  }
66

67
  @SuppressWarnings("StaticMethodOnlyUsedInOneClass")
68
  public static boolean parseHashKey(@NotNull PsiBuilder b, int l, @NotNull Parser keywordOrIdentifierTermParser) {
69
    PsiBuilder.Marker m = b.mark();
1✔
70
    if (keywordOrIdentifierTermParser.parse(b, l)) {
1✔
71
      m.collapse(TT2_STRING_CONTENT);
1✔
72
      m.precede().done(SQ_STRING_EXPR);
1✔
73
      return true;
1✔
74
    }
75

76
    return false;
1✔
77
  }
78

79
  private static boolean isEndMarker(PsiBuilder b) {
80
    IElementType tokenType = b.getTokenType();
1✔
81
    return tokenType == TT2_HARD_NEWLINE || isBlockEndMarker(b);
1✔
82
  }
83

84
  private static boolean isBlockEndMarker(PsiBuilder b) {
85
    IElementType tokenType = b.getTokenType();
1✔
86
    return tokenType == TT2_SEMI || tokenType == TT2_CLOSE_TAG;
1✔
87
  }
88

89
  public static boolean parseFileAsString(PsiBuilder b, int ignoredL) {
90
    if (b.eof()) {
1!
91
      return false;
×
92
    }
93

94
    if (isEndMarker(b)) {
1✔
95
      return false;
1✔
96
    }
97

98
    boolean gotItem = false;
1✔
99
    PsiBuilder.Marker stringMarker = b.mark();
1✔
100
    while (!b.eof()) {
1!
101
      if (isEndMarker(b)) {
1✔
102
        break;
1✔
103
      }
104

105
      boolean isLastToken = TemplateToolkitTokenSets.WHITE_SPACES.contains(b.rawLookup(1));
1✔
106

107
      PsiBuilder.Marker m = b.mark();
1✔
108
      b.advanceLexer();
1✔
109
      m.collapse(TT2_STRING_CONTENT);
1✔
110

111
      gotItem = true;
1✔
112

113
      if (isLastToken) {
1✔
114
        break;
1✔
115
      }
116
    }
1✔
117

118
    if (gotItem) {
1!
119
      stringMarker.done(SQ_STRING_EXPR);
1✔
120
    }
121
    else {
122
      stringMarker.drop();
×
123
    }
124
    return gotItem;
1✔
125
  }
126

127
  @SuppressWarnings("StaticMethodOnlyUsedInOneClass")
128
  public static boolean parseBlockComment(PsiBuilder b, int ignoredL) {
129
    if (b.getTokenType() == TT2_OPEN_TAG && b.rawLookup(1) == LINE_COMMENT) {
1✔
130
      PsiBuilder.Marker m = b.mark();
1✔
131
      b.advanceLexer(); // open
1✔
132
      b.advanceLexer(); // close  fixme add unclosed handling
1✔
133

134
      m.done(BLOCK_COMMENT);
1✔
135
      return true;
1✔
136
    }
137
    return false;
1✔
138
  }
139

140
  public static boolean parseMacroBody(@NotNull PsiBuilder b, int l, @NotNull Parser directiveParser) {
141
    boolean r = false;
1✔
142
    LighterASTNode latestDoneMarker = null;
1✔
143
    PsiBuilder.Marker outerMarker = b.mark();
1✔
144

145
    if (directiveParser.parse(b, l)) {
1!
146
      latestDoneMarker = b.getLatestDoneMarker();
1✔
147

148
      PsiBuilder.Marker m = null;
1✔
149
      while (!b.eof()) {
1✔
150
        if (isEndMarker(b)) {
1✔
151
          break;
1✔
152
        }
153
        if (m == null) {
1✔
154
          m = b.mark();
1✔
155
        }
156
        b.advanceLexer();
1✔
157
      }
158

159
      if (m != null) {
1✔
160
        m.error(TemplateToolkitBundle.message("ttk2.unexpected.token"));
1✔
161
      }
162

163
      consumeToken(b, TT2_HARD_NEWLINE);
1✔
164
      consumeToken(b, TT2_SEMI);
1✔
165
      consumeToken(b, TT2_CLOSE_TAG);
1✔
166

167
      r = true;
1✔
168
    }
169

170
    processMarkers(b, l, latestDoneMarker, outerMarker);
1✔
171

172
    return r;
1✔
173
  }
174

175

176
  public static boolean parseDirective(@NotNull PsiBuilder b, int l, @NotNull Parser directiveParser) {
177
    IElementType tokenType = b.getTokenType();
1✔
178
    boolean r = false;
1✔
179
    LighterASTNode latestDoneMarker = null;
1✔
180
    PsiBuilder.Marker outerMarker = b.mark();
1✔
181
    boolean isAfterSemi = tokenType != TT2_OPEN_TAG && tokenType != TT2_OUTLINE_TAG && isAfterSemi(b);
1✔
182

183
    if (isAfterSemi || tokenType == TT2_OPEN_TAG) {
1✔
184
      if (!isAfterSemi) {
1✔
185
        b.advanceLexer();
1✔
186
      }
187

188
      if (directiveParser.parse(b, l)) {
1!
189
        latestDoneMarker = b.getLatestDoneMarker();
1✔
190
      }
191

192
      if (latestDoneMarker == null || latestDoneMarker.getTokenType() != MACRO_DIRECTIVE) {
1!
193
        PsiBuilder.Marker m = null;
1✔
194
        while (!b.eof()) {
1✔
195
          if (isBlockEndMarker(b)) {
1✔
196
            break;
1✔
197
          }
198
          if (m == null) {
1✔
199
            m = b.mark();
1✔
200
          }
201
          b.advanceLexer();
1✔
202
        }
203

204
        if (m != null) {
1✔
205
          m.error(TemplateToolkitBundle.message("ttk2.unexpected.token"));
1✔
206
        }
207

208
        consumeToken(b, TT2_SEMI);
1✔
209
        consumeToken(b, TT2_CLOSE_TAG);
1✔
210
      }
211
      r = true;
1✔
212
    }
213
    else if (tokenType == TT2_OUTLINE_TAG) {
1✔
214
      b.advanceLexer();
1✔
215

216
      if (directiveParser.parse(b, l)) {
1!
217
        latestDoneMarker = b.getLatestDoneMarker();
1✔
218
      }
219

220
      if (latestDoneMarker == null || latestDoneMarker.getTokenType() != MACRO_DIRECTIVE) {
1!
221

222
        PsiBuilder.Marker m = null;
1✔
223

224
        while (!b.eof()) {
1✔
225
          if (b.getTokenType() == TT2_HARD_NEWLINE) {
1✔
226
            break;
1✔
227
          }
228
          if (m == null) {
1!
229
            m = b.mark();
1✔
230
          }
231
          b.advanceLexer();
1✔
232
        }
233

234
        if (m != null) {
1✔
235
          m.error(TemplateToolkitBundle.message("ttk2.unexpected.token"));
1✔
236
        }
237
        if (b.getTokenType() == TT2_HARD_NEWLINE) {
1✔
238
          b.remapCurrentToken(TokenType.WHITE_SPACE);
1✔
239
          b.advanceLexer();
1✔
240
        }
241
      }
242
      r = true;
1✔
243
    }
244

245
    processMarkers(b, l, latestDoneMarker, outerMarker);
1✔
246

247
    return r;
1✔
248
  }
249

250

251
  protected static void processMarkers(PsiBuilder b, int l, LighterASTNode latestDoneMarker, PsiBuilder.Marker outerMarker) {
252
    if (latestDoneMarker == null) {
1✔
253
      outerMarker.drop();
1✔
254
      return;
1✔
255
    }
256

257
    IElementType tokenType = latestDoneMarker.getTokenType();
1✔
258
    if (tokenType == BLOCK_DIRECTIVE) {
1✔
259
      parseBlockContent(b, l, outerMarker, NAMED_BLOCK);
1✔
260
    }
261
    else if (tokenType == ANON_BLOCK_DIRECTIVE) {
1✔
262
      parseBlockContent(b, l, outerMarker, ANON_BLOCK);
1✔
263
    }
264
    else if (tokenType == WRAPPER_DIRECTIVE) {
1✔
265
      parseBlockContent(b, l, outerMarker, WRAPPER_BLOCK);
1✔
266
    }
267
    else if (tokenType == FOREACH_DIRECTIVE) {
1✔
268
      parseBlockContent(b, l, outerMarker, FOREACH_BLOCK);
1✔
269
    }
270
    else if (tokenType == WHILE_DIRECTIVE) {
1✔
271
      parseBlockContent(b, l, outerMarker, WHILE_BLOCK);
1✔
272
    }
273
    else if (tokenType == FILTER_DIRECTIVE) {
1✔
274
      parseBlockContent(b, l, outerMarker, FILTER_BLOCK);
1✔
275
    }
276
    else if (tokenType == PERL_DIRECTIVE) {
1✔
277
      parsePerlCode(b, l, outerMarker, TT2_PERL_CODE, PERL_BLOCK);
1✔
278
    }
279
    else if (tokenType == RAWPERL_DIRECTIVE) {
1✔
280
      parsePerlCode(b, l, outerMarker, TT2_RAWPERL_CODE, RAWPERL_BLOCK);
1✔
281
    }
282
    else if (tokenType == SWITCH_DIRECTIVE) {
1✔
283
      parseSwitchBlockContent(b, l);
1✔
284
      outerMarker.done(SWITCH_BLOCK);
1✔
285
    }
286
    else if (tokenType == TRY_DIRECTIVE) {
1✔
287
      PsiBuilder.Marker branchMarker = outerMarker;
1✔
288
      outerMarker = outerMarker.precede();
1✔
289
      parseTryCatchBlock(b, l, branchMarker, TRY_BRANCH);
1✔
290
      outerMarker.done(TRY_CATCH_BLOCK);
1✔
291
    }
1✔
292
    else if (tokenType == IF_DIRECTIVE) {
1✔
293
      PsiBuilder.Marker branchMarker = outerMarker;
1✔
294
      outerMarker = outerMarker.precede();
1✔
295
      parseIfSequence(b, l, branchMarker, IF_BRANCH);
1✔
296
      outerMarker.done(IF_BLOCK);
1✔
297
    }
1✔
298
    else if (tokenType == UNLESS_DIRECTIVE) {
1✔
299
      PsiBuilder.Marker branchMarker = outerMarker;
1✔
300
      outerMarker = outerMarker.precede();
1✔
301
      parseIfSequence(b, l, branchMarker, UNLESS_BRANCH);
1✔
302
      outerMarker.done(UNLESS_BLOCK);
1✔
303
    }
1✔
304
    else {
305
      outerMarker.drop();
1✔
306
    }
307
  }
1✔
308

309

310
  /**
311
   * Parses block content
312
   *
313
   * @param b builder
314
   * @param l level
315
   * @return result of end parsing.
316
   */
317
  @SuppressWarnings("UnusedReturnValue")
318
  public static boolean parseBlockContent(PsiBuilder b, int l, PsiBuilder.Marker outerMarker, IElementType blockTokenType) {
319
    boolean r = false;
1✔
320
    while (!b.eof() && TemplateToolkitParserGenerated.element(b, l)) {
1!
321
      LighterASTNode latestDoneMarker = b.getLatestDoneMarker();
1✔
322
      if (latestDoneMarker != null && latestDoneMarker.getTokenType() == END_DIRECTIVE) {
1!
323
        r = true;
1✔
324
        break;
1✔
325
      }
326
    }
1✔
327

328
    outerMarker.done(blockTokenType);
1✔
329
    if (!r) // this can happen on incomplete block, missing end
1✔
330
    {
331
      outerMarker.setCustomEdgeTokenBinders(WhitespacesBinders.DEFAULT_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
332
      outerMarker.precede().error(TemplateToolkitBundle.message("ttk2.error.unclosed.block.directive"));
1✔
333
    }
334

335
    return r;
1✔
336
  }
337

338
  /**
339
   * Collapses perl code for lazy parsing
340
   *
341
   * @param b builder
342
   * @param l level
343
   * @return result of end parsing.
344
   */
345
  @SuppressWarnings({"UnusedReturnValue", "SameReturnValue"})
346
  public static boolean parsePerlCode(PsiBuilder b,
347
                                      int l,
348
                                      PsiBuilder.Marker outerMarker,
349
                                      IElementType perlTokenType,
350
                                      IElementType blockTokenType) {
351
    PsiBuilder.Marker perlMarker = b.mark();
1✔
352
    while (!b.eof() && !isEndTagAhead(b, l)) {
1✔
353
      b.advanceLexer();
1✔
354
    }
355
    boolean recoverBlock = true;
1✔
356

357
    if (isEndTagAhead(b, l)) {
1✔
358
      perlMarker.collapse(perlTokenType);
1✔
359
      perlMarker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
360
    }
361
    else {
362
      perlMarker.drop();
1✔
363
    }
364

365
    if (TemplateToolkitParserGenerated.element(b, l)) {
1✔
366
      LighterASTNode latestDoneMarker = b.getLatestDoneMarker();
1✔
367

368
      if (latestDoneMarker != null && latestDoneMarker.getTokenType() == END_DIRECTIVE) {
1!
369
        outerMarker.done(blockTokenType);
1✔
370
        recoverBlock = false;
1✔
371
      }
372
    }
373

374
    if (recoverBlock) {
1✔
375
      while (!b.eof() || b.getTokenType() == TT2_OUTLINE_TAG || b.getTokenType() == TT2_OPEN_TAG) {
1!
376
        b.advanceLexer();
×
377
      }
378

379
      outerMarker.done(blockTokenType);
1✔
380
      outerMarker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
381
      outerMarker.precede().error(TemplateToolkitBundle.message("ttk2.error.unclosed.perl.block"));
1✔
382
    }
383

384
    return true;
1✔
385
  }
386

387

388
  protected static boolean isEndTagAhead(PsiBuilder b, int ignoredL) {
389
    IElementType tokenType = b.getTokenType();
1✔
390
    return (tokenType == TT2_OPEN_TAG || tokenType == TT2_OUTLINE_TAG) && b.lookAhead(1) == TT2_END;
1✔
391
  }
392

393
  @SuppressWarnings({"UnusedReturnValue", "SameReturnValue"})
394
  public static boolean parseIfSequence(PsiBuilder b, int l, PsiBuilder.Marker branchMarker, IElementType branchTokenType) {
395
    while (!b.eof()) {
1✔
396
      PsiBuilder.Marker currentMarker = b.mark();
1✔
397
      if (TemplateToolkitParserGenerated.element(b, l)) {
1!
398
        LighterASTNode latestDoneMarker = b.getLatestDoneMarker();
1✔
399
        if (latestDoneMarker != null) {
1!
400
          if (latestDoneMarker.getTokenType() == END_DIRECTIVE) {
1✔
401
            branchMarker.doneBefore(branchTokenType, currentMarker);
1✔
402
            branchMarker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
403
            currentMarker.drop();
1✔
404
            branchMarker = null;
1✔
405
            break;
1✔
406
          }
407
          else if (latestDoneMarker.getTokenType() == ELSIF_DIRECTIVE) {
1✔
408
            branchMarker.doneBefore(branchTokenType, currentMarker);
1✔
409
            branchMarker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
410
            branchMarker = currentMarker.precede();
1✔
411
            branchTokenType = ELSIF_BRANCH;
1✔
412
          }
413
          else if (latestDoneMarker.getTokenType() == ELSE_DIRECTIVE) {
1✔
414
            branchMarker.doneBefore(branchTokenType, currentMarker);
1✔
415
            branchMarker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
416
            branchMarker = currentMarker.precede();
1✔
417
            branchTokenType = ELSE_BRANCH;
1✔
418
          }
419
          else {
420
            currentMarker.error(TemplateToolkitBundle.message("ttk2.else.elsif.end.expected"));
1✔
421
          }
422
          currentMarker.drop();
1✔
423
        }
424
      }
1✔
425
      else {
426
        b.advanceLexer();
×
427
        currentMarker.error(TemplateToolkitBundle.message("ttk2.unexpected.token"));
×
428
      }
429
    }
1✔
430

431
    if (branchMarker != null) {
1✔
432
      branchMarker.done(branchTokenType);
1✔
433
      branchMarker.precede().error(TemplateToolkitBundle.message("ttk2.error.unclosed.block.directive"));
1✔
434
      branchMarker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
435
    }
436

437
    return true;
1✔
438
  }
439

440
  @SuppressWarnings({"UnusedReturnValue", "SameReturnValue"})
441
  public static boolean parseTryCatchBlock(PsiBuilder b, int l, PsiBuilder.Marker branchMarker, IElementType branchTokenType) {
442
    while (!b.eof()) {
1✔
443
      PsiBuilder.Marker currentMarker = b.mark();
1✔
444
      if (TemplateToolkitParserGenerated.element(b, l)) {
1!
445
        LighterASTNode latestDoneMarker = b.getLatestDoneMarker();
1✔
446
        if (latestDoneMarker != null) {
1!
447
          if (latestDoneMarker.getTokenType() == END_DIRECTIVE) {
1✔
448
            branchMarker.doneBefore(branchTokenType, currentMarker);
1✔
449
            branchMarker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
450
            currentMarker.drop();
1✔
451
            branchMarker = null;
1✔
452
            break;
1✔
453
          }
454
          else if (latestDoneMarker.getTokenType() == CATCH_DIRECTIVE) {
1✔
455
            branchMarker.doneBefore(branchTokenType, currentMarker);
1✔
456
            branchMarker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
457
            branchMarker = currentMarker.precede();
1✔
458
            branchTokenType = CATCH_BRANCH;
1✔
459
          }
460
          else if (latestDoneMarker.getTokenType() == FINAL_DIRECTIVE) {
1✔
461
            branchMarker.doneBefore(branchTokenType, currentMarker);
1✔
462
            branchMarker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
463
            branchMarker = currentMarker.precede();
1✔
464
            branchTokenType = FINAL_BRANCH;
1✔
465
          }
466
          else {
467
            currentMarker.error(TemplateToolkitBundle.message("ttk2.catch.final.end.expected"));
1✔
468
          }
469
          currentMarker.drop();
1✔
470
        }
471
      }
1✔
472
      else {
473
        b.advanceLexer();
×
474
        currentMarker.error(TemplateToolkitBundle.message("ttk2.unexpected.token"));
×
475
      }
476
    }
1✔
477

478
    if (branchMarker != null) {
1✔
479
      branchMarker.done(branchTokenType);
1✔
480
      branchMarker.precede().error(TemplateToolkitBundle.message("ttk2.error.unclosed.block.directive"));
1✔
481
      branchMarker.setCustomEdgeTokenBinders(WhitespacesBinders.GREEDY_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
482
    }
483

484
    return true;
1✔
485
  }
486

487
  @SuppressWarnings({"UnusedReturnValue", "SameReturnValue"})
488
  public static boolean parseSwitchBlockContent(PsiBuilder b, int l) {
489
    PsiBuilder.Marker branchMarker = null;
1✔
490
    while (!b.eof()) {
1✔
491
      PsiBuilder.Marker currentMarker = b.mark();
1✔
492
      if (TemplateToolkitParserGenerated.element(b, l)) {
1!
493
        LighterASTNode latestDoneMarker = b.getLatestDoneMarker();
1✔
494
        if (latestDoneMarker != null) {
1!
495
          if (latestDoneMarker.getTokenType() == END_DIRECTIVE) {
1✔
496
            if (branchMarker != null) {
1✔
497
              branchMarker.doneBefore(CASE_BLOCK, currentMarker);
1✔
498
              branchMarker.setCustomEdgeTokenBinders(WhitespacesBinders.DEFAULT_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
499
            }
500
            branchMarker = null;
1✔
501
            currentMarker.drop();
1✔
502
            break;
1✔
503
          }
504
          else if (latestDoneMarker.getTokenType() == CASE_DIRECTIVE) {
1✔
505
            if (branchMarker != null) {
1✔
506
              branchMarker.doneBefore(CASE_BLOCK, currentMarker);
1✔
507
              branchMarker.setCustomEdgeTokenBinders(WhitespacesBinders.DEFAULT_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
508
            }
509
            branchMarker = currentMarker.precede();
1✔
510
          }
511
        }
512
      }
513
      currentMarker.drop();
1✔
514
    }
1✔
515

516
    if (branchMarker != null) {
1✔
517
      branchMarker.done(CASE_BLOCK);
1✔
518
      branchMarker.setCustomEdgeTokenBinders(WhitespacesBinders.DEFAULT_LEFT_BINDER, WhitespacesBinders.GREEDY_RIGHT_BINDER);
1✔
519
    }
520

521
    return true;
1✔
522
  }
523

524
  @SuppressWarnings("SameReturnValue")
525
  public static boolean parseTags(PsiBuilder b, int ignoredL) {
526
    PsiBuilder.Marker m = null;
1✔
527
    while (!b.eof() && !isEndMarker(b)) {
1✔
528
      if (m == null) {
1✔
529
        m = b.mark();
1✔
530
      }
531
      b.advanceLexer();
1✔
532
    }
533

534
    if (m != null) {
1✔
535
      m.collapse(TT2_STRING_CONTENT);
1✔
536
      m.precede().done(SQ_STRING_EXPR);
1✔
537
    }
538

539
    return true;
1✔
540
  }
541

542
  @SuppressWarnings("StaticMethodOnlyUsedInOneClass")
543
  public static boolean parseSetElement(@NotNull PsiBuilder b, int l, @NotNull Parser setElementParser) {
544
    PsiBuilder.Marker m = b.mark();
1✔
545
    if (setElementParser.parse(b, l)) {
1✔
546
      m.done(ASSIGN_EXPR);
1✔
547
      return true;
1✔
548
    }
549
    m.drop();
1✔
550
    return false;
1✔
551
  }
552

553
  protected static boolean isAfterSemi(PsiBuilder b) {
554
    int offset = -1;
1✔
555
    IElementType tokenType;
556

557
    while ((tokenType = b.rawLookup(offset)) != null) {
1✔
558
      if (tokenType == TT2_SEMI) {
1✔
559
        return true;
1✔
560
      }
561
      if (!TemplateToolkitTokenSets.WHITESPACES_AND_COMMENTS.contains(tokenType)) {
1✔
562
        return false;
1✔
563
      }
564
      offset--;
1✔
565
    }
566

567
    return false;
1✔
568
  }
569

570
  @SuppressWarnings("StaticMethodOnlyUsedInOneClass")
571
  public static boolean parseKeywordFallback(PsiBuilder b, int ignoredL) {
572
    if (TemplateToolkitSyntaxElements.KEYWORDS_OR_TEXT_OPERATORS_TOKENSET.contains(b.getTokenType())) {
×
573
      PsiBuilder.Marker m = b.mark();
×
574
      b.advanceLexer();
×
575
      m.error(TemplateToolkitBundle.message("tt2.error.keyword.in.identifier"));
×
576
      return true;
×
577
    }
578

579
    return false;
×
580
  }
581

582
  @SuppressWarnings({"UnusedReturnValue", "StaticMethodOnlyUsedInOneClass"})
583
  public static boolean parseUnaryMinus(PsiBuilder b, int ignoredL) {
584
    if (b.getTokenType() == TT2_MINUS) {
1✔
585
      PsiBuilder.Marker m = b.mark();
1✔
586
      b.advanceLexer();
1✔
587
      m.collapse(TT2_MINUS_UNARY);
1✔
588
      return true;
1✔
589
    }
590
    return false;
1✔
591
  }
592
}
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