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

polserver / polserver / 21108840797

18 Jan 2026 08:35AM UTC coverage: 60.508% (+0.02%) from 60.492%
21108840797

push

github

web-flow
ClangTidy readability-else-after-return (#857)

* trigger tidy

* Automated clang-tidy change: readability-else-after-return

* compile test

* rerun

* Automated clang-tidy change: readability-else-after-return

* trigger..

* Automated clang-tidy change: readability-else-after-return

* manually removed a few

* Automated clang-tidy change: readability-else-after-return

* removed duplicate code

* fix remaining warnings

* fixed scope

---------

Co-authored-by: Clang Tidy <clang-tidy@users.noreply.github.com>

837 of 1874 new or added lines in 151 files covered. (44.66%)

46 existing lines in 25 files now uncovered.

44448 of 73458 relevant lines covered (60.51%)

525066.38 hits per line

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

95.39
/pol-core/bscript/compiler/astbuilder/ExpressionBuilder.cpp
1
#include "ExpressionBuilder.h"
2

3
#include "bscript/compiler/Report.h"
4
#include "bscript/compiler/ast/Argument.h"
5
#include "bscript/compiler/ast/ArrayInitializer.h"
6
#include "bscript/compiler/ast/BinaryOperator.h"
7
#include "bscript/compiler/ast/BooleanValue.h"
8
#include "bscript/compiler/ast/ConditionalOperator.h"
9
#include "bscript/compiler/ast/DictionaryEntry.h"
10
#include "bscript/compiler/ast/DictionaryInitializer.h"
11
#include "bscript/compiler/ast/ElementAccess.h"
12
#include "bscript/compiler/ast/ElementAssignment.h"
13
#include "bscript/compiler/ast/ElementIndexes.h"
14
#include "bscript/compiler/ast/ElvisOperator.h"
15
#include "bscript/compiler/ast/ErrorInitializer.h"
16
#include "bscript/compiler/ast/FormatExpression.h"
17
#include "bscript/compiler/ast/FunctionCall.h"
18
#include "bscript/compiler/ast/FunctionExpression.h"
19
#include "bscript/compiler/ast/FunctionParameterDeclaration.h"
20
#include "bscript/compiler/ast/FunctionParameterList.h"
21
#include "bscript/compiler/ast/FunctionReference.h"
22
#include "bscript/compiler/ast/Identifier.h"
23
#include "bscript/compiler/ast/InterpolateString.h"
24
#include "bscript/compiler/ast/MemberAccess.h"
25
#include "bscript/compiler/ast/MemberAssignment.h"
26
#include "bscript/compiler/ast/MethodCall.h"
27
#include "bscript/compiler/ast/MethodCallArgumentList.h"
28
#include "bscript/compiler/ast/ModuleFunctionDeclaration.h"
29
#include "bscript/compiler/ast/SpreadElement.h"
30
#include "bscript/compiler/ast/StringValue.h"
31
#include "bscript/compiler/ast/StructInitializer.h"
32
#include "bscript/compiler/ast/StructMemberInitializer.h"
33
#include "bscript/compiler/ast/UnaryOperator.h"
34
#include "bscript/compiler/ast/UninitializedValue.h"
35
#include "bscript/compiler/astbuilder/BuilderWorkspace.h"
36
#include "bscript/compiler/model/CompilerWorkspace.h"
37
#include "bscript/compiler/model/ScopeName.h"
38

39
using EscriptGrammar::EscriptParser;
40

41
namespace Pol::Bscript::Compiler
42
{
43
ExpressionBuilder::ExpressionBuilder( const SourceFileIdentifier& source_file_identifier,
13,355✔
44
                                      BuilderWorkspace& workspace )
13,355✔
45
    : ValueBuilder( source_file_identifier, workspace )
13,355✔
46
{
47
}
13,355✔
48

49
void ExpressionBuilder::unhandled_operator( const SourceLocation& source_location )
×
50
{
51
  // This indicates a log error in the compiler: likely a disconnect between the grammar
52
  // and the code building the AST from the parsed file.
53
  source_location.internal_error( "unhandled operator.\n" );
×
54
}
55

56
std::unique_ptr<ArrayInitializer> ExpressionBuilder::array_initializer(
1,896✔
57
    EscriptParser::BareArrayInitializerContext* ctx )
58
{
59
  auto values = expressions( ctx->expressionList() );
1,896✔
60
  return std::make_unique<ArrayInitializer>( location_for( *ctx ), std::move( values ) );
3,792✔
61
}
1,896✔
62

63
std::unique_ptr<InterpolateString> ExpressionBuilder::interpolate_string(
2,302✔
64
    EscriptParser::InterpolatedStringContext* ctx )
65
{
66
  auto values = expressions( ctx->interpolatedStringPart() );
2,302✔
67
  return std::make_unique<InterpolateString>( location_for( *ctx ), std::move( values ) );
4,604✔
68
}
2,302✔
69

70
std::unique_ptr<Expression> ExpressionBuilder::format_expression(
108✔
71
    std::unique_ptr<Expression> expr, antlr4::tree::TerminalNode* format )
72
{
73
  return std::make_unique<FormatExpression>( location_for( *format ), std::move( expr ),
216✔
74
                                             string_value( format, false ) );
324✔
75
}
76

77
std::unique_ptr<ArrayInitializer> ExpressionBuilder::array_initializer(
541✔
78
    EscriptParser::ExplicitArrayInitializerContext* ctx )
79
{
80
  auto values = expressions( ctx->arrayInitializer() );
541✔
81
  return std::make_unique<ArrayInitializer>( location_for( *ctx ), std::move( values ) );
1,082✔
82
}
541✔
83

84
std::unique_ptr<Expression> ExpressionBuilder::binary_operator(
12,663✔
85
    EscriptParser::ExpressionContext* ctx, bool consume )
86
{
87
  auto lhs = expression( ctx->expression( 0 ) );
12,663✔
88
  auto rhs = expression( ctx->expression( 1 ) );
12,663✔
89

90
  BTokenId token_id = binary_operator_token( ctx );
12,663✔
91

92
  if ( token_id == TOK_ASSIGN )
12,663✔
93
  {
94
    if ( auto element_access = dynamic_cast<ElementAccess*>( lhs.get() ) )
4,048✔
95
    {
96
      return std::make_unique<ElementAssignment>(
878✔
97
          location_for( *ctx ), consume, element_access->take_entity(),
878✔
98
          element_access->take_indexes(), std::move( rhs ) );
1,317✔
99
    }
100
    if ( auto get_member = dynamic_cast<MemberAccess*>( lhs.get() ) )
3,609✔
101
    {
102
      return std::make_unique<MemberAssignment>( location_for( *ctx ), consume,
1,116✔
103
                                                 get_member->take_entity(), get_member->name,
1,116✔
104
                                                 std::move( rhs ), get_member->known_member );
1,116✔
105
    }
106
  }
107

108
  if ( token_id == TOK_ADDMEMBER || token_id == TOK_CHKMEMBER || token_id == TOK_DELMEMBER )
11,666✔
109
  {
110
    // On the right-hand side, any of the following are valid:
111
    //   - an identifier: treat as the field name
112
    //   - an expression: evaluate and use as the field name
113
    if ( auto identifier = dynamic_cast<Identifier*>( rhs.get() ) )
187✔
114
    {
115
      rhs = std::make_unique<StringValue>( rhs->source_location, identifier->scoped_name.string() );
184✔
116
    }
117
  }
118

119
  auto op = std::make_unique<BinaryOperator>( location_for( *ctx ), std::move( lhs ),
11,666✔
120
                                              ctx->bop->getText(), token_id, std::move( rhs ) );
23,332✔
121
  if ( consume )
11,666✔
122
    return consume_expression_result( std::move( op ) );
2,805✔
123
  return op;
8,861✔
124
}
12,663✔
125

126
BTokenId ExpressionBuilder::binary_operator_token(
12,663✔
127
    EscriptGrammar::EscriptParser::ExpressionContext* ctx )
128
{
129
  if ( ctx->ADD() )
12,663✔
130
    return TOK_ADD;
3,105✔
131
  if ( ctx->SUB() )
9,558✔
132
    return TOK_SUBTRACT;
519✔
133
  if ( ctx->MUL() )
9,039✔
134
    return TOK_MULT;
274✔
135
  if ( ctx->DIV() )
8,765✔
136
    return TOK_DIV;
99✔
137
  if ( ctx->ASSIGN() )
8,666✔
138
    return TOK_ASSIGN;
4,048✔
139
  if ( ctx->EQUAL() )
4,618✔
140
    return TOK_EQUAL;
1,152✔
141
  if ( ctx->NOTEQUAL_A() || ctx->NOTEQUAL_B() )
3,466✔
142
    return TOK_NEQ;
1,275✔
143
  if ( ctx->LT() )
2,191✔
144
    return TOK_LESSTHAN;
300✔
145
  if ( ctx->LE() )
1,891✔
146
    return TOK_LESSEQ;
103✔
147
  if ( ctx->GT() )
1,788✔
148
    return TOK_GRTHAN;
206✔
149
  if ( ctx->GE() )
1,582✔
150
    return TOK_GREQ;
113✔
151
  if ( ctx->AND_A() || ctx->AND_B() )
1,469✔
152
    return TOK_AND;
162✔
153
  if ( ctx->OR_A() || ctx->OR_B() )
1,307✔
154
    return TOK_OR;
578✔
155
  if ( ctx->ADD_ASSIGN() )
729✔
156
    return TOK_PLUSEQUAL;
106✔
157
  if ( ctx->SUB_ASSIGN() )
623✔
158
    return TOK_MINUSEQUAL;
33✔
159
  if ( ctx->MUL_ASSIGN() )
590✔
160
    return TOK_TIMESEQUAL;
37✔
161
  if ( ctx->DIV_ASSIGN() )
553✔
162
    return TOK_DIVIDEEQUAL;
21✔
163
  if ( ctx->MOD() )
532✔
164
    return TOK_MODULUS;
54✔
165
  if ( ctx->MOD_ASSIGN() )
478✔
166
    return TOK_MODULUSEQUAL;
24✔
167
  if ( ctx->ADDMEMBER() )
454✔
168
    return TOK_ADDMEMBER;
96✔
169
  if ( ctx->DELMEMBER() )
358✔
170
    return TOK_DELMEMBER;
9✔
171
  if ( ctx->CHKMEMBER() )
349✔
172
    return TOK_CHKMEMBER;
82✔
173
  if ( ctx->BITAND() )
267✔
174
    return TOK_BITAND;
28✔
175
  if ( ctx->BITOR() )
239✔
176
    return TOK_BITOR;
46✔
177
  if ( ctx->CARET() )
193✔
178
    return TOK_BITXOR;
21✔
179
  if ( ctx->TOK_IN() )
172✔
180
    return TOK_IN;
75✔
181
  if ( ctx->LSHIFT() )
97✔
182
    return TOK_BSLEFT;
18✔
183
  if ( ctx->RSHIFT() )
79✔
184
    return TOK_BSRIGHT;
18✔
185
  if ( ctx->ADDMEMBER() )
61✔
186
    return TOK_ADDMEMBER;
×
187
  if ( ctx->CHKMEMBER() )
61✔
188
    return TOK_CHKMEMBER;
×
189
  if ( ctx->DELMEMBER() )
61✔
190
    return TOK_DELMEMBER;
×
191
  if ( ctx->IS() )
61✔
192
    return TOK_IS;
61✔
193

NEW
194
  location_for( *ctx ).internal_error( "unrecognized binary operator" );
×
195
}
196

197
std::unique_ptr<DictionaryInitializer> ExpressionBuilder::dictionary_initializer(
164✔
198
    EscriptParser::ExplicitDictInitializerContext* ctx )
199
{
200
  std::vector<std::unique_ptr<Node>> entries;
164✔
201
  if ( auto initializer_ctx = ctx->dictInitializer() )
164✔
202
  {
203
    if ( auto list_ctx = initializer_ctx->dictInitializerExpressionList() )
119✔
204
    {
205
      for ( auto entry_ctx : list_ctx->dictInitializerExpression() )
234✔
206
      {
207
        auto loc = location_for( *entry_ctx );
155✔
208
        auto expressions = entry_ctx->expression();
155✔
209
        bool spread = entry_ctx->ELLIPSIS();
155✔
210

211
        auto key = expression( expressions.at( 0 ) );
155✔
212
        if ( spread )
155✔
213
        {
214
          auto entry = std::make_unique<SpreadElement>( loc, std::move( key ), true );
15✔
215
          entries.push_back( std::move( entry ) );
15✔
216
        }
15✔
217
        else
218
        {
219
          auto value = ( expressions.size() >= 2 ) ? expression( expressions.at( 1 ) )
271✔
220
                                                   : std::make_unique<UninitializedValue>( loc );
271✔
221
          auto entry =
222
              std::make_unique<DictionaryEntry>( loc, std::move( key ), std::move( value ) );
140✔
223
          entries.push_back( std::move( entry ) );
140✔
224
        }
140✔
225
      }
234✔
226
    }
227
  }
228
  auto loc = location_for( *ctx );
164✔
229

230
  return std::make_unique<DictionaryInitializer>( loc, std::move( entries ) );
328✔
231
}
164✔
232

233
std::unique_ptr<ElementAccess> ExpressionBuilder::element_access(
2,219✔
234
    std::unique_ptr<Expression> lhs, EscriptParser::IndexListContext* ctx )
235
{
236
  auto source_location = location_for( *ctx );
2,219✔
237

238
  std::vector<std::unique_ptr<Expression>> indexes;
2,219✔
239
  for ( auto expression_ctx : ctx->expression() )
4,689✔
240
  {
241
    indexes.push_back( expression( expression_ctx ) );
2,470✔
242
  }
2,219✔
243

244
  auto xx = std::make_unique<ElementIndexes>( location_for( *ctx ), std::move( indexes ) );
2,219✔
245

246
  return std::make_unique<ElementAccess>( source_location, std::move( lhs ), std::move( xx ) );
4,438✔
247
}
2,219✔
248

249
std::unique_ptr<ElvisOperator> ExpressionBuilder::elvis_operator(
244✔
250
    EscriptParser::ExpressionContext* ctx )
251
{
252
  auto source_location = location_for( *ctx );
244✔
253
  auto expressions = ctx->expression();
244✔
254
  auto lhs = expression( expressions[0] );
244✔
255
  auto rhs = expression( expressions[1] );
244✔
256
  return std::make_unique<ElvisOperator>( source_location, std::move( lhs ), std::move( rhs ) );
488✔
257
}
244✔
258

259
std::unique_ptr<ConditionalOperator> ExpressionBuilder::conditional_operator(
165✔
260
    EscriptParser::ExpressionContext* ctx )
261
{
262
  auto source_location = location_for( *ctx );
165✔
263
  auto expressions = ctx->expression();
165✔
264
  auto conditional = expression( expressions[0] );
165✔
265
  auto consequent = expression( expressions[1] );
165✔
266
  auto alternate = expression( expressions[2] );
165✔
267

268
  return std::make_unique<ConditionalOperator>( source_location, std::move( conditional ),
165✔
269
                                                std::move( consequent ), std::move( alternate ) );
495✔
270
}
165✔
271

272

273
std::unique_ptr<ErrorInitializer> ExpressionBuilder::error(
297✔
274
    EscriptParser::ExplicitErrorInitializerContext* ctx )
275
{
276
  auto source_location = location_for( *ctx );
297✔
277

278
  std::vector<std::string> identifiers;
297✔
279
  std::vector<std::unique_ptr<Expression>> expressions;
297✔
280

281
  if ( auto struct_initializer = ctx->structInitializer() )
297✔
282
  {
283
    if ( auto expression_list_ctx = struct_initializer->structInitializerExpressionList() )
194✔
284
    {
285
      for ( auto expression_ctx : expression_list_ctx->structInitializerExpression() )
352✔
286
      {
287
        auto expression_source_ctx = location_for( *expression_ctx );
176✔
288
        std::string identifier;
176✔
289
        if ( auto x = expression_ctx->IDENTIFIER() )
176✔
290
          identifier = text( x );
173✔
291
        else if ( auto string_literal = expression_ctx->STRING_LITERAL() )
3✔
292
          identifier = unquote( string_literal );
3✔
293
        else
294
          expression_source_ctx.internal_error(
×
295
              "Unable to determine identifier for struct initializer" );
296

297
        auto value = expression_ctx->expression()
176✔
298
                         ? expression( expression_ctx->expression() )
176✔
299
                         : std::make_unique<UninitializedValue>( expression_source_ctx );
176✔
300

301
        identifiers.push_back( std::move( identifier ) );
176✔
302
        expressions.push_back( std::move( value ) );
176✔
303
      }
352✔
304
    }
305
  }
306

307
  return std::make_unique<ErrorInitializer>( source_location, std::move( identifiers ),
297✔
308
                                             std::move( expressions ) );
891✔
309
}
297✔
310

311
std::vector<std::unique_ptr<Expression>> ExpressionBuilder::expressions(
6,257✔
312
    EscriptParser::ExpressionListContext* ctx )
313
{
314
  std::vector<std::unique_ptr<Expression>> expressions;
6,257✔
315
  if ( ctx )
6,257✔
316
  {
317
    for ( auto entry_ctx : ctx->expressionListEntry() )
14,733✔
318
    {
319
      expressions.push_back( expression( entry_ctx->expression(), false, entry_ctx->ELLIPSIS() ) );
9,605✔
320
    }
5,128✔
321
  }
322
  return expressions;
6,257✔
323
}
×
324

325
std::vector<std::unique_ptr<Expression>> ExpressionBuilder::expressions(
2,302✔
326
    std::vector<EscriptGrammar::EscriptParser::InterpolatedStringPartContext*> ctx )
327
{
328
  std::vector<std::unique_ptr<Expression>> expressions;
2,302✔
329

330
  for ( auto interstringPart_ctx : ctx )
9,814✔
331
  {
332
    if ( auto expression_ctx = interstringPart_ctx->expression() )
7,512✔
333
    {
334
      std::unique_ptr<Expression> expr = expression( expression_ctx );
3,581✔
335
      if ( auto format = interstringPart_ctx->FORMAT_STRING() )
3,581✔
336
      {
337
        expr = format_expression( std::move( expr ), format );
108✔
338
      }
339
      expressions.push_back( std::move( expr ) );
3,581✔
340
    }
3,581✔
341
    else if ( auto string_literal = interstringPart_ctx->STRING_LITERAL_INSIDE() )
3,931✔
342
    {
343
      expressions.push_back( string_value( string_literal, false ) );
3,744✔
344
    }
345
    else if ( auto lbrace = interstringPart_ctx->DOUBLE_LBRACE_INSIDE() )
187✔
346
    {
347
      auto loc = location_for( *lbrace );
42✔
348
      expressions.push_back( std::make_unique<StringValue>( loc, "{" ) );
42✔
349
    }
350
    else if ( auto rbrace = interstringPart_ctx->DOUBLE_RBRACE() )
145✔
351
    {
352
      auto loc = location_for( *rbrace );
36✔
353
      expressions.push_back( std::make_unique<StringValue>( loc, "}" ) );
36✔
354
    }
355
    else if ( auto escaped = interstringPart_ctx->REGULAR_CHAR_INSIDE() )
109✔
356
    {
357
      expressions.push_back( string_value( escaped, false ) );
109✔
358
    }
359
    else
360
    {
361
      location_for( *interstringPart_ctx )
×
362
          .internal_error( "unhandled context in interpolated string part" );
×
363
    }
364
  }
365
  return expressions;
2,302✔
366
}
×
367

368
std::vector<std::unique_ptr<Expression>> ExpressionBuilder::expressions(
541✔
369
    EscriptParser::ArrayInitializerContext* ctx )
370
{
371
  if ( ctx )
541✔
372
  {
373
    if ( auto expression_list = ctx->expressionList() )
515✔
374
    {
375
      return expressions( expression_list );
404✔
376
    }
377
  }
378
  return {};
137✔
379
}
380

381
std::unique_ptr<Expression> ExpressionBuilder::expression( EscriptParser::ExpressionContext* ctx,
380,219✔
382
                                                           bool consume, bool spread )
383
{
384
  std::unique_ptr<Expression> result;
380,219✔
385
  if ( auto prim = ctx->primary() )
380,219✔
386
    result = primary( prim );
346,361✔
387
  else if ( ctx->prefix )
33,858✔
388
    result = prefix_unary_operator( ctx );
9,260✔
389
  else if ( ctx->postfix )
24,598✔
390
    result = postfix_unary_operator( ctx );
160✔
391
  else if ( ctx->bop && ctx->expression().size() == 2 )
24,438✔
392
  {
393
    if ( ctx->ELVIS() )
12,907✔
394
      result = elvis_operator( ctx );
244✔
395
    else
396
      return binary_operator( ctx, consume );
12,663✔
397
  }
398
  else if ( auto suffix = ctx->expressionSuffix() )
11,531✔
399
  {
400
    result = expression_suffix( expression( ctx->expression()[0] ), suffix );
11,366✔
401
  }
402
  else if ( ctx->QUESTION() )
165✔
403
  {
404
    result = conditional_operator( ctx );
165✔
405
  }
406
  else
407
  {
408
    location_for( *ctx ).internal_error( "unhandled expression" );
×
409
  }
410

411
  if ( spread )
367,554✔
412
  {
413
    result = std::make_unique<SpreadElement>( location_for( *ctx ), std::move( result ), false );
611✔
414
  }
415

416
  if ( consume )
367,554✔
417
  {
418
    result = consume_expression_result( std::move( result ) );
13,915✔
419
  }
420

421
  return result;
367,554✔
422
}
380,219✔
423

424
std::unique_ptr<FunctionCall> ExpressionBuilder::function_call(
18,602✔
425
    SourceLocation loc, EscriptParser::FunctionCallContext* ctx, const ScopeName& scope )
426
{
427
  auto method_name = text( ctx->IDENTIFIER() );
18,602✔
428

429
  auto arguments = value_arguments( ctx->expressionList() );
18,602✔
430

431
  ScopableName name( scope, method_name );
18,602✔
432

433
  auto function_call = std::make_unique<FunctionCall>(
434
      std::move( loc ), current_scope_name.string(), name, std::move( arguments ) );
18,602✔
435

436
  workspace.function_resolver.register_function_link( std::move( name ),
18,602✔
437
                                                      function_call->function_link );
18,602✔
438

439
  return function_call;
37,204✔
440
}
18,602✔
441

442
std::unique_ptr<FunctionCall> ExpressionBuilder::function_call(
272✔
443
    std::unique_ptr<Expression> callee,
444
    EscriptGrammar::EscriptParser::FunctionCallSuffixContext* ctx )
445
{
446
  auto arguments = value_arguments( ctx->expressionList() );
272✔
447

448
  auto function_call =
449
      std::make_unique<FunctionCall>( callee->source_location, current_scope_name.string(),
544✔
450
                                      std::move( callee ), std::move( arguments ) );
544✔
451

452
  return function_call;
544✔
453
}
272✔
454

455
std::unique_ptr<MethodCall> ExpressionBuilder::method_call(
3,957✔
456
    std::unique_ptr<Expression> lhs, EscriptParser::MethodCallSuffixContext* ctx )
457
{
458
  auto loc = location_for( *ctx );
3,957✔
459
  auto methodname = text( ctx->IDENTIFIER() );
3,957✔
460
  auto arguments = expressions( ctx->expressionList() );
3,957✔
461

462
  auto argument_list = std::make_unique<MethodCallArgumentList>( loc, std::move( arguments ) );
3,957✔
463
  return std::make_unique<MethodCall>( loc, std::move( lhs ), std::move( methodname ),
3,957✔
464
                                       std::move( argument_list ) );
11,871✔
465
}
3,957✔
466

467
std::unique_ptr<MemberAccess> ExpressionBuilder::navigation(
4,918✔
468
    std::unique_ptr<Expression> lhs, EscriptGrammar::EscriptParser::NavigationSuffixContext* ctx )
469
{
470
  auto loc = location_for( *ctx );
4,918✔
471

472
  std::string name;
4,918✔
473
  if ( auto identifier = ctx->IDENTIFIER() )
4,918✔
474
    name = text( identifier );
4,891✔
475
  else if ( auto string_literal = ctx->STRING_LITERAL() )
27✔
476
    name = unquote( string_literal );
3✔
477
  else if ( auto function_keyword = ctx->FUNCTION() )
24✔
478
    name = text( function_keyword );
24✔
479
  else
480
    loc.internal_error( "member_access: need string literal, function keyword, or identifier" );
×
481
  return std::make_unique<MemberAccess>( loc, std::move( lhs ), std::move( name ) );
9,836✔
482
}
4,918✔
483

484
std::unique_ptr<Expression> ExpressionBuilder::expression_suffix(
11,366✔
485
    std::unique_ptr<Expression> lhs, EscriptParser::ExpressionSuffixContext* ctx )
486
{
487
  if ( auto indexing = ctx->indexingSuffix() )
11,366✔
488
  {
489
    return element_access( std::move( lhs ), indexing->indexList() );
2,219✔
490
  }
491
  if ( auto member = ctx->navigationSuffix() )
9,147✔
492
  {
493
    return navigation( std::move( lhs ), member );
4,918✔
494
  }
495
  if ( auto method = ctx->methodCallSuffix() )
4,229✔
496
  {
497
    return method_call( std::move( lhs ), method );
3,957✔
498
  }
499
  if ( auto function_call_suffix = ctx->functionCallSuffix() )
272✔
500
  {
501
    return function_call( std::move( lhs ), function_call_suffix );
272✔
502
  }
NEW
503
  location_for( *ctx ).internal_error( "unhandled navigation suffix" );
×
504
}
505

506
std::unique_ptr<Expression> ExpressionBuilder::prefix_unary_operator(
9,260✔
507
    EscriptParser::ExpressionContext* ctx )
508
{
509
  auto expression_ctx = ctx->expression( 0 );
9,260✔
510
  auto source_location = location_for( *expression_ctx );
9,260✔
511
  auto expression_ast = expression( expression_ctx );
9,260✔
512

513
  BTokenId token_id;
514
  if ( ctx->ADD() )
9,260✔
515
    token_id = TOK_UNPLUS;
9✔
516
  else if ( ctx->SUB() )
9,251✔
517
    token_id = TOK_UNMINUS;
6,985✔
518
  else if ( ctx->INC() )
2,266✔
519
    token_id = TOK_UNPLUSPLUS;
124✔
520
  else if ( ctx->DEC() )
2,142✔
521
    token_id = TOK_UNMINUSMINUS;
98✔
522
  else if ( ctx->TILDE() )
2,044✔
523
    token_id = TOK_BITWISE_NOT;
24✔
524
  else if ( ctx->BANG_A() || ctx->BANG_B() )
2,020✔
525
    token_id = TOK_LOG_NOT;
2,020✔
526
  else
527
    unhandled_operator( source_location );
×
528

529
  if ( token_id == TOK_UNPLUS )
9,260✔
530
    return expression_ast;
9✔
531

532
  return std::make_unique<UnaryOperator>( source_location, ctx->prefix->getText(), token_id,
18,502✔
533
                                          std::move( expression_ast ) );
18,502✔
534
}
9,260✔
535

536
std::unique_ptr<Expression> ExpressionBuilder::postfix_unary_operator(
160✔
537
    EscriptParser::ExpressionContext* ctx )
538
{
539
  auto loc = location_for( *ctx );
160✔
540
  auto expression_ctx = ctx->expression( 0 );
160✔
541
  auto expression_ast = expression( expression_ctx );
160✔
542

543
  BTokenId token_id;
544
  if ( ctx->INC() )
160✔
545
    token_id = TOK_UNPLUSPLUS_POST;
107✔
546
  else if ( ctx->DEC() )
53✔
547
    token_id = TOK_UNMINUSMINUS_POST;
53✔
548
  else
549
    unhandled_operator( loc );
×
550

551
  return std::make_unique<UnaryOperator>( loc, ctx->postfix->getText(), token_id,
320✔
552
                                          std::move( expression_ast ) );
480✔
553
}
160✔
554

555
std::unique_ptr<Expression> ExpressionBuilder::primary( EscriptParser::PrimaryContext* ctx )
346,361✔
556
{
557
  if ( auto literal = ctx->literal() )
346,361✔
558
  {
559
    return value( literal );
266,964✔
560
  }
561
  if ( auto par_expression = ctx->parExpression() )
79,397✔
562
  {
563
    return expression( par_expression->expression() );
592✔
564
  }
565
  if ( auto scoped_ident = ctx->scopedIdentifier() )
78,805✔
566
  {
567
    return scoped_identifier( scoped_ident );
171✔
568
  }
569
  if ( auto identifier = ctx->IDENTIFIER() )
78,634✔
570
  {
571
    return std::make_unique<Identifier>( location_for( *ctx ), text( identifier ) );
52,390✔
572
  }
573
  if ( auto f_call = ctx->functionCall() )
26,244✔
574
  {
575
    return function_call( location_for( *f_call ), f_call, ScopeName::None );
18,273✔
576
  }
577
  if ( auto scoped_f_call = ctx->scopedFunctionCall() )
7,971✔
578
  {
579
    return scoped_function_call( scoped_f_call );
277✔
580
  }
581
  if ( auto dict_init = ctx->explicitDictInitializer() )
7,694✔
582
  {
583
    return dictionary_initializer( dict_init );
164✔
584
  }
585
  if ( auto struct_init = ctx->explicitStructInitializer() )
7,530✔
586
  {
587
    return struct_initializer( struct_init );
1,080✔
588
  }
589
  if ( auto fr = ctx->functionReference() )
6,450✔
590
  {
591
    return function_reference( fr );
765✔
592
  }
593
  if ( auto fe = ctx->functionExpression() )
5,685✔
594
  {
595
    return function_expression( fe );
675✔
596
  }
597
  if ( auto error_init = ctx->explicitErrorInitializer() )
5,010✔
598
  {
599
    return error( error_init );
297✔
600
  }
601
  if ( auto array_init = ctx->explicitArrayInitializer() )
4,713✔
602
  {
603
    return array_initializer( array_init );
532✔
604
  }
605
  if ( auto bare_array = ctx->bareArrayInitializer() )
4,181✔
606
  {
607
    return array_initializer( bare_array );
1,879✔
608
  }
609
  if ( auto inter_string = ctx->interpolatedString() )
2,302✔
610
  {
611
    return interpolate_string( inter_string );
2,302✔
612
  }
613

614
  location_for( *ctx ).internal_error( "unhandled primary expression" );
×
615
}
616

617
std::unique_ptr<FunctionCall> ExpressionBuilder::scoped_function_call(
280✔
618
    EscriptParser::ScopedFunctionCallContext* ctx )
619
{
620
  auto id = ctx->IDENTIFIER();
280✔
621
  auto scope = id ? ScopeName( text( id ) ) : ScopeName::Global;
280✔
622
  return function_call( location_for( *ctx ), ctx->functionCall(), scope );
560✔
623
}
280✔
624

625
std::unique_ptr<Identifier> ExpressionBuilder::scoped_identifier(
183✔
626
    EscriptGrammar::EscriptParser::ScopedIdentifierContext* ctx )
627
{
628
  auto loc = location_for( *ctx );
183✔
629
  if ( ctx->scope )
183✔
630
  {
631
    ScopeName scope_name( text( ctx->scope ) );
162✔
632
    if ( !scope_name.global() )
162✔
633
    {
634
      // Force a reference to the class so it will be visited by the UserFunctionVisitor.
635
      workspace.function_resolver.force_reference( scope_name, loc );
162✔
636
    }
637

638
    ScopableName scoped_name( std::move( scope_name ), text( ctx->identifier ) );
162✔
639

640
    return std::make_unique<Identifier>( loc, std::move( scoped_name ) );
162✔
641
  }
162✔
642

643
  ScopableName scoped_name( ScopeName::Global, text( ctx->identifier ) );
21✔
644

645
  return std::make_unique<Identifier>( loc,
646
                                       ScopableName( ScopeName::Global, text( ctx->identifier ) ) );
42✔
647
}
21✔
648

649
std::unique_ptr<Expression> ExpressionBuilder::struct_initializer(
1,080✔
650
    EscriptParser::ExplicitStructInitializerContext* ctx )
651
{
652
  std::vector<std::unique_ptr<Node>> initializers;
1,080✔
653

654
  if ( auto struct_init = ctx->structInitializer() )
1,080✔
655
  {
656
    if ( auto expression_list_ctx = struct_init->structInitializerExpressionList() )
1,038✔
657
    {
658
      for ( auto initializer_expression_ctx : expression_list_ctx->structInitializerExpression() )
2,644✔
659
      {
660
        auto loc = location_for( *initializer_expression_ctx );
1,878✔
661
        std::string identifier;
1,878✔
662
        bool spread = initializer_expression_ctx->ELLIPSIS();
1,878✔
663
        if ( auto x = initializer_expression_ctx->IDENTIFIER() )
1,878✔
664
          identifier = text( x );
1,639✔
665
        else if ( auto string_literal = initializer_expression_ctx->STRING_LITERAL() )
239✔
666
          identifier = unquote( string_literal );
230✔
667
        else if ( !spread )
9✔
668
          loc.internal_error( "Unable to determine identifier for struct initializer" );
×
669

670
        if ( auto expression_ctx = initializer_expression_ctx->expression() )
1,878✔
671
        {
672
          auto initializer = expression( expression_ctx );
1,833✔
673
          if ( spread )
1,833✔
674
            initializers.push_back(
9✔
675
                std::make_unique<SpreadElement>( loc, std::move( initializer ), true ) );
18✔
676
          else
677
            initializers.push_back( std::make_unique<StructMemberInitializer>(
1,824✔
678
                loc, std::move( identifier ), std::move( initializer ) ) );
1,824✔
679
        }
1,833✔
680
        else
681
        {
682
          initializers.push_back(
45✔
683
              std::make_unique<StructMemberInitializer>( loc, std::move( identifier ) ) );
90✔
684
        }
685
      }
2,644✔
686
    }
687
  }
688
  return std::make_unique<StructInitializer>( location_for( *ctx ), std::move( initializers ) );
2,160✔
689
}
1,080✔
690

691
std::vector<std::unique_ptr<Argument>> ExpressionBuilder::value_arguments(
18,874✔
692
    EscriptGrammar::EscriptParser::ExpressionListContext* ctx )
693
{
694
  std::vector<std::unique_ptr<Argument>> arguments;
18,874✔
695

696
  if ( ctx )
18,874✔
697
  {
698
    for ( auto argument_context : ctx->expressionListEntry() )
41,843✔
699
    {
700
      auto loc = location_for( *argument_context );
24,141✔
701

702
      std::unique_ptr<Argument> argument = nullptr;
24,141✔
703

704
      auto value =
705
          expression( argument_context->expression(), false, argument_context->ELLIPSIS() );
24,141✔
706

707
      if ( auto binary_operator = dynamic_cast<BinaryOperator*>( value.get() ) )
24,141✔
708
      {
709
        if ( binary_operator->token_id == TOK_ASSIGN )
3,312✔
710
        {
711
          if ( auto identifier = dynamic_cast<Identifier*>( &binary_operator->lhs() ) )
504✔
712
          {
713
            ScopableName name( identifier->scoped_name );
504✔
714
            value = binary_operator->take_rhs();
504✔
715
            argument = std::make_unique<Argument>( loc, name, std::move( value ),
1,008✔
716
                                                   argument_context->ELLIPSIS() );
1,008✔
717
          }
504✔
718
        }
719
      }
720

721
      if ( !argument )
24,141✔
722
      {
723
        argument =
724
            std::make_unique<Argument>( loc, std::move( value ), argument_context->ELLIPSIS() );
23,637✔
725
      }
726

727
      arguments.push_back( std::move( argument ) );
24,141✔
728
    }
41,843✔
729
  }
730

731
  return arguments;
18,874✔
732
}
×
733

734
}  // namespace Pol::Bscript::Compiler
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