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

polserver / polserver / 16683711876

01 Aug 2025 07:40PM UTC coverage: 59.756% (-0.03%) from 59.79%
16683711876

push

github

web-flow
use c++20 (#799)

* use c++20
* increased used clang version
* compiler report and logfacility use now compile time formatting, which
means that the formatstring gets checked at compile time. (which found 2 errors)
adapted a few places since report only accepts formatting arguments
adapted a few places with logging since char[] is compile time
formatting and string or chr* is runtime formatting
* use std::ranges instead of boost
* disabled pragma_assume vs specific macro (I guess noone cares)
* needed to fix ancient ms exception code
* modernized SpinLock
* removed unused code in ECompile
* replaced std::filesystem::path::u8string with string. It now returns an actual u8string type
* cleanup layers.h added the defines for other layers which where before
  only defined in the pkt
* osmod::OpenConnection and HTTPRequest cleanup: early outs, dont check for pChild which is
  only needed for startscript and placed suspend at the very last
  position

* fix warning

* rebuild cache with new compiler version

* define c++ standard for external libs where possible

* added fixme

156 of 212 new or added lines in 26 files covered. (73.58%)

45 existing lines in 19 files now uncovered.

43621 of 72999 relevant lines covered (59.76%)

409874.73 hits per line

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

95.89
/pol-core/bscript/compiler/codegen/InstructionEmitter.cpp
1
#include "InstructionEmitter.h"
2

3
#include <limits>
4
#include <list>
5
#include <set>
6

7
#include "StoredToken.h"
8
#include "bscript/compiler/Report.h"
9
#include "bscript/compiler/ast/ClassDeclaration.h"
10
#include "bscript/compiler/ast/ModuleFunctionDeclaration.h"
11
#include "bscript/compiler/ast/UserFunction.h"
12
#include "bscript/compiler/codegen/CaseJumpDataBlock.h"
13
#include "bscript/compiler/codegen/ClassDeclarationRegistrar.h"
14
#include "bscript/compiler/codegen/FunctionReferenceRegistrar.h"
15
#include "bscript/compiler/codegen/ModuleDeclarationRegistrar.h"
16
#include "bscript/compiler/model/ClassLink.h"
17
#include "bscript/compiler/model/FlowControlLabel.h"
18
#include "bscript/compiler/model/FunctionLink.h"
19
#include "bscript/compiler/model/LocalVariableScopeInfo.h"
20
#include "bscript/compiler/model/ScopableName.h"
21
#include "bscript/compiler/model/Variable.h"
22
#include "bscript/compiler/representation/ClassDescriptor.h"
23
#include "bscript/compiler/representation/CompiledScript.h"
24
#include "bscript/compiler/representation/ConstructorDescriptor.h"
25
#include "bscript/compiler/representation/ExportedFunction.h"
26
#include "escriptv.h"
27
#include "modules.h"
28
#include "token.h"
29
#include "tokens.h"
30

31
namespace Pol::Bscript::Compiler
32
{
33
InstructionEmitter::InstructionEmitter( CodeSection& code, DataSection& data, DebugStore& debug,
2,099✔
34
                                        ExportedFunctions& exported_functions,
35
                                        ModuleDeclarationRegistrar& module_declaration_registrar,
36
                                        FunctionReferenceRegistrar& function_reference_registrar,
37
                                        ClassDeclarationRegistrar& class_declaration_registrar,
38
                                        Report& report )
2,099✔
39
    : code_emitter( code ),
2,099✔
40
      data_emitter( data ),
2,099✔
41
      debug( debug ),
2,099✔
42
      exported_functions( exported_functions ),
2,099✔
43
      module_declaration_registrar( module_declaration_registrar ),
2,099✔
44
      function_reference_registrar( function_reference_registrar ),
2,099✔
45
      class_declaration_registrar( class_declaration_registrar ),
2,099✔
46
      report( report )
2,099✔
47
{
48
  initialize_data();
2,099✔
49
}
2,099✔
50

51
void InstructionEmitter::initialize_data()
2,099✔
52
{
53
  std::byte nul{};
2,099✔
54
  data_emitter.store( &nul, sizeof nul );
2,099✔
55
}
2,099✔
56

57
void InstructionEmitter::register_exported_function( FlowControlLabel& label,
553✔
58
                                                     const std::string& name, unsigned parameters )
59
{
60
  exported_functions.emplace_back( name, parameters, label.address() );
553✔
61
}
553✔
62

63
void InstructionEmitter::register_class_declaration(
368✔
64
    const ClassDeclaration& node, std::map<std::string, FlowControlLabel>& user_function_labels )
65
{
66
  std::set<std::string> visited;
368✔
67
  std::set<std::string, Clib::ci_cmp_pred> visited_methods;
368✔
68
  std::vector<ConstructorDescriptor> constructor_descriptors;
368✔
69
  std::set<std::string> method_names;
368✔
70
  std::vector<MethodDescriptor> method_descriptors;
368✔
71
  std::list<const ClassDeclaration*> to_link( { &node } );
368✔
72

73
  const auto& class_name = node.name;
368✔
74
  auto class_name_offset = this->emit_data( class_name );
368✔
75
  unsigned constructor_function_reference_index = std::numeric_limits<unsigned>::max();
368✔
76

77
  report.debug( node, "Registering class: {}", node.name );
368✔
78

79
  if ( node.constructor_link )
736✔
80
  {
81
    if ( auto uf = node.constructor_link->user_function() )
338✔
82
    {
83
      auto ctor_itr = user_function_labels.find( uf->scoped_name() );
338✔
84

85
      if ( ctor_itr == user_function_labels.end() )
338✔
86
      {
87
        uf->internal_error(
×
88
            fmt::format( "Constructor {} not found in user_function_labels", uf->scoped_name() ) );
×
89
      }
90

91
      function_reference_registrar.lookup_or_register_reference(
676✔
92
          *uf, ctor_itr->second, constructor_function_reference_index );
338✔
93
    }
94
  }
95
  if ( constructor_function_reference_index < std::numeric_limits<unsigned>::max() )
368✔
96
    report.debug( node, " - Constructor at FuncRef index {}",
338✔
97
                  constructor_function_reference_index );
98

99
  for ( auto itr = to_link.begin(); itr != to_link.end(); ++itr )
1,070✔
100
  {
101
    auto cd = *itr;
702✔
102
    if ( visited.find( cd->name ) != visited.end() )
702✔
103
      continue;
41✔
104

105
    visited.insert( cd->name );
661✔
106
    report.debug( *cd, "Class {} with {} methods", cd->name, cd->methods.size() );
661✔
107

108
    if ( cd->constructor_link && cd->constructor_link->user_function() )
1,322✔
109
    {
110
      auto type_tag_offset = emit_data( cd->type_tag() );
628✔
111
      constructor_descriptors.push_back( type_tag_offset );
628✔
112
    }
113

114
    for ( const auto& [method, uf_link] : cd->methods )
997✔
115
    {
116
      auto uf = uf_link->user_function();
336✔
117

118
      if ( !uf )
336✔
119
      {
120
        cd->internal_error( fmt::format( "method {}::{} no function linked", cd->name, method ) );
×
121
      }
122

123
      auto method_itr = user_function_labels.find( ScopableName( cd->name, method ).string() );
336✔
124
      if ( method_itr == user_function_labels.end() )
336✔
125
      {
126
        report.debug( *cd, " - Method: {} label=???", method );
×
127
        cd->internal_error( fmt::format( "Method {} not found in user_function_labels", method ) );
×
128
      }
129
      auto address = method_itr->second.address();
336✔
130
      if ( address == 0 )
336✔
131
      {
132
        report.debug( *cd, " - Method: {} PC=???", method );
×
133
        cd->internal_error( fmt::format( "Method {} has no PC for attached label", method ) );
×
134
      }
135

136
      bool use_method = method_names.find( method ) == method_names.end();
336✔
137

138
      if ( use_method )
336✔
139
      {
140
        unsigned funcref_index;
141
        function_reference_registrar.lookup_or_register_reference( *uf, method_itr->second,
270✔
142
                                                                   funcref_index );
143
        auto name_offset = this->emit_data( method );
270✔
144
        method_descriptors.emplace_back( name_offset, address, funcref_index );
270✔
UNCOV
145
        report.debug( *cd, " - Method: {} PC={} funcref_index={}", method,
×
146
                      method_itr->second.address(), funcref_index );
270✔
147
        method_names.insert( method );
270✔
148
      }
149
      else
150
      {
151
        report.debug( *cd, " - Method: {} PC={} [ignored]", method, method_itr->second.address() );
66✔
152
      }
153
    }
154

155
    for ( const auto& base_cd_link : cd->base_class_links )
995✔
156
    {
157
      if ( auto base_cd = base_cd_link->class_declaration() )
334✔
158
      {
159
        to_link.push_back( base_cd );
334✔
160
      }
161
    }
162
  }
163
  report.debug( node, "Class: {}", node.name );
368✔
164

165
  for ( const auto& constructor : constructor_descriptors )
996✔
166
  {
167
    report.debug( node, " - Constructor @ type_tag_offset={}", constructor.type_tag_offset );
628✔
168
  }
169

170
  for ( const auto& method_info : method_descriptors )
638✔
171
  {
172
    report.debug( node, " - Method @ PC={} name_offset={} funcref_index={} ", method_info.address,
270✔
173
                  method_info.name_offset, method_info.function_reference_index );
270✔
174
  }
175

176
  class_declaration_registrar.register_class( class_name_offset,
368✔
177
                                              constructor_function_reference_index,
178
                                              constructor_descriptors, method_descriptors );
179
}
368✔
180

181
unsigned InstructionEmitter::enter_debug_block(
9,654✔
182
    const LocalVariableScopeInfo& local_variable_scope_info )
183
{
184
  unsigned previous_debug_block_index = debug_instruction_info.block_index;
9,654✔
185

186
  if ( !local_variable_scope_info.variables.empty() )
9,654✔
187
  {
188
    debug_instruction_info.block_index =
4,233✔
189
        debug.add_block( debug_instruction_info.block_index, local_variable_scope_info );
4,233✔
190
  }
191

192
  return previous_debug_block_index;
9,654✔
193
}
194

195
void InstructionEmitter::set_debug_block( unsigned block_index )
9,654✔
196
{
197
  debug_instruction_info.block_index = block_index;
9,654✔
198
}
9,654✔
199

200
// - When visiting an identifier:
201
// - If type == Capture: set to Local and ValueStack offset will be current function's param count +
202
// this variable index
203
// - If type == Local: if offset >= function param count, add current function's capture count
204
void InstructionEmitter::access_variable( const Variable& v, VariableIndex function_params_count,
27,938✔
205
                                          VariableIndex function_capture_count )
206
{
207
  BTokenId token_id;
208
  unsigned offset;
209

210
  if ( v.scope == VariableScope::Capture )
27,938✔
211
  {
212
    token_id = TOK_LOCALVAR;
656✔
213

214
    offset = v.index + function_params_count;
656✔
215
  }
216
  else if ( v.scope == VariableScope::Local )
27,282✔
217
  {
218
    token_id = TOK_LOCALVAR;
19,178✔
219

220
    if ( v.index >= function_params_count )
19,178✔
221
    {
222
      offset = v.index + function_capture_count;
14,294✔
223
    }
224
    else
225
    {
226
      offset = v.index;
4,884✔
227
    }
228
  }
229
  else
230
  {
231
    token_id = TOK_GLOBALVAR;
8,104✔
232
    offset = v.index;
8,104✔
233
  }
234
  emit_token( token_id, TYP_OPERAND, offset );
27,938✔
235
}
27,938✔
236

237
void InstructionEmitter::array_append()
5,547✔
238
{
239
  emit_token( TOK_INSERTINTO, TYP_OPERATOR );
5,547✔
240
}
5,547✔
241

242
void InstructionEmitter::array_create()
2,529✔
243
{
244
  emit_token( TOK_ARRAY, TYP_OPERAND );
2,529✔
245
}
2,529✔
246

247
void InstructionEmitter::array_declare()
69✔
248
{
249
  emit_token( INS_DECLARE_ARRAY, TYP_RESERVED );
69✔
250
}
69✔
251

252
void InstructionEmitter::assign()
4,644✔
253
{
254
  emit_token( TOK_ASSIGN, TYP_OPERATOR );
4,644✔
255
}
4,644✔
256

257
void InstructionEmitter::assign_subscript_consume()
427✔
258
{
259
  unsigned indexes = 1;
427✔
260
  emit_token( INS_SUBSCRIPT_ASSIGN_CONSUME, TYP_UNARY_OPERATOR, indexes );
427✔
261
}
427✔
262

263
void InstructionEmitter::assign_subscript()
3✔
264
{
265
  unsigned indexes = 1;
3✔
266
  emit_token( INS_SUBSCRIPT_ASSIGN, TYP_UNARY_OPERATOR, indexes );
3✔
267
}
3✔
268

269
void InstructionEmitter::assign_multisubscript( unsigned indexes )
6✔
270
{
271
  emit_token( INS_MULTISUBSCRIPT_ASSIGN, TYP_UNARY_OPERATOR, indexes );
6✔
272
}
6✔
273

274
void InstructionEmitter::assign_variable( const Variable& v, VariableIndex function_params_count,
1,883✔
275
                                          VariableIndex function_capture_count )
276
{
277
  BTokenId token_id;
278
  unsigned offset;
279

280
  if ( v.scope == VariableScope::Capture )
1,883✔
281
  {
282
    token_id = INS_ASSIGN_LOCALVAR;
19✔
283

284
    offset = v.index + function_params_count;
19✔
285
  }
286
  else if ( v.scope == VariableScope::Local )
1,864✔
287
  {
288
    token_id = INS_ASSIGN_LOCALVAR;
1,100✔
289

290
    if ( v.index >= function_params_count )
1,100✔
291
    {
292
      offset = v.index + function_capture_count;
1,037✔
293
    }
294
    else
295
    {
296
      offset = v.index;
63✔
297
    }
298
  }
299
  else
300
  {
301
    token_id = INS_ASSIGN_GLOBALVAR;
764✔
302
    offset = v.index;
764✔
303
  }
304

305
  emit_token( token_id, TYP_UNARY_OPERATOR, offset );
1,883✔
306
}
1,883✔
307

308
void InstructionEmitter::basic_for_init( FlowControlLabel& label )
65✔
309
{
310
  register_with_label( label, emit_token( INS_INITFOR, TYP_RESERVED ) );
65✔
311
}
65✔
312

313
void InstructionEmitter::basic_for_next( FlowControlLabel& label )
65✔
314
{
315
  register_with_label( label, emit_token( INS_NEXTFOR, TYP_RESERVED ) );
65✔
316
}
65✔
317

318
void InstructionEmitter::binary_operator( BTokenId token_id )
7,502✔
319
{
320
  emit_token( token_id, TYP_OPERATOR );
7,502✔
321
}
7,502✔
322

323
void InstructionEmitter::call_method_id( MethodID method_id, unsigned argument_count )
3,354✔
324
{
325
  emit_token( INS_CALL_METHOD_ID, (BTokenType)argument_count, method_id );
3,354✔
326
}
3,354✔
327

328
void InstructionEmitter::call_method( const std::string& name, unsigned argument_count )
347✔
329
{
330
  unsigned offset = emit_data( name );
347✔
331
  emit_token( INS_CALL_METHOD, (BTokenType)argument_count, offset );
347✔
332
}
347✔
333

334
void InstructionEmitter::call_modulefunc(
12,441✔
335
    const ModuleFunctionDeclaration& module_function_declaration )
336
{
337
  unsigned module_id, function_index;
338
  module_declaration_registrar.lookup_or_register_module_function( module_function_declaration,
12,441✔
339
                                                                   module_id, function_index );
340
  unsigned sympos = include_debug ? emit_data( module_function_declaration.name ) : 0;
12,441✔
341
  StoredToken token(
342
      static_cast<unsigned char>( module_id ), TOK_FUNC,
343
      static_cast<BTokenType>(
12,441✔
344
          function_index ),  // function index, stored in Token.lval, saved in StoredToken.type
345
      sympos );
12,441✔
346
  append_token( token );
12,441✔
347
}
12,441✔
348

349
void InstructionEmitter::call_userfunc( FlowControlLabel& label )
5,085✔
350
{
351
  unsigned addr = emit_token( CTRL_JSR_USERFUNC, TYP_CONTROL );
5,085✔
352
  register_with_label( label, addr );
5,085✔
353
}
5,085✔
354

355
void InstructionEmitter::check_mro( unsigned offset )
225✔
356
{
357
  emit_token( INS_CHECK_MRO, TYP_CONTROL, offset );
225✔
358
}
225✔
359

360
void InstructionEmitter::classinst_create( unsigned index )
182✔
361
{
362
  emit_token( TOK_CLASSINST, TYP_OPERAND, index );
182✔
363
}
182✔
364

365
unsigned InstructionEmitter::casejmp()
101✔
366
{
367
  return emit_token( INS_CASEJMP, TYP_RESERVED );
101✔
368
}
369

370
unsigned InstructionEmitter::case_dispatch_table( const CaseJumpDataBlock& dispatch_table )
101✔
371
{
372
  auto& bytes = dispatch_table.get_data();
101✔
373
  return data_emitter.append( bytes.data(), bytes.size() );
101✔
374
}
375

376
void InstructionEmitter::consume()
18,964✔
377
{
378
  emit_token( TOK_CONSUMER, TYP_UNARY_OPERATOR );
18,964✔
379
}
18,964✔
380

381
void InstructionEmitter::ctrl_statementbegin( unsigned file_index, unsigned file_offset,
×
382
                                              const std::string& source_text )
383
{
384
  unsigned source_offset = emit_data( source_text );
×
385
  Pol::Bscript::DebugToken debug_token;
386
  debug_token.sourceFile = file_index + 1;
×
387
  debug_token.offset = file_offset;
×
388
  debug_token.strOffset = source_offset;
×
389
  unsigned offset =
390
      data_emitter.store( reinterpret_cast<std::byte*>( &debug_token ), sizeof debug_token );
×
391
  emit_token( CTRL_STATEMENTBEGIN, TYP_CONTROL, offset );
×
392
}
×
393

394
// - When declaring an identifier:
395
// - If type == Local: if offset >= function param count, add current function's capture count
396
void InstructionEmitter::declare_variable( const Variable& v, VariableIndex function_capture_count,
6,004✔
397
                                           bool take )
398
{
399
  int offset;
400

401
  if ( v.scope == VariableScope::Local && v.index >= function_capture_count )
6,004✔
402
  {
403
    offset = v.index + function_capture_count;
3,660✔
404
  }
405
  else
406
  {
407
    offset = v.index;
2,344✔
408
  }
409

410
  BTokenId token_id = v.scope == VariableScope::Global ? ( take ? INS_TAKE_GLOBAL : RSV_GLOBAL )
9,732✔
411
                                                       : ( take ? INS_TAKE_LOCAL : RSV_LOCAL );
3,728✔
412
  emit_token( token_id, TYP_RESERVED, offset );
6,004✔
413
}
6,004✔
414

415
void InstructionEmitter::dictionary_create()
162✔
416
{
417
  emit_token( TOK_DICTIONARY, TYP_OPERAND );
162✔
418
}
162✔
419

420
void InstructionEmitter::dictionary_add_member()
138✔
421
{
422
  emit_token( INS_DICTIONARY_ADDMEMBER, TYP_OPERATOR );
138✔
423
}
138✔
424

425
void InstructionEmitter::error_create()
287✔
426
{
427
  emit_token( TOK_ERROR, TYP_OPERAND );
287✔
428
}
287✔
429

430
void InstructionEmitter::exit()
18✔
431
{
432
  emit_token( RSV_EXIT, TYP_RESERVED );
18✔
433
}
18✔
434

435
void InstructionEmitter::foreach_init( FlowControlLabel& label )
464✔
436
{
437
  register_with_label( label, emit_token( INS_INITFOREACH, TYP_RESERVED ) );
464✔
438
}
464✔
439

440
void InstructionEmitter::foreach_step( FlowControlLabel& label )
464✔
441
{
442
  register_with_label( label, emit_token( INS_STEPFOREACH, TYP_RESERVED ) );
464✔
443
}
464✔
444

445
void InstructionEmitter::function_reference( const UserFunction& uf, FlowControlLabel& label )
732✔
446
{
447
  unsigned index;
448

449
  function_reference_registrar.lookup_or_register_reference( uf, label, index );
732✔
450

451
  emit_token( TOK_FUNCREF, TYP_OPERAND, index );
732✔
452
}
732✔
453

454
void InstructionEmitter::functor_create( const UserFunction& uf, FlowControlLabel& label )
509✔
455
{
456
  unsigned reference_index;
457
  function_reference_registrar.lookup_or_register_reference( uf, label, reference_index );
509✔
458
  StoredToken token( static_cast<unsigned char>( Mod_Basic ), TOK_FUNCTOR,
459
                     static_cast<BTokenType>(
509✔
460
                         reference_index ),  // index to the EScriptProgram's function_references,
461
                                             // stored in Token.lval, saved in StoredToken.type
462
                     0 );
509✔
463
  append_token( token );
509✔
464
}
509✔
465

466
void InstructionEmitter::get_arg( const std::string& name )
202✔
467
{
468
  unsigned offset = emit_data( name );
202✔
469
  emit_token( INS_GET_ARG, TYP_OPERATOR, offset );
202✔
470
}
202✔
471

472
void InstructionEmitter::get_member( const std::string& name )
1,410✔
473
{
474
  unsigned offset = emit_data( name );
1,410✔
475
  emit_token( INS_GET_MEMBER, TYP_UNARY_OPERATOR, offset );
1,410✔
476
}
1,410✔
477

478
void InstructionEmitter::get_member_id( MemberID member_id )
2,714✔
479
{
480
  emit_token( INS_GET_MEMBER_ID, TYP_UNARY_OPERATOR, member_id );
2,714✔
481
}
2,714✔
482

483
void InstructionEmitter::jmp_always( FlowControlLabel& label )
2,183✔
484
{
485
  register_with_label( label, emit_token( RSV_GOTO, TYP_RESERVED ) );
2,183✔
486
}
2,183✔
487

488
void InstructionEmitter::jmp_if_false( FlowControlLabel& label )
2,441✔
489
{
490
  register_with_label( label, emit_token( RSV_JMPIFFALSE, TYP_RESERVED ) );
2,441✔
491
}
2,441✔
492

493
void InstructionEmitter::jmp_if_true( FlowControlLabel& label )
1,657✔
494
{
495
  register_with_label( label, emit_token( RSV_JMPIFTRUE, TYP_RESERVED ) );
1,657✔
496
}
1,657✔
497

498
void InstructionEmitter::label( FlowControlLabel& label )
12,247✔
499
{
500
  label.assign_address( code_emitter.next_address() );
12,247✔
501

502
  for ( auto referencing_address : label.get_referencing_instruction_addresses() )
21,942✔
503
  {
504
    patch_offset( referencing_address, label.address() );
9,695✔
505
  }
506
}
12,247✔
507

508
void InstructionEmitter::leaveblock( unsigned local_vars_to_remove )
1,924✔
509
{
510
  emit_token( CTRL_LEAVE_BLOCK, TYP_CONTROL, local_vars_to_remove );
1,924✔
511
}
1,924✔
512

513
void InstructionEmitter::makelocal()
5,085✔
514
{
515
  emit_token( CTRL_MAKELOCAL, TYP_CONTROL );
5,085✔
516
}
5,085✔
517

518
void InstructionEmitter::pop_param( const std::string& name )
2,940✔
519
{
520
  unsigned offset = emit_data( name );
2,940✔
521
  emit_token( INS_POP_PARAM, TYP_OPERATOR, offset );
2,940✔
522
}
2,940✔
523

524
void InstructionEmitter::pop_param_byref( const std::string& name )
1,195✔
525
{
526
  unsigned offset = emit_data( name );
1,195✔
527
  emit_token( INS_POP_PARAM_BYREF, TYP_OPERATOR, offset );
1,195✔
528
}
1,195✔
529

530
void InstructionEmitter::progend()
2,956✔
531
{
532
  emit_token( CTRL_PROGEND, TYP_CONTROL );
2,956✔
533
}
2,956✔
534

535
void InstructionEmitter::return_from_user_function()
5,383✔
536
{
537
  emit_token( RSV_RETURN, TYP_RESERVED );
5,383✔
538
}
5,383✔
539

540
void InstructionEmitter::return_from_constructor_function( unsigned this_offset )
338✔
541
{
542
  // Emit `this`
543
  emit_token( TOK_LOCALVAR, TYP_OPERAND, this_offset );
338✔
544

545
  // Emit a return
546
  return_from_user_function();
338✔
547
}
338✔
548

549
void InstructionEmitter::set_member_id_consume( MemberID member_id )
295✔
550
{
551
  emit_token( INS_SET_MEMBER_ID_CONSUME, TYP_UNARY_OPERATOR, member_id );
295✔
552
}
295✔
553

554
void InstructionEmitter::set_member_id( MemberID member_id )
3✔
555
{
556
  emit_token( INS_SET_MEMBER_ID, TYP_UNARY_OPERATOR, member_id );
3✔
557
}
3✔
558

559
void InstructionEmitter::set_member_consume( const std::string& name )
219✔
560
{
561
  unsigned offset = emit_data( name );
219✔
562
  emit_token( INS_SET_MEMBER_CONSUME, TYP_UNARY_OPERATOR, offset );
219✔
563
}
219✔
564

565
void InstructionEmitter::set_member( const std::string& name )
3✔
566
{
567
  unsigned offset = emit_data( name );
3✔
568
  emit_token( INS_SET_MEMBER, TYP_UNARY_OPERATOR, offset );
3✔
569
}
3✔
570

571
void InstructionEmitter::set_member_by_operator( BTokenId token_id, MemberID member_id )
70✔
572
{
573
  emit_token( token_id, TYP_UNARY_OPERATOR, member_id );
70✔
574
}
70✔
575

576
void InstructionEmitter::spread( bool spread_into )
671✔
577
{
578
  emit_token( TOK_SPREAD, TYP_OPERAND, spread_into );
671✔
579
}
671✔
580

581
unsigned InstructionEmitter::skip_if_true_else_consume()
199✔
582
{
583
  return emit_token( INS_SKIPIFTRUE_ELSE_CONSUME, TYP_CONTROL );
199✔
584
}
585

586
void InstructionEmitter::struct_create()
874✔
587
{
588
  emit_token( TOK_STRUCT, TYP_OPERAND );
874✔
589
}
874✔
590

591
void InstructionEmitter::struct_add_member( const std::string& name )
1,945✔
592
{
593
  auto offset = emit_data( name );
1,945✔
594
  emit_token( INS_ADDMEMBER_ASSIGN, TYP_OPERAND, offset );
1,945✔
595
}
1,945✔
596

597
void InstructionEmitter::struct_add_uninit_member( const std::string& name )
45✔
598
{
599
  auto offset = emit_data( name );
45✔
600
  emit_token( INS_ADDMEMBER2, TYP_OPERAND, offset );
45✔
601
}
45✔
602

603
void InstructionEmitter::subscript_single()
1,340✔
604
{
605
  emit_token( TOK_ARRAY_SUBSCRIPT, TYP_OPERATOR, 1 );
1,340✔
606
}
1,340✔
607

608
void InstructionEmitter::subscript_multiple( unsigned indexes )
185✔
609
{
610
  emit_token( INS_MULTISUBSCRIPT, TYP_OPERATOR, indexes );
185✔
611
}
185✔
612

613
void InstructionEmitter::unary_operator( BTokenId token_id )
557✔
614
{
615
  emit_token( token_id, TYP_UNARY_OPERATOR );
557✔
616
}
557✔
617

618
void InstructionEmitter::uninit()
114✔
619
{
620
  emit_token( INS_UNINIT, TYP_OPERAND );
114✔
621
}
114✔
622

623
void InstructionEmitter::unpack_sequence( unsigned count, unsigned rest_at )
109✔
624
{
625
  // Two-byte offset encodes (1) if rest unpacking, (2) index of rest binding, (3) the number of
626
  // bindings: aa'bbbbbbb'ccccccc => a: is rest, b: rest index, c: number of bindings
627
  unsigned short offset = rest_at == 0xFF
109✔
628
                              ? ( count & 0x7F )
40✔
629
                              : ( 1 << 14 ) | ( ( rest_at & 0x7F ) << 7 ) | ( count & 0x7F );
69✔
630

631
  emit_token( INS_UNPACK_SEQUENCE, TYP_RESERVED, offset );
109✔
632
}
109✔
633

634
void InstructionEmitter::unpack_indices( unsigned count, unsigned rest_at )
85✔
635
{
636
  // Two-byte offset encodes (1) if rest unpacking, (2) index of rest binding, (3) the number of
637
  // bindings: aa'bbbbbbb'ccccccc => a: is rest, b: rest index, c: number of bindings
638
  unsigned short offset = rest_at == 0xFF
85✔
639
                              ? ( count & 0x7F )
58✔
640
                              : ( 1 << 14 ) | ( ( rest_at & 0x7F ) << 7 ) | ( count & 0x7F );
27✔
641

642
  emit_token( INS_UNPACK_INDICES, TYP_RESERVED, offset );
85✔
643
}
85✔
644

645
void InstructionEmitter::value( double v )
434✔
646
{
647
  unsigned offset = data_emitter.append( v );
434✔
648
  emit_token( TOK_DOUBLE, TYP_OPERAND, offset );
434✔
649
}
434✔
650

651
void InstructionEmitter::value( int v )
16,671✔
652
{
653
  unsigned offset = data_emitter.append( v );
16,671✔
654
  emit_token( TOK_LONG, TYP_OPERAND, offset );
16,671✔
655
}
16,671✔
656

657
void InstructionEmitter::value( bool v )
177✔
658
{
659
  emit_token( TOK_BOOL, TYP_OPERAND, v );
177✔
660
}
177✔
661

662
void InstructionEmitter::value( const std::string& v )
24,719✔
663
{
664
  unsigned data_offset = emit_data( v );
24,719✔
665
  emit_token( TOK_STRING, TYP_OPERAND, data_offset );
24,719✔
666
}
24,719✔
667

668
void InstructionEmitter::interpolate_string( unsigned count )
2,074✔
669
{
670
  emit_token( TOK_INTERPOLATE_STRING, TYP_OPERAND, count );
2,074✔
671
}
2,074✔
672

673
void InstructionEmitter::format_expression()
108✔
674
{
675
  emit_token( TOK_FORMAT_EXPRESSION, TYP_OPERAND );
108✔
676
}
108✔
677

678
unsigned InstructionEmitter::emit_data( const std::string& s )
34,291✔
679
{
680
  return data_emitter.store( s );
34,291✔
681
}
682

683
unsigned InstructionEmitter::emit_token( BTokenId id, BTokenType type, unsigned offset )
168,606✔
684
{
685
  StoredToken token( Mod_Basic, id, type, offset );
168,606✔
686
  return append_token( token );
337,212✔
687
}
688

689
unsigned InstructionEmitter::append_token( StoredToken& token )
181,556✔
690
{
691
  debug.add_instruction( debug_instruction_info );
181,556✔
692
  debug_instruction_info.statement_begin = false;
181,556✔
693
  return code_emitter.append( token );
181,556✔
694
}
695

696
void InstructionEmitter::debug_file_line( unsigned file, unsigned line )
168,935✔
697
{
698
  // debug info always has file #0 = empty (keeping for parity, for now)
699
  debug_instruction_info.file_index = file + 1;
168,935✔
700
  debug_instruction_info.line_number = line;
168,935✔
701
}
168,935✔
702

703
void InstructionEmitter::debug_statementbegin()
37,462✔
704
{
705
  debug_instruction_info.statement_begin = true;
37,462✔
706
}
37,462✔
707

708
unsigned InstructionEmitter::next_instruction_address()
7,554✔
709
{
710
  return code_emitter.next_address();
7,554✔
711
}
712

713
void InstructionEmitter::debug_user_function( const std::string& name, unsigned first_pc,
2,972✔
714
                                              unsigned last_pc )
715
{
716
  DebugStore::UserFunctionInfo ufi{ name, first_pc, last_pc };
2,972✔
717
  debug.add_user_function( std::move( ufi ) );
2,972✔
718
}
2,972✔
719

720
void InstructionEmitter::patch_offset( unsigned index, unsigned offset )
13,271✔
721
{
722
  code_emitter.update_offset( index, offset );
13,271✔
723
}
13,271✔
724

725
bool InstructionEmitter::has_function_reference( const UserFunction& uf )
2,768✔
726
{
727
  unsigned index;
728
  return function_reference_registrar.lookup_reference( uf, index );
5,536✔
729
}
730

731
void InstructionEmitter::register_with_label( FlowControlLabel& label, unsigned offset )
12,462✔
732
{
733
  if ( label.has_address() )
12,462✔
734
  {
735
    patch_offset( offset, label.address() );
2,767✔
736
  }
737
  else
738
  {
739
    label.add_referencing_instruction_address( offset );
9,695✔
740
  }
741
}
12,462✔
742

743
void InstructionEmitter::logical_jmp( FlowControlLabel& label, bool if_true )
38✔
744
{
745
  register_with_label(
38✔
746
      label, emit_token( INS_LOGICAL_JUMP, if_true ? TYP_RESERVED : TYP_LOGICAL_JUMP_FALSE ) );
747
}
38✔
748

749
void InstructionEmitter::logical_convert()
38✔
750
{
751
  emit_token( INS_LOGICAL_CONVERT, TYP_OPERAND );
38✔
752
}
38✔
753

754
}  // 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