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

polserver / polserver / 25918451630

15 May 2026 12:43PM UTC coverage: 60.929% (+2.1%) from 58.859%
25918451630

push

github

turleypol
added dynamic property which returns a pointer of the object instead of
a copy like the current imp.
needed to be able to eg store a vector

43 of 61 new or added lines in 2 files covered. (70.49%)

14455 existing lines in 345 files now uncovered.

44695 of 73356 relevant lines covered (60.93%)

449621.59 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,447✔
44
                                      BuilderWorkspace& workspace )
13,447✔
45
    : ValueBuilder( source_file_identifier, workspace )
13,447✔
46
{
47
}
13,447✔
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(
2,097✔
57
    EscriptParser::BareArrayInitializerContext* ctx )
58
{
59
  auto values = expressions( ctx->expressionList() );
2,097✔
60
  return std::make_unique<ArrayInitializer>( location_for( *ctx ), std::move( values ) );
4,194✔
61
}
2,097✔
62

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

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

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

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

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

92
  if ( token_id == TOK_ASSIGN )
12,977✔
93
  {
94
    if ( auto element_access = dynamic_cast<ElementAccess*>( lhs.get() ) )
4,113✔
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,674✔
101
    {
102
      return std::make_unique<MemberAssignment>( location_for( *ctx ), consume,
1,160✔
103
                                                 get_member->take_entity(), get_member->name,
1,160✔
104
                                                 std::move( rhs ), get_member->known_member );
1,160✔
105
    }
106
  }
107

108
  if ( token_id == TOK_ADDMEMBER || token_id == TOK_CHKMEMBER || token_id == TOK_DELMEMBER )
11,958✔
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() ) )
189✔
114
    {
115
      rhs = std::make_unique<StringValue>( rhs->source_location, identifier->scoped_name.string() );
186✔
116
    }
117
  }
118

119
  auto op = std::make_unique<BinaryOperator>( location_for( *ctx ), std::move( lhs ),
11,958✔
120
                                              ctx->bop->getText(), token_id, std::move( rhs ) );
23,916✔
121
  if ( consume )
11,958✔
122
    return consume_expression_result( std::move( op ) );
2,842✔
123
  return op;
9,116✔
124
}
12,977✔
125

126
BTokenId ExpressionBuilder::binary_operator_token(
12,977✔
127
    EscriptGrammar::EscriptParser::ExpressionContext* ctx )
128
{
129
  if ( ctx->ADD() )
12,977✔
130
    return TOK_ADD;
3,116✔
131
  if ( ctx->SUB() )
9,861✔
132
    return TOK_SUBTRACT;
521✔
133
  if ( ctx->MUL() )
9,340✔
134
    return TOK_MULT;
274✔
135
  if ( ctx->DIV() )
9,066✔
136
    return TOK_DIV;
99✔
137
  if ( ctx->ASSIGN() )
8,967✔
138
    return TOK_ASSIGN;
4,113✔
139
  if ( ctx->EQUAL() )
4,854✔
140
    return TOK_EQUAL;
1,170✔
141
  if ( ctx->NOTEQUAL_A() || ctx->NOTEQUAL_B() )
3,684✔
142
    return TOK_NEQ;
1,443✔
143
  if ( ctx->LT() )
2,241✔
144
    return TOK_LESSTHAN;
300✔
145
  if ( ctx->LE() )
1,941✔
146
    return TOK_LESSEQ;
103✔
147
  if ( ctx->GT() )
1,838✔
148
    return TOK_GRTHAN;
208✔
149
  if ( ctx->GE() )
1,630✔
150
    return TOK_GREQ;
113✔
151
  if ( ctx->AND_A() || ctx->AND_B() )
1,517✔
152
    return TOK_AND;
162✔
153
  if ( ctx->OR_A() || ctx->OR_B() )
1,355✔
154
    return TOK_OR;
618✔
155
  if ( ctx->ADD_ASSIGN() )
737✔
156
    return TOK_PLUSEQUAL;
106✔
157
  if ( ctx->SUB_ASSIGN() )
631✔
158
    return TOK_MINUSEQUAL;
33✔
159
  if ( ctx->MUL_ASSIGN() )
598✔
160
    return TOK_TIMESEQUAL;
37✔
161
  if ( ctx->DIV_ASSIGN() )
561✔
162
    return TOK_DIVIDEEQUAL;
21✔
163
  if ( ctx->MOD() )
540✔
164
    return TOK_MODULUS;
54✔
165
  if ( ctx->MOD_ASSIGN() )
486✔
166
    return TOK_MODULUSEQUAL;
24✔
167
  if ( ctx->ADDMEMBER() )
462✔
168
    return TOK_ADDMEMBER;
96✔
169
  if ( ctx->DELMEMBER() )
366✔
170
    return TOK_DELMEMBER;
11✔
171
  if ( ctx->CHKMEMBER() )
355✔
172
    return TOK_CHKMEMBER;
82✔
173
  if ( ctx->BITAND() )
273✔
174
    return TOK_BITAND;
28✔
175
  if ( ctx->BITOR() )
245✔
176
    return TOK_BITOR;
46✔
177
  if ( ctx->CARET() )
199✔
178
    return TOK_BITXOR;
21✔
179
  if ( ctx->TOK_IN() )
178✔
180
    return TOK_IN;
81✔
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✔
UNCOV
186
    return TOK_ADDMEMBER;
×
187
  if ( ctx->CHKMEMBER() )
61✔
UNCOV
188
    return TOK_CHKMEMBER;
×
189
  if ( ctx->DELMEMBER() )
61✔
UNCOV
190
    return TOK_DELMEMBER;
×
191
  if ( ctx->IS() )
61✔
192
    return TOK_IS;
61✔
193

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

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

211
        auto key = expression( expressions.at( 0 ) );
171✔
212
        if ( spread )
171✔
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 ) )
303✔
220
                                                   : std::make_unique<UninitializedValue>( loc );
303✔
221
          auto entry =
222
              std::make_unique<DictionaryEntry>( loc, std::move( key ), std::move( value ) );
156✔
223
          entries.push_back( std::move( entry ) );
156✔
224
        }
156✔
225
      }
258✔
226
    }
227
  }
228
  auto loc = location_for( *ctx );
174✔
229

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

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

238
  std::vector<std::unique_ptr<Expression>> indexes;
2,443✔
239
  for ( auto expression_ctx : ctx->expression() )
5,137✔
240
  {
241
    indexes.push_back( expression( expression_ctx ) );
2,694✔
242
  }
2,443✔
243

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

246
  return std::make_unique<ElementAccess>( source_location, std::move( lhs ), std::move( xx ) );
4,886✔
247
}
2,443✔
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(
299✔
274
    EscriptParser::ExplicitErrorInitializerContext* ctx )
275
{
276
  auto source_location = location_for( *ctx );
299✔
277

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

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

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

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

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

311
std::vector<std::unique_ptr<Expression>> ExpressionBuilder::expressions(
6,528✔
312
    EscriptParser::ExpressionListContext* ctx )
313
{
314
  std::vector<std::unique_ptr<Expression>> expressions;
6,528✔
315
  if ( ctx )
6,528✔
316
  {
317
    for ( auto entry_ctx : ctx->expressionListEntry() )
15,425✔
318
    {
319
      expressions.push_back( expression( entry_ctx->expression(), false, entry_ctx->ELLIPSIS() ) );
10,085✔
320
    }
5,340✔
321
  }
322
  return expressions;
6,528✔
UNCOV
323
}
×
324

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

330
  for ( auto interstringPart_ctx : ctx )
10,346✔
331
  {
332
    if ( auto expression_ctx = interstringPart_ctx->expression() )
7,874✔
333
    {
334
      std::unique_ptr<Expression> expr = expression( expression_ctx );
3,759✔
335
      if ( auto format = interstringPart_ctx->FORMAT_STRING() )
3,759✔
336
      {
337
        expr = format_expression( std::move( expr ), format );
110✔
338
      }
339
      expressions.push_back( std::move( expr ) );
3,759✔
340
    }
3,759✔
341
    else if ( auto string_literal = interstringPart_ctx->STRING_LITERAL_INSIDE() )
4,115✔
342
    {
343
      expressions.push_back( string_value( string_literal, false ) );
3,922✔
344
    }
345
    else if ( auto lbrace = interstringPart_ctx->DOUBLE_LBRACE_INSIDE() )
193✔
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() )
151✔
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() )
115✔
356
    {
357
      expressions.push_back( string_value( escaped, false ) );
115✔
358
    }
359
    else
360
    {
UNCOV
361
      location_for( *interstringPart_ctx )
×
362
          .internal_error( "unhandled context in interpolated string part" );
×
363
    }
364
  }
365
  return expressions;
2,472✔
UNCOV
366
}
×
367

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

381
std::unique_ptr<Expression> ExpressionBuilder::expression( EscriptParser::ExpressionContext* ctx,
386,483✔
382
                                                           bool consume, bool spread )
383
{
384
  std::unique_ptr<Expression> result;
386,483✔
385
  if ( auto prim = ctx->primary() )
386,483✔
386
    result = primary( prim );
351,531✔
387
  else if ( ctx->prefix )
34,952✔
388
    result = prefix_unary_operator( ctx );
9,410✔
389
  else if ( ctx->postfix )
25,542✔
390
    result = postfix_unary_operator( ctx );
160✔
391
  else if ( ctx->bop && ctx->expression().size() == 2 )
25,382✔
392
  {
393
    if ( ctx->ELVIS() )
13,221✔
394
      result = elvis_operator( ctx );
244✔
395
    else
396
      return binary_operator( ctx, consume );
12,977✔
397
  }
398
  else if ( auto suffix = ctx->expressionSuffix() )
12,161✔
399
  {
400
    result = expression_suffix( expression( ctx->expression()[0] ), suffix );
11,996✔
401
  }
402
  else if ( ctx->QUESTION() )
165✔
403
  {
404
    result = conditional_operator( ctx );
165✔
405
  }
406
  else
407
  {
UNCOV
408
    location_for( *ctx ).internal_error( "unhandled expression" );
×
409
  }
410

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

416
  if ( consume )
373,504✔
417
  {
418
    result = consume_expression_result( std::move( result ) );
13,967✔
419
  }
420

421
  return result;
373,504✔
422
}
386,483✔
423

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

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

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

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

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

439
  return function_call;
37,930✔
440
}
18,965✔
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(
4,025✔
456
    std::unique_ptr<Expression> lhs, EscriptParser::MethodCallSuffixContext* ctx )
457
{
458
  auto loc = location_for( *ctx );
4,025✔
459
  auto methodname = text( ctx->IDENTIFIER() );
4,025✔
460
  auto arguments = expressions( ctx->expressionList() );
4,025✔
461

462
  auto argument_list = std::make_unique<MethodCallArgumentList>( loc, std::move( arguments ) );
4,025✔
463
  return std::make_unique<MethodCall>( loc, std::move( lhs ), std::move( methodname ),
4,025✔
464
                                       std::move( argument_list ) );
12,075✔
465
}
4,025✔
466

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

472
  std::string name;
5,256✔
473
  if ( auto identifier = ctx->IDENTIFIER() )
5,256✔
474
    name = text( identifier );
5,229✔
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
UNCOV
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 ) );
10,512✔
482
}
5,256✔
483

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

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

513
  BTokenId token_id;
514
  if ( ctx->ADD() )
9,410✔
515
    token_id = TOK_UNPLUS;
9✔
516
  else if ( ctx->SUB() )
9,401✔
517
    token_id = TOK_UNMINUS;
7,051✔
518
  else if ( ctx->INC() )
2,350✔
519
    token_id = TOK_UNPLUSPLUS;
124✔
520
  else if ( ctx->DEC() )
2,226✔
521
    token_id = TOK_UNMINUSMINUS;
98✔
522
  else if ( ctx->TILDE() )
2,128✔
523
    token_id = TOK_BITWISE_NOT;
24✔
524
  else if ( ctx->BANG_A() || ctx->BANG_B() )
2,104✔
525
    token_id = TOK_LOG_NOT;
2,104✔
526
  else
UNCOV
527
    unhandled_operator( source_location );
×
528

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

532
  return std::make_unique<UnaryOperator>( source_location, ctx->prefix->getText(), token_id,
18,802✔
533
                                          std::move( expression_ast ) );
18,802✔
534
}
9,410✔
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
UNCOV
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 )
351,531✔
556
{
557
  if ( auto literal = ctx->literal() )
351,531✔
558
  {
559
    return value( literal );
270,039✔
560
  }
561
  if ( auto par_expression = ctx->parExpression() )
81,492✔
562
  {
563
    return expression( par_expression->expression() );
598✔
564
  }
565
  if ( auto scoped_ident = ctx->scopedIdentifier() )
80,894✔
566
  {
567
    return scoped_identifier( scoped_ident );
171✔
568
  }
569
  if ( auto identifier = ctx->IDENTIFIER() )
80,723✔
570
  {
571
    return std::make_unique<Identifier>( location_for( *ctx ), text( identifier ) );
53,726✔
572
  }
573
  if ( auto f_call = ctx->functionCall() )
26,997✔
574
  {
575
    return function_call( location_for( *f_call ), f_call, ScopeName::None );
18,634✔
576
  }
577
  if ( auto scoped_f_call = ctx->scopedFunctionCall() )
8,363✔
578
  {
579
    return scoped_function_call( scoped_f_call );
277✔
580
  }
581
  if ( auto dict_init = ctx->explicitDictInitializer() )
8,086✔
582
  {
583
    return dictionary_initializer( dict_init );
174✔
584
  }
585
  if ( auto struct_init = ctx->explicitStructInitializer() )
7,912✔
586
  {
587
    return struct_initializer( struct_init );
1,087✔
588
  }
589
  if ( auto fr = ctx->functionReference() )
6,825✔
590
  {
591
    return function_reference( fr );
765✔
592
  }
593
  if ( auto fe = ctx->functionExpression() )
6,060✔
594
  {
595
    return function_expression( fe );
675✔
596
  }
597
  if ( auto error_init = ctx->explicitErrorInitializer() )
5,385✔
598
  {
599
    return error( error_init );
299✔
600
  }
601
  if ( auto array_init = ctx->explicitArrayInitializer() )
5,086✔
602
  {
603
    return array_initializer( array_init );
534✔
604
  }
605
  if ( auto bare_array = ctx->bareArrayInitializer() )
4,552✔
606
  {
607
    return array_initializer( bare_array );
2,080✔
608
  }
609
  if ( auto inter_string = ctx->interpolatedString() )
2,472✔
610
  {
611
    return interpolate_string( inter_string );
2,472✔
612
  }
613

UNCOV
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,087✔
650
    EscriptParser::ExplicitStructInitializerContext* ctx )
651
{
652
  std::vector<std::unique_ptr<Node>> initializers;
1,087✔
653

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

670
        if ( auto expression_ctx = initializer_expression_ctx->expression() )
1,936✔
671
        {
672
          auto initializer = expression( expression_ctx );
1,891✔
673
          if ( spread )
1,891✔
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,882✔
678
                loc, std::move( identifier ), std::move( initializer ) ) );
1,882✔
679
        }
1,891✔
680
        else
681
        {
682
          initializers.push_back(
45✔
683
              std::make_unique<StructMemberInitializer>( loc, std::move( identifier ) ) );
90✔
684
        }
685
      }
2,706✔
686
    }
687
  }
688
  return std::make_unique<StructInitializer>( location_for( *ctx ), std::move( initializers ) );
2,174✔
689
}
1,087✔
690

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

696
  if ( ctx )
19,237✔
697
  {
698
    for ( auto argument_context : ctx->expressionListEntry() )
42,629✔
699
    {
700
      auto loc = location_for( *argument_context );
24,597✔
701

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

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

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

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

727
      arguments.push_back( std::move( argument ) );
24,597✔
728
    }
42,629✔
729
  }
730

731
  return arguments;
19,237✔
UNCOV
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