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

polserver / polserver / 21541532363

31 Jan 2026 08:14AM UTC coverage: 60.532% (+0.03%) from 60.507%
21541532363

push

github

web-flow
Tidy modernize for loops (#862)

* trigger loop convert

* Automated clang-tidy change: modernize-loop-convert

* fixed refactor

* Automated clang-tidy change: modernize-loop-convert

* compile

* first look through

* fixes and start to use a few ranges

* revert autogenerated file

* compilation fix

* second pass

* renamed loop variable

---------

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

164 of 447 new or added lines in 61 files covered. (36.69%)

6 existing lines in 5 files now uncovered.

44377 of 73312 relevant lines covered (60.53%)

499857.83 hits per line

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

74.57
/pol-core/bscript/object.cpp
1
/** @file
2
 *
3
 * @par History
4
 * - 2005/11/26 Shinigami: changed "strcmp" into "stricmp" to suppress Script Errors
5
 * - 2008/02/11 Turley:    ObjArray::unpack() will accept zero length Arrays and Erros from
6
 * Array-Elements
7
 * - 2009/09/05 Turley:    Added struct .? and .- as shortcut for .exists() and .erase()
8
 * - 2009/12/21 Turley:    ._method() call fix
9
 */
10

11
#include <assert.h>
12
#include <istream>
13
#include <limits>
14
#include <stddef.h>
15
#include <string>
16

17
#include "../clib/clib.h"
18
#include "../clib/fixalloc.h"
19
#include "../clib/logfacility.h"
20
#include "../clib/random.h"
21
#include "../clib/rawtypes.h"
22
#include "../clib/refptr.h"
23
#include "../clib/stlutil.h"
24
#include "bclassinstance.h"
25
#include "berror.h"
26
#include "bobject.h"
27
#include "bstruct.h"
28
#include "continueimp.h"
29
#include "dict.h"
30
#include "executor.h"
31
#include "executor.inl.h"
32
#include "impstr.h"
33
#include "object.h"
34
#include "objmembers.h"
35
#include "objmethods.h"
36

37
#if BOBJECTIMP_DEBUG
38
#include "escriptv.h"
39
#include <unordered_map>
40
#endif
41

42

43
namespace Pol::Bscript
44
{
45
Clib::fixed_allocator<sizeof( BObject ), 256> bobject_alloc;
46
Clib::fixed_allocator<sizeof( UninitObject ), 256> uninit_alloc;
47
Clib::fixed_allocator<sizeof( BLong ), 256> blong_alloc;
48
Clib::fixed_allocator<sizeof( Double ), 256> double_alloc;
49

50
size_t BObjectRef::sizeEstimate() const
2,301✔
51
{
52
  if ( get() )
2,301✔
53
    return sizeof( BObjectRef ) + get()->sizeEstimate();
2,211✔
54
  return sizeof( BObjectRef );
90✔
55
}
56
size_t BObject::sizeEstimate() const
4,741✔
57
{
58
  if ( objimp.get() )
4,741✔
59
    return sizeof( BObject ) + objimp.get()->sizeEstimate();
4,741✔
60
  return sizeof( BObject );
×
61
}
62

63

64
/**
65
 * Pack formats:
66
 * - sSTRING\0   string
67
 * - iINTEGER\0  integer
68
 * - rREAL\0     real
69
 * - u\0         uninitialized
70
 * - aNN:ELEMS   array
71
 * - SNN:STRING
72
 *
73
 * Examples:
74
 * - 57              i57
75
 * - 4.3             r4.3
76
 * - "hello world"   shello world
77
 * - { 5,3 }         a2:i5i3
78
 * - { 5, "hey" }    a2:i5S3:hey
79
 * - { 5, "hey", 7 } a3:i5S3:heyi7
80
 */
81
BObjectImp* BObjectImp::unpack( std::istream& is )
667✔
82
{
83
  char typech;
84
  if ( is >> typech )
667✔
85
  {
86
    switch ( typech )
667✔
87
    {
88
    case 's':
25✔
89
      return String::unpack( is );
25✔
90
    case 'S':
34✔
91
      return String::unpackWithLen( is );
34✔
92
    case 'i':
358✔
93
      return BLong::unpack( is );
358✔
94
    case 'r':
18✔
95
      return Double::unpack( is );
18✔
96
    case 'u':
189✔
97
      return UninitObject::create();
189✔
98
    case 'a':
19✔
99
      return ObjArray::unpack( is );
19✔
100
    case 'd':
9✔
101
      return BDictionary::unpack( is );
9✔
102
    case 't':
×
103
      return BStruct::unpack( is );
×
104
    case 'e':
3✔
105
      return BError::unpack( is );
3✔
106
    case 'x':
×
107
      return UninitObject::create();
×
108
    case 'b':
12✔
109
      return BBoolean::unpack( is );
12✔
110

111
    default:
×
112
      return new BError( "Unknown object type '" + std::string( 1, typech ) + "'" );
×
113
    }
114
  }
115
  else
116
  {
117
    return new BError( "Unable to extract type character" );
×
118
  }
119
}
120

121
BObjectImp* BObjectImp::unpack( const char* pstr )
179✔
122
{
123
  ISTRINGSTREAM is( pstr );
179✔
124
  return unpack( is );
358✔
125
}
179✔
126

127
BObject* BObject::clone() const
476✔
128
{
129
  return new BObject( objimp->copy() );
476✔
130
}
131

132
bool BObject::operator!=( const BObject& obj ) const
27,287✔
133
{
134
  return *objimp != *( obj.objimp );
27,287✔
135
}
136
bool BObject::operator==( const BObject& obj ) const
8,093✔
137
{
138
  return *objimp == *( obj.objimp );
8,093✔
139
}
140
bool BObject::operator<( const BObject& obj ) const
7,506✔
141
{
142
  return *objimp < *( obj.objimp );
7,506✔
143
}
144
bool BObject::operator<=( const BObject& obj ) const
803✔
145
{
146
  return *objimp <= *( obj.objimp );
803✔
147
}
148
bool BObject::operator>( const BObject& obj ) const
6,037✔
149
{
150
  return *objimp > *( obj.objimp );
6,037✔
151
}
152
bool BObject::operator>=( const BObject& obj ) const
419✔
153
{
154
  return *objimp >= *( obj.objimp );
419✔
155
}
156

157
////////////////////// BObjectImp //////////////////////
158
#if BOBJECTIMP_DEBUG
159
typedef std::unordered_map<unsigned int, BObjectImp*> bobjectimps;
160

161

162
bobjectimps bobjectimp_instances;
163
int display_bobjectimp_instance( BObjectImp* imp )
164
{
165
  INFO_PRINTLN( "{}: {}", imp->instance(), imp->getStringRep() );
166
  return 0;
167
}
168
void display_bobjectimp_instances()
169
{
170
  INFO_PRINTLN( "bobjectimp instances: {}", bobjectimp_instances.size() );
171
  for ( bobjectimps::iterator itr = bobjectimp_instances.begin(); itr != bobjectimp_instances.end();
172
        ++itr )
173
  {
174
    display_bobjectimp_instance( ( *itr ).second );
175
  }
176
}
177
#endif
178

179
#if !INLINE_BOBJECTIMP_CTOR
180
unsigned int BObjectImp::instances_ = 0;
181
Clib::SpinLock BObjectImp::bobjectimp_lock;
182
BObjectImp::BObjectImp( BObjectType type ) : type_( type ), instance_( 0 )
183
{
184
  Clib::SpinLockGuard lock( bobjectimp_lock );
185
  instance_ = instances_++;
186
  ++eobject_imp_count;
187
  ++eobject_imp_constructions;
188
  bobjectimp_instances[instance_] = this;
189
}
190

191
BObjectImp::~BObjectImp()
192
{
193
  Clib::SpinLockGuard lock( bobjectimp_lock );
194
  bobjectimp_instances.erase( instance_ );
195
  --eobject_imp_count;
196
}
197
#endif
198

199
std::string BObjectImp::pack() const
53✔
200
{
201
  OSTRINGSTREAM os;
53✔
202
  packonto( os );
53✔
203
  return OSTRINGSTREAM_STR( os );
106✔
204
}
53✔
205

206
void BObjectImp::packonto( std::ostream& os ) const
6✔
207
{
208
  os << "u";
6✔
209
}
6✔
210

211
std::string BObjectImp::getFormattedStringRep() const
1,087✔
212
{
213
  return getStringRep();
1,087✔
214
}
215

216
const char* BObjectImp::typestr( BObjectType typ )
337✔
217
{
218
  switch ( typ )
337✔
219
  {
220
  case OTUnknown:
×
221
    return "Unknown";
×
222
  case OTUninit:
×
223
    return "Uninit";
×
224
  case OTString:
203✔
225
    return "String";
203✔
226
  case OTLong:
61✔
227
    return "Integer";
61✔
228
  case OTDouble:
30✔
229
    return "Double";
30✔
230
  case OTArray:
18✔
231
    return "Array";
18✔
232
  case OTApplicPtr:
×
233
    return "ApplicPtr";
×
234
  case OTApplicObj:
×
235
    return "ApplicObj";
×
236
  case OTError:
2✔
237
    return "Error";
2✔
238
  case OTDictionary:
1✔
239
    return "Dictionary";
1✔
240
  case OTStruct:
1✔
241
    return "Struct";
1✔
242
  case OTPacket:
×
243
    return "Packet";
×
244
  case OTBinaryFile:
×
245
    return "BinaryFile";
×
246
  case OTBoolean:
6✔
247
    return "Boolean";
6✔
248
  case OTFuncRef:
15✔
249
    return "FunctionReference";
15✔
250
  default:
×
251
    return "Undefined";
×
252
  }
253
}
254

255
const char* BObjectImp::typeOf() const
202✔
256
{
257
  return typestr( type_ );
202✔
258
}
259

260

261
u8 BObjectImp::typeOfInt() const
68✔
262
{
263
  return type_;
68✔
264
}
265

266
/**
267
 * Can be overridden. By default objects are considered equal
268
 * only when having the same address in memory
269
 */
270
bool BObjectImp::operator==( const BObjectImp& objimp ) const
191✔
271
{
272
  return ( this == &objimp );
191✔
273
}
274
/**
275
 * Should be overridden. By default objects are lesser or greater
276
 * based on their type ID. Uninit and Error are always lesser than any other.
277
 * Same type object should have a custom comparison.
278
 *
279
 * @warning: do not forget to call base class when overriding
280
 */
281
bool BObjectImp::operator<( const BObjectImp& objimp ) const
272✔
282
{
283
  // Error an uninit are always lesser than any other type
284
  if ( ( objimp.type_ == OTError || objimp.type_ == OTUninit ) && type_ != OTError &&
272✔
285
       type_ != OTUninit )
45✔
286
    return false;
45✔
287

288
  if ( type_ == objimp.type_ )
227✔
289
  {
290
    // This is "undefined behavior" and should be avoided by implementing
291
    // comparison in child class
292
    return ( this < &objimp );
×
293
  }
294

295
  return type_ < objimp.type_;
227✔
296
}
297
/**
298
 * Can be overridden. By default uses == and <
299
 */
300
bool BObjectImp::operator<=( const BObjectImp& objimp ) const
803✔
301
{
302
  return *this == objimp || *this < objimp;
803✔
303
}
304
/**
305
 * Can be overridden. By default uses == and <
306
 */
307
bool BObjectImp::operator>( const BObjectImp& objimp ) const
6,037✔
308
{
309
  return !( *this == objimp || *this < objimp );
6,037✔
310
}
311
/**
312
 * Can be overridden. By default uses <
313
 */
314
bool BObjectImp::operator>=( const BObjectImp& objimp ) const
6,662✔
315
{
316
  return !( *this < objimp );
6,662✔
317
}
318
/**
319
 * Can be overridden. By default uses ==
320
 */
321
bool BObjectImp::operator!=( const BObjectImp& objimp ) const
27,287✔
322
{
323
  return !( *this == objimp );
27,287✔
324
}
325

326
BObjectImp* BObjectImp::array_assign( BObjectImp* /*idx*/, BObjectImp* /*target*/, bool /*copy*/ )
3✔
327
{
328
  return this;
3✔
329
}
330

331
BObjectRef BObjectImp::OperMultiSubscript( std::stack<BObjectRef>& indices )
6✔
332
{
333
  BObjectRef index = indices.top();
6✔
334
  indices.pop();
6✔
335
  BObjectRef ref = OperSubscript( *index );
6✔
336
  if ( indices.empty() )
6✔
337
    return ref;
3✔
338
  return ( *ref ).impptr()->OperMultiSubscript( indices );
3✔
339
}
6✔
340

341
BObjectRef BObjectImp::OperMultiSubscriptAssign( std::stack<BObjectRef>& indices,
×
342
                                                 BObjectImp* target )
343
{
344
  BObjectRef index = indices.top();
×
345
  indices.pop();
×
346
  if ( indices.empty() )
×
347
  {
348
    BObjectImp* imp = array_assign( ( *index ).impptr(), target, false );
×
349
    return BObjectRef( imp );
×
350
  }
351

352
  BObjectRef ref = OperSubscript( *index );
×
353
  return ( *ref ).impptr()->OperMultiSubscript( indices );
×
354
}
×
355

356
BObjectImp* BObjectImp::selfIsObjImp( const BObjectImp& objimp ) const
6✔
357
{
358
  return objimp.selfIsObj( *this );
6✔
359
}
360

361
BObjectImp* BObjectImp::selfIsObj( const BObjectImp& ) const
6✔
362
{
363
  return new BLong( 0 );
6✔
364
}
365

366
BObjectImp* BObjectImp::selfPlusObjImp( const BObjectImp& objimp ) const
1,219✔
367
{
368
  return objimp.selfPlusObj( *this );
1,219✔
369
}
370
BObjectImp* BObjectImp::selfPlusObj( const BObjectImp& /*objimp*/ ) const
57✔
371
{
372
  return copy();
57✔
373
}
374
BObjectImp* BObjectImp::selfPlusObj( const BLong& /*objimp*/ ) const
9✔
375
{
376
  return copy();
9✔
377
}
378
BObjectImp* BObjectImp::selfPlusObj( const Double& /*objimp*/ ) const
9✔
379
{
380
  return copy();
9✔
381
}
382
BObjectImp* BObjectImp::selfPlusObj( const String& /*objimp*/ ) const
24✔
383
{
384
  return copy();
24✔
385
}
386
BObjectImp* BObjectImp::selfPlusObj( const ObjArray& /*objimp*/ ) const
15✔
387
{
388
  return copy();
15✔
389
}
390
void BObjectImp::selfPlusObjImp( BObjectImp& objimp, BObject& obj )
78✔
391
{
392
  objimp.selfPlusObj( *this, obj );
78✔
393
}
78✔
394
void BObjectImp::selfPlusObj( BObjectImp& /*objimp*/, BObject& /*obj*/ )
45✔
395
{
396
  //
397
}
45✔
398
void BObjectImp::selfPlusObj( BLong& /*objimp*/, BObject& /*obj*/ )
15✔
399
{
400
  //
401
}
15✔
402
void BObjectImp::selfPlusObj( Double& /*objimp*/, BObject& /*obj*/ )
9✔
403
{
404
  // obj.setimp( selfPlusObj(objimp) );
405
}
9✔
406
void BObjectImp::selfPlusObj( String& /*objimp*/, BObject& /*obj*/ )
9✔
407
{
408
  // obj.setimp( selfPlusObj(objimp) );
409
}
9✔
410
void BObjectImp::selfPlusObj( ObjArray& /*objimp*/, BObject& /*obj*/ )
15✔
411
{
412
  // obj.setimp( selfPlusObj(objimp) );
413
}
15✔
414

415
BObjectImp* BObjectImp::selfMinusObjImp( const BObjectImp& objimp ) const
105✔
416
{
417
  return objimp.selfMinusObj( *this );
105✔
418
}
419
BObjectImp* BObjectImp::selfMinusObj( const BObjectImp& /*objimp*/ ) const
72✔
420
{
421
  return copy();
72✔
422
}
423
BObjectImp* BObjectImp::selfMinusObj( const BLong& /*objimp*/ ) const
12✔
424
{
425
  return copy();
12✔
426
}
427
BObjectImp* BObjectImp::selfMinusObj( const Double& /*objimp*/ ) const
12✔
428
{
429
  return copy();
12✔
430
}
431
BObjectImp* BObjectImp::selfMinusObj( const String& /*objimp*/ ) const
33✔
432
{
433
  return copy();
33✔
434
}
435
BObjectImp* BObjectImp::selfMinusObj( const ObjArray& /*objimp*/ ) const
×
436
{
437
  return copy();
×
438
}
439
void BObjectImp::selfMinusObjImp( BObjectImp& objimp, BObject& obj )
105✔
440
{
441
  objimp.selfMinusObj( *this, obj );
105✔
442
}
105✔
443
void BObjectImp::selfMinusObj( BObjectImp& /*objimp*/, BObject& /*obj*/ )
72✔
444
{
445
  //
446
}
72✔
447
void BObjectImp::selfMinusObj( BLong& /*objimp*/, BObject& /*obj*/ )
12✔
448
{
449
  //
450
}
12✔
451
void BObjectImp::selfMinusObj( Double& /*objimp*/, BObject& /*obj*/ )
12✔
452
{
453
  //
454
}
12✔
455
void BObjectImp::selfMinusObj( String& /*objimp*/, BObject& /*obj*/ )
12✔
456
{
457
  //
458
}
12✔
459
void BObjectImp::selfMinusObj( ObjArray& /*objimp*/, BObject& /*obj*/ )
×
460
{
461
  //
462
}
×
463

464
BObjectImp* BObjectImp::selfTimesObjImp( const BObjectImp& objimp ) const
237✔
465
{
466
  return objimp.selfTimesObj( *this );
237✔
467
}
468
BObjectImp* BObjectImp::selfTimesObj( const BObjectImp& /*objimp*/ ) const
237✔
469
{
470
  return copy();
237✔
471
}
472
BObjectImp* BObjectImp::selfTimesObj( const BLong& /*objimp*/ ) const
24✔
473
{
474
  return copy();
24✔
475
}
476
BObjectImp* BObjectImp::selfTimesObj( const Double& /*objimp*/ ) const
24✔
477
{
478
  return copy();
24✔
479
}
480
BObjectImp* BObjectImp::selfTimesObj( const String& /*objimp*/ ) const
×
481
{
482
  return copy();
×
483
}
484
BObjectImp* BObjectImp::selfTimesObj( const ObjArray& /*objimp*/ ) const
×
485
{
486
  return copy();
×
487
}
488
void BObjectImp::selfTimesObjImp( BObjectImp& objimp, BObject& obj )
162✔
489
{
490
  objimp.selfTimesObj( *this, obj );
162✔
491
}
162✔
492
void BObjectImp::selfTimesObj( BObjectImp& /*objimp*/, BObject& /*obj*/ )
162✔
493
{
494
  //
495
}
162✔
496
void BObjectImp::selfTimesObj( BLong& /*objimp*/, BObject& /*obj*/ )
24✔
497
{
498
  //
499
}
24✔
500
void BObjectImp::selfTimesObj( Double& /*objimp*/, BObject& /*obj*/ )
24✔
501
{
502
  //
503
}
24✔
504
void BObjectImp::selfTimesObj( String& /*objimp*/, BObject& /*obj*/ )
×
505
{
506
  //
507
}
×
508
void BObjectImp::selfTimesObj( ObjArray& /*objimp*/, BObject& /*obj*/ )
×
509
{
510
  //
511
}
×
512

513
BObjectImp* BObjectImp::selfDividedByObjImp( const BObjectImp& objimp ) const
237✔
514
{
515
  return objimp.selfDividedByObj( *this );
237✔
516
}
517
BObjectImp* BObjectImp::selfDividedByObj( const BObjectImp& /*objimp*/ ) const
237✔
518
{
519
  return copy();
237✔
520
}
521
BObjectImp* BObjectImp::selfDividedByObj( const BLong& /*objimp*/ ) const
24✔
522
{
523
  return copy();
24✔
524
}
525
BObjectImp* BObjectImp::selfDividedByObj( const Double& /*objimp*/ ) const
24✔
526
{
527
  return copy();
24✔
528
}
529
BObjectImp* BObjectImp::selfDividedByObj( const String& /*objimp*/ ) const
×
530
{
531
  return copy();
×
532
}
533
BObjectImp* BObjectImp::selfDividedByObj( const ObjArray& /*objimp*/ ) const
×
534
{
535
  return copy();
×
536
}
537
void BObjectImp::selfDividedByObjImp( BObjectImp& objimp, BObject& obj )
162✔
538
{
539
  objimp.selfDividedByObj( *this, obj );
162✔
540
}
162✔
541
void BObjectImp::selfDividedByObj( BObjectImp& /*objimp*/, BObject& /*obj*/ )
162✔
542
{
543
  //
544
}
162✔
545
void BObjectImp::selfDividedByObj( BLong& /*objimp*/, BObject& /*obj*/ )
24✔
546
{
547
  //
548
}
24✔
549
void BObjectImp::selfDividedByObj( Double& /*objimp*/, BObject& /*obj*/ )
24✔
550
{
551
  //
552
}
24✔
553
void BObjectImp::selfDividedByObj( String& /*objimp*/, BObject& /*obj*/ )
×
554
{
555
  //
556
}
×
557
void BObjectImp::selfDividedByObj( ObjArray& /*objimp*/, BObject& /*obj*/ )
×
558
{
559
  //
560
}
×
561

562
BObjectImp* BObjectImp::selfModulusObjImp( const BObjectImp& objimp ) const
237✔
563
{
564
  return objimp.selfModulusObj( *this );
237✔
565
}
566
BObjectImp* BObjectImp::selfModulusObj( const BObjectImp& /*objimp*/ ) const
237✔
567
{
568
  return copy();
237✔
569
}
570
BObjectImp* BObjectImp::selfModulusObj( const BLong& /*objimp*/ ) const
24✔
571
{
572
  return copy();
24✔
573
}
574
BObjectImp* BObjectImp::selfModulusObj( const Double& /*objimp*/ ) const
24✔
575
{
576
  return copy();
24✔
577
}
578
BObjectImp* BObjectImp::selfModulusObj( const String& /*objimp*/ ) const
×
579
{
580
  return copy();
×
581
}
582
BObjectImp* BObjectImp::selfModulusObj( const ObjArray& /*objimp*/ ) const
×
583
{
584
  return copy();
×
585
}
586
void BObjectImp::selfModulusObjImp( BObjectImp& objimp, BObject& obj )
162✔
587
{
588
  objimp.selfModulusObj( *this, obj );
162✔
589
}
162✔
590
void BObjectImp::selfModulusObj( BObjectImp& /*objimp*/, BObject& /*obj*/ )
162✔
591
{
592
  //
593
}
162✔
594
void BObjectImp::selfModulusObj( BLong& /*objimp*/, BObject& /*obj*/ )
24✔
595
{
596
  //
597
}
24✔
598
void BObjectImp::selfModulusObj( Double& /*objimp*/, BObject& /*obj*/ )
24✔
599
{
600
  //
601
}
24✔
602
void BObjectImp::selfModulusObj( String& /*objimp*/, BObject& /*obj*/ )
×
603
{
604
  //
605
}
×
606
void BObjectImp::selfModulusObj( ObjArray& /*objimp*/, BObject& /*obj*/ )
×
607
{
608
  //
609
}
×
610

611
BObjectImp* BObjectImp::selfBitShiftRightObjImp( const BObjectImp& objimp ) const
267✔
612
{
613
  return objimp.selfBitShiftRightObj( *this );
267✔
614
}
615
BObjectImp* BObjectImp::selfBitShiftRightObj( const BObjectImp& /*objimp*/ ) const
267✔
616
{
617
  return copy();
267✔
618
}
619
BObjectImp* BObjectImp::selfBitShiftRightObj( const BLong& /*objimp*/ ) const
27✔
620
{
621
  return copy();
27✔
622
}
623
BObjectImp* BObjectImp::selfBitShiftRightObj( const Double& /*objimp*/ ) const
×
624
{
625
  return copy();
×
626
}
627
BObjectImp* BObjectImp::selfBitShiftRightObj( const String& /*objimp*/ ) const
×
628
{
629
  return copy();
×
630
}
631
BObjectImp* BObjectImp::selfBitShiftRightObj( const ObjArray& /*objimp*/ ) const
×
632
{
633
  return copy();
×
634
}
635
void BObjectImp::selfBitShiftRightObjImp( BObjectImp& objimp, BObject& obj )
×
636
{
637
  objimp.selfBitShiftRightObj( *this, obj );
×
638
}
×
639
void BObjectImp::selfBitShiftRightObj( BObjectImp& /*objimp*/, BObject& /*obj*/ )
×
640
{
641
  //
642
}
×
643
void BObjectImp::selfBitShiftRightObj( BLong& /*objimp*/, BObject& /*obj*/ )
×
644
{
645
  //
646
}
×
647
void BObjectImp::selfBitShiftRightObj( Double& /*objimp*/, BObject& /*obj*/ )
×
648
{
649
  //
650
}
×
651
void BObjectImp::selfBitShiftRightObj( String& /*objimp*/, BObject& /*obj*/ )
×
652
{
653
  //
654
}
×
655
void BObjectImp::selfBitShiftRightObj( ObjArray& /*objimp*/, BObject& /*obj*/ )
×
656
{
657
  //
658
}
×
659

660
BObjectImp* BObjectImp::selfBitShiftLeftObjImp( const BObjectImp& objimp ) const
267✔
661
{
662
  return objimp.selfBitShiftLeftObj( *this );
267✔
663
}
664
BObjectImp* BObjectImp::selfBitShiftLeftObj( const BObjectImp& /*objimp*/ ) const
267✔
665
{
666
  return copy();
267✔
667
}
668
BObjectImp* BObjectImp::selfBitShiftLeftObj( const BLong& /*objimp*/ ) const
27✔
669
{
670
  return copy();
27✔
671
}
672
BObjectImp* BObjectImp::selfBitShiftLeftObj( const Double& /*objimp*/ ) const
×
673
{
674
  return copy();
×
675
}
676
BObjectImp* BObjectImp::selfBitShiftLeftObj( const String& /*objimp*/ ) const
×
677
{
678
  return copy();
×
679
}
680
BObjectImp* BObjectImp::selfBitShiftLeftObj( const ObjArray& /*objimp*/ ) const
×
681
{
682
  return copy();
×
683
}
684
void BObjectImp::selfBitShiftLeftObjImp( BObjectImp& objimp, BObject& obj )
×
685
{
686
  objimp.selfBitShiftLeftObj( *this, obj );
×
687
}
×
688
void BObjectImp::selfBitShiftLeftObj( BObjectImp& /*objimp*/, BObject& /*obj*/ )
×
689
{
690
  //
691
}
×
692
void BObjectImp::selfBitShiftLeftObj( BLong& /*objimp*/, BObject& /*obj*/ )
×
693
{
694
  //
695
}
×
696
void BObjectImp::selfBitShiftLeftObj( Double& /*objimp*/, BObject& /*obj*/ )
×
697
{
698
  //
699
}
×
700
void BObjectImp::selfBitShiftLeftObj( String& /*objimp*/, BObject& /*obj*/ )
×
701
{
702
  //
703
}
×
704
void BObjectImp::selfBitShiftLeftObj( ObjArray& /*objimp*/, BObject& /*obj*/ )
×
705
{
706
  //
707
}
×
708

709
BObjectImp* BObjectImp::selfBitAndObjImp( const BObjectImp& objimp ) const
267✔
710
{
711
  return objimp.selfBitAndObj( *this );
267✔
712
}
713
BObjectImp* BObjectImp::selfBitAndObj( const BObjectImp& /*objimp*/ ) const
267✔
714
{
715
  return copy();
267✔
716
}
717
BObjectImp* BObjectImp::selfBitAndObj( const BLong& /*objimp*/ ) const
28✔
718
{
719
  return copy();
28✔
720
}
721
BObjectImp* BObjectImp::selfBitAndObj( const Double& /*objimp*/ ) const
×
722
{
723
  return copy();
×
724
}
725
BObjectImp* BObjectImp::selfBitAndObj( const String& /*objimp*/ ) const
×
726
{
727
  return copy();
×
728
}
729
BObjectImp* BObjectImp::selfBitAndObj( const ObjArray& /*objimp*/ ) const
×
730
{
731
  return copy();
×
732
}
733
void BObjectImp::selfBitAndObjImp( BObjectImp& objimp, BObject& obj )
×
734
{
735
  objimp.selfBitAndObj( *this, obj );
×
736
}
×
737
void BObjectImp::selfBitAndObj( BObjectImp& /*objimp*/, BObject& /*obj*/ )
×
738
{
739
  //
740
}
×
741
void BObjectImp::selfBitAndObj( BLong& /*objimp*/, BObject& /*obj*/ )
×
742
{
743
  //
744
}
×
745
void BObjectImp::selfBitAndObj( Double& /*objimp*/, BObject& /*obj*/ )
×
746
{
747
  //
748
}
×
749
void BObjectImp::selfBitAndObj( String& /*objimp*/, BObject& /*obj*/ )
×
750
{
751
  //
752
}
×
753
void BObjectImp::selfBitAndObj( ObjArray& /*objimp*/, BObject& /*obj*/ )
×
754
{
755
  //
756
}
×
757

758
BObjectImp* BObjectImp::selfBitOrObjImp( const BObjectImp& objimp ) const
267✔
759
{
760
  return objimp.selfBitOrObj( *this );
267✔
761
}
762
BObjectImp* BObjectImp::selfBitOrObj( const BObjectImp& /*objimp*/ ) const
267✔
763
{
764
  return copy();
267✔
765
}
766
BObjectImp* BObjectImp::selfBitOrObj( const BLong& /*objimp*/ ) const
27✔
767
{
768
  return copy();
27✔
769
}
770
BObjectImp* BObjectImp::selfBitOrObj( const Double& /*objimp*/ ) const
×
771
{
772
  return copy();
×
773
}
774
BObjectImp* BObjectImp::selfBitOrObj( const String& /*objimp*/ ) const
×
775
{
776
  return copy();
×
777
}
778
BObjectImp* BObjectImp::selfBitOrObj( const ObjArray& /*objimp*/ ) const
×
779
{
780
  return copy();
×
781
}
782
void BObjectImp::selfBitOrObjImp( BObjectImp& objimp, BObject& obj )
×
783
{
784
  objimp.selfBitOrObj( *this, obj );
×
785
}
×
786
void BObjectImp::selfBitOrObj( BObjectImp& /*objimp*/, BObject& /*obj*/ )
×
787
{
788
  //
789
}
×
790
void BObjectImp::selfBitOrObj( BLong& /*objimp*/, BObject& /*obj*/ )
×
791
{
792
  //
793
}
×
794
void BObjectImp::selfBitOrObj( Double& /*objimp*/, BObject& /*obj*/ )
×
795
{
796
  //
797
}
×
798
void BObjectImp::selfBitOrObj( String& /*objimp*/, BObject& /*obj*/ )
×
799
{
800
  //
801
}
×
802
void BObjectImp::selfBitOrObj( ObjArray& /*objimp*/, BObject& /*obj*/ )
×
803
{
804
  //
805
}
×
806

807
BObjectImp* BObjectImp::selfBitXorObjImp( const BObjectImp& objimp ) const
267✔
808
{
809
  return objimp.selfBitXorObj( *this );
267✔
810
}
811
BObjectImp* BObjectImp::selfBitXorObj( const BObjectImp& /*objimp*/ ) const
267✔
812
{
813
  return copy();
267✔
814
}
815
BObjectImp* BObjectImp::selfBitXorObj( const BLong& /*objimp*/ ) const
27✔
816
{
817
  return copy();
27✔
818
}
819
BObjectImp* BObjectImp::selfBitXorObj( const Double& /*objimp*/ ) const
×
820
{
821
  return copy();
×
822
}
823
BObjectImp* BObjectImp::selfBitXorObj( const String& /*objimp*/ ) const
×
824
{
825
  return copy();
×
826
}
827
BObjectImp* BObjectImp::selfBitXorObj( const ObjArray& /*objimp*/ ) const
×
828
{
829
  return copy();
×
830
}
831
void BObjectImp::selfBitXorObjImp( BObjectImp& objimp, BObject& obj )
×
832
{
833
  objimp.selfBitXorObj( *this, obj );
×
834
}
×
835
void BObjectImp::selfBitXorObj( BObjectImp& /*objimp*/, BObject& /*obj*/ )
×
836
{
837
  //
838
}
×
839
void BObjectImp::selfBitXorObj( BLong& /*objimp*/, BObject& /*obj*/ )
×
840
{
841
  //
842
}
×
843
void BObjectImp::selfBitXorObj( Double& /*objimp*/, BObject& /*obj*/ )
×
844
{
845
  //
846
}
×
847
void BObjectImp::selfBitXorObj( String& /*objimp*/, BObject& /*obj*/ )
×
848
{
849
  //
850
}
×
851
void BObjectImp::selfBitXorObj( ObjArray& /*objimp*/, BObject& /*obj*/ )
×
852
{
853
  //
854
}
×
855

856
BObjectImp* BObjectImp::bitnot() const
132✔
857
{
858
  return copy();
132✔
859
}
860

861
void BObjectImp::operInsertInto( BObject& obj, const BObjectImp& /*objimp*/ )
×
862
{
863
  obj.setimp( new BError( "Object is not a 'container'" ) );
×
864
}
×
865

866

867
void BObjectImp::operPlusEqual( BObject& obj, BObjectImp& objimp )
827✔
868
{
869
  objimp.selfPlusObjImp( *this, obj );
827✔
870
  // obj.setimp( objimp.selfPlusObjImp( *this ) );
871
}
827✔
872

873
void BObjectImp::operMinusEqual( BObject& obj, BObjectImp& objimp )
246✔
874
{
875
  objimp.selfMinusObjImp( *this, obj );
246✔
876
  // obj.setimp( selfMinusObjImp( objimp ) );
877
}
246✔
878

879
void BObjectImp::operTimesEqual( BObject& obj, BObjectImp& objimp )
246✔
880
{
881
  objimp.selfTimesObjImp( *this, obj );
246✔
882
  // obj.setimp( selfTimesObjImp( objimp ) );
883
}
246✔
884

885
void BObjectImp::operDivideEqual( BObject& obj, BObjectImp& objimp )
234✔
886
{
887
  objimp.selfDividedByObjImp( *this, obj );
234✔
888
  // obj.setimp( selfDividedByObjImp( objimp ) );
889
}
234✔
890

891
void BObjectImp::operModulusEqual( BObject& obj, BObjectImp& objimp )
381✔
892
{
893
  objimp.selfModulusObjImp( *this, obj );
381✔
894
  // obj.setimp( selfModulusObjImp( objimp ) );
895
}
381✔
896

897
BObject BObjectImp::operator-() const
×
898
{
899
  BObjectImp* newobj = inverse();
×
900
  return BObject( newobj );
×
901
}
902

903
BObjectImp* BObjectImp::inverse() const
105✔
904
{
905
  return UninitObject::create();
105✔
906
}
907

908
void BObjectImp::selfPlusPlus() {}
18✔
909

910
void BObjectImp::selfMinusMinus() {}
9✔
911

912
BObjectRef BObjectImp::OperSubscript( const BObject& /*obj*/ )
25✔
913
{
914
  return BObjectRef( copy() );
25✔
915
}
916

917
/*
918
  "All Objects are inherently good."
919
  */
920
bool BObjectImp::isTrue() const
2,341✔
921
{
922
  return true;
2,341✔
923
}
924

925
BObjectImp* BObjectImp::call_method( const char* methodname, Executor& /*ex*/ )
25✔
926
{
927
  return new BError( std::string( "Method '" ) + methodname + "' not found" );
25✔
928
}
929
BObjectImp* BObjectImp::call_method_id( const int id, Executor& /*ex*/, bool /*forcebuiltin*/ )
3✔
930
{
931
  OSTRINGSTREAM os;
3✔
932
  os << "Method id '" << id << "' (" << getObjMethod( id )->code << ") not found";
3✔
933
  return new BError( std::string( OSTRINGSTREAM_STR( os ) ) );
6✔
934
}
3✔
935
BObjectRef BObjectImp::set_member( const char* membername, BObjectImp* /*valueimp*/, bool /*copy*/ )
3✔
936
{
937
  return BObjectRef( new BError( std::string( "Member '" ) + membername + "' not found" ) );
6✔
938
}
939
BObjectRef BObjectImp::get_member( const char* /*membername*/ )
37✔
940
{
941
  return BObjectRef( new BError( "Object does not support members" ) );
74✔
942
}
943
BObjectRef BObjectImp::get_member_id( const int id )
7,711✔
944
{
945
  ObjMember* memb = getObjMember( id );
7,711✔
946

947
  return get_member( memb->code );
7,711✔
948
}
949
BObjectRef BObjectImp::set_member_id( const int id, BObjectImp* valueimp, bool copy )
190✔
950
{
951
  ObjMember* memb = getObjMember( id );
190✔
952

953
  return set_member( memb->code, valueimp, copy );
190✔
954
}
955
long BObjectImp::contains( const BObjectImp& /*imp*/ ) const
3✔
956
{
957
  return 0;
3✔
958
}
959

960
BObjectRef BObjectImp::operDotPlus( const char* /*name*/ )
78✔
961
{
962
  return BObjectRef( new BError( "Operator .+ undefined" ) );
156✔
963
}
964

965
BObjectRef BObjectImp::operDotMinus( const char* /*name*/ )
78✔
966
{
967
  return BObjectRef( new BError( "Operator .- undefined" ) );
156✔
968
}
969

970
BObjectRef BObjectImp::operDotQMark( const char* /*name*/ )
4✔
971
{
972
  return BObjectRef( new BError( "Operator .? undefined" ) );
8✔
973
}
974

975
UninitObject* UninitObject::SharedInstance;
976
ref_ptr<BObjectImp> UninitObject::SharedInstanceOwner;
977

978
UninitObject::UninitObject() : BObjectImp( OTUninit ) {}
27,403✔
979

980
BObjectImp* UninitObject::copy() const
1,002✔
981
{
982
  return create();
1,002✔
983
}
984

985
size_t UninitObject::sizeEstimate() const
154✔
986
{
987
  return sizeof( UninitObject );
154✔
988
}
989

990
bool UninitObject::isTrue() const
2,355✔
991
{
992
  return false;
2,355✔
993
}
994

995
/**
996
 * An uninit is equal to any other error or uninit
997
 */
998
bool UninitObject::operator==( const BObjectImp& imp ) const
39✔
999
{
1000
  return ( imp.isa( OTError ) || imp.isa( OTUninit ) );
39✔
1001
}
1002

1003
bool UninitObject::operator<( const BObjectImp& imp ) const
375✔
1004
{
1005
  if ( imp.isa( OTError ) || imp.isa( OTUninit ) )
375✔
1006
    return false;  // Because it's equal can't be lesser
366✔
1007

1008
  return true;
9✔
1009
}
1010

1011

1012
ObjArray::ObjArray() : BObjectImp( OTArray ), name_arr(), ref_arr() {}
6,722✔
1013

1014
ObjArray::ObjArray( BObjectType type ) : BObjectImp( type ), name_arr(), ref_arr() {}
×
1015

1016
ObjArray::ObjArray( const ObjArray& copyfrom )
4,890✔
1017
    : BObjectImp( copyfrom.type() ), name_arr( copyfrom.name_arr ), ref_arr( copyfrom.ref_arr )
4,890✔
1018
{
1019
  deepcopy();
4,890✔
1020
}
4,890✔
1021

1022
void ObjArray::deepcopy()
4,890✔
1023
{
1024
  for ( auto& elem : ref_arr )
53,481✔
1025
  {
1026
    if ( elem.get() )
48,591✔
1027
    {
1028
      /*
1029
          NOTE: all BObjectRefs in an ObjArray reference BNamedObjects not BObjects
1030
          HMMM, can this BNamedObject get destructed before we're done with it?
1031
          No, we're making a copy, leaving the original be.
1032
          (SO, bno's refcount should be >1 here)
1033
          */
1034

1035
      BObject* bo = elem.get();
48,579✔
1036
      elem.set( new BObject( bo->impptr()->copy() ) );
48,579✔
1037
    }
1038
  }
1039
}
4,890✔
1040

1041
BObjectImp* ObjArray::copy() const
4,834✔
1042
{
1043
  auto nobj = new ObjArray( *this );
4,834✔
1044
  return nobj;
4,834✔
1045
}
1046

1047
size_t ObjArray::sizeEstimate() const
561✔
1048
{
1049
  size_t size = sizeof( ObjArray );
561✔
1050
  size += Clib::memsize( ref_arr );
561✔
1051
  for ( const auto& elem : ref_arr )
2,180✔
1052
  {
1053
    size += elem.sizeEstimate();
1,619✔
1054
  }
1055
  size += Clib::memsize( name_arr );
561✔
1056
  for ( const auto& elem : name_arr )
597✔
1057
  {
1058
    size += elem.capacity();
36✔
1059
  }
1060
  return size;
561✔
1061
}
1062

1063
/**
1064
 * Equality for arrays:
1065
 * if the other guy is an array, check each element
1066
 * otherwise not equal.
1067
 * note that struct names aren't checked.
1068
 *
1069
 * @todo check structure names too?
1070
 */
1071
bool ObjArray::operator==( const BObjectImp& imp ) const
94✔
1072
{
1073
  if ( !imp.isa( OTArray ) )
94✔
1074
    return false;
27✔
1075

1076
  const ObjArray& thatarr = static_cast<const ObjArray&>( imp );
67✔
1077
  if ( thatarr.ref_arr.size() != ref_arr.size() )
67✔
1078
    return false;
3✔
1079

1080
  for ( unsigned i = 0; i < ref_arr.size(); ++i )
311✔
1081
  {
1082
    const BObjectRef& thisref = ref_arr[i];
250✔
1083
    const BObjectRef& thatref = thatarr.ref_arr[i];
250✔
1084

1085
    const BObject* thisobj = thisref.get();
250✔
1086
    const BObject* thatobj = thatref.get();
250✔
1087
    if ( thisobj != nullptr && thatobj != nullptr )
250✔
1088
    {
1089
      const BObjectImp& thisimp = thisobj->impref();
250✔
1090
      const BObjectImp& thatimp = thatobj->impref();
250✔
1091

1092
      if ( thisimp == thatimp )
250✔
1093
        continue;
247✔
1094
      return false;
3✔
1095
    }
1096
    if ( thisobj == nullptr && thatobj == nullptr )
×
1097
    {
1098
      continue;
×
1099
    }
1100

1101
    return false;
×
1102
  }
1103
  return true;
61✔
1104
}
1105

1106
const BObjectImp* ObjArray::imp_at( unsigned index /* 1-based */ ) const
×
1107
{
1108
  assert( index > 0 );
1109
  if ( index > ref_arr.size() )
×
1110
    return nullptr;
×
1111
  const BObjectRef& ref = ref_arr[index - 1];
×
1112
  if ( ref.get() == nullptr )
×
1113
    return nullptr;
×
1114
  return ref.get()->impptr();
×
1115
}
1116

1117
BObjectImp* ObjArray::array_assign( BObjectImp* idx, BObjectImp* target, bool copy )
525✔
1118
{
1119
  if ( idx->isa( OTLong ) )
525✔
1120
  {
1121
    BLong& lng = (BLong&)*idx;
525✔
1122

1123
    unsigned index = (unsigned)lng.value();
525✔
1124
    if ( index > ref_arr.size() )
525✔
1125
      ref_arr.resize( index );
300✔
1126
    else if ( index <= 0 )
225✔
1127
      return new BError( "Array index out of bounds" );
×
1128

1129
    BObjectRef& ref = ref_arr[index - 1];
525✔
1130
    BObject* refobj = ref.get();
525✔
1131

1132
    BObjectImp* new_target = copy ? target->copy() : target;
525✔
1133

1134
    if ( refobj != nullptr )
525✔
1135
    {
1136
      refobj->setimp( new_target );
219✔
1137
    }
1138
    else
1139
    {
1140
      ref.set( new BObject( new_target ) );
306✔
1141
    }
1142
    return ref->impptr();
525✔
1143
  }
1144

1145
  return UninitObject::create();
×
1146
}
1147

1148
void ObjArray::operInsertInto( BObject& /*obj*/, const BObjectImp& objimp )
9,064✔
1149
{
1150
  ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
9,064✔
1151
}
9,064✔
1152

1153
BObjectImp* ObjArray::selfPlusObj( const BObjectImp& objimp ) const
9✔
1154
{
1155
  std::unique_ptr<ObjArray> result( new ObjArray( *this ) );
9✔
1156
  result->ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
9✔
1157
  return result.release();
18✔
1158
}
9✔
1159
BObjectImp* ObjArray::selfPlusObj( const BLong& objimp ) const
6✔
1160
{
1161
  std::unique_ptr<ObjArray> result( new ObjArray( *this ) );
6✔
1162
  result->ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
6✔
1163
  return result.release();
12✔
1164
}
6✔
1165
BObjectImp* ObjArray::selfPlusObj( const Double& objimp ) const
3✔
1166
{
1167
  std::unique_ptr<ObjArray> result( new ObjArray( *this ) );
3✔
1168
  result->ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
3✔
1169
  return result.release();
6✔
1170
}
3✔
1171
BObjectImp* ObjArray::selfPlusObj( const String& objimp ) const
9✔
1172
{
1173
  std::unique_ptr<ObjArray> result( new ObjArray( *this ) );
9✔
1174
  result->ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
9✔
1175
  return result.release();
18✔
1176
}
9✔
1177

1178
BObjectImp* ObjArray::selfPlusObj( const ObjArray& objimp ) const
26✔
1179
{
1180
  std::unique_ptr<ObjArray> result( new ObjArray( *this ) );
26✔
1181

1182
  for ( const auto& elem : objimp.ref_arr )
77✔
1183
  {
1184
    if ( elem.get() )
51✔
1185
    {
1186
      /*
1187
          NOTE: all BObjectRefs in an ObjArray reference BNamedObjects not BObjects
1188
          HMMM, can this BNamedObject get destructed before we're done with it?
1189
          No, we're making a copy, leaving the original be.
1190
          (SO, bno's refcount should be >1 here)
1191
          */
1192
      BObject* bo = elem.get();
42✔
1193

1194
      result->ref_arr.push_back( BObjectRef( new BObject( ( *bo )->copy() ) ) );
42✔
1195
    }
1196
    else
1197
    {
1198
      result->ref_arr.emplace_back();
9✔
1199
    }
1200
  }
1201
  return result.release();
52✔
1202
}
26✔
1203

1204
BObjectImp* ObjArray::selfPlusObjImp( const BObjectImp& other ) const
224✔
1205
{
1206
  return other.selfPlusObj( *this );
224✔
1207
}
1208
void ObjArray::selfPlusObjImp( BObjectImp& objimp, BObject& obj )
27✔
1209
{
1210
  objimp.selfPlusObj( *this, obj );
27✔
1211
}
27✔
1212
void ObjArray::selfPlusObj( BObjectImp& objimp, BObject& /*obj*/ )
9✔
1213
{
1214
  ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
9✔
1215
}
9✔
1216
void ObjArray::selfPlusObj( BLong& objimp, BObject& /*obj*/ )
3✔
1217
{
1218
  ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
3✔
1219
}
3✔
1220
void ObjArray::selfPlusObj( Double& objimp, BObject& /*obj*/ )
3✔
1221
{
1222
  ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
3✔
1223
}
3✔
1224
void ObjArray::selfPlusObj( String& objimp, BObject& /*obj*/ )
3✔
1225
{
1226
  ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
3✔
1227
}
3✔
1228
void ObjArray::selfPlusObj( ObjArray& objimp, BObject& /*obj*/ )
3✔
1229
{
1230
  for ( const auto& itr : objimp.ref_arr )
3✔
1231
  {
NEW
1232
    if ( itr.get() )
×
1233
    {
1234
      /*
1235
          NOTE: all BObjectRefs in an ObjArray reference BNamedObjects not BObjects
1236
          HMMM, can this BNamedObject get destructed before we're done with it?
1237
          No, we're making a copy, leaving the original be.
1238
          (SO, bno's refcount should be >1 here)
1239
          */
NEW
1240
      BObject* bo = itr.get();
×
1241

1242
      ref_arr.push_back( BObjectRef( new BObject( ( *bo )->copy() ) ) );
×
1243
    }
1244
    else
1245
    {
1246
      ref_arr.emplace_back();
×
1247
    }
1248
  }
1249
}
3✔
1250

1251
BObjectRef ObjArray::OperMultiSubscript( std::stack<BObjectRef>& indices )
9✔
1252
{
1253
  BObjectRef start_ref = indices.top();
9✔
1254
  indices.pop();
9✔
1255
  BObjectRef length_ref = indices.top();
9✔
1256
  indices.pop();
9✔
1257

1258
  BObject& length_obj = *length_ref;
9✔
1259
  BObject& start_obj = *start_ref;
9✔
1260

1261
  BObjectImp& length = length_obj.impref();
9✔
1262
  BObjectImp& start = start_obj.impref();
9✔
1263

1264
  // first deal with the start position.
1265
  // return BObjectRef(new BError( "Subscript out of range" ));
1266

1267
  unsigned index;
1268
  if ( start.isa( OTLong ) )
9✔
1269
  {
1270
    BLong& lng = (BLong&)start;
9✔
1271
    index = (unsigned)lng.value();
9✔
1272
    if ( index == 0 || index > ref_arr.size() )
9✔
1273
      return BObjectRef( new BError( "Array start index out of bounds" ) );
×
1274
  }
1275
  else
1276
    return BObjectRef( copy() );
×
1277

1278
  // now the end index
1279

1280
  unsigned end;
1281
  if ( length.isa( OTLong ) )
9✔
1282
  {
1283
    BLong& lng = (BLong&)length;
6✔
1284
    end = (unsigned)lng.value();
6✔
1285
    if ( end == 0 || end > ref_arr.size() )
6✔
1286
      return BObjectRef( new BError( "Array end index out of bounds" ) );
×
1287
  }
1288
  else
1289
    return BObjectRef( copy() );
3✔
1290

1291
  auto str = new ObjArray();
6✔
1292

1293

1294
  // std::unique_ptr<ObjArray> result (new ObjArray());
1295
  unsigned i = 0;
6✔
1296
  for ( const auto& itr : ref_arr )
663✔
1297
  {
1298
    if ( ++i < index )
660✔
1299
      continue;
534✔
1300
    if ( i > end )
126✔
1301
      break;
3✔
1302
    if ( itr.get() )
123✔
1303
    {
1304
      BObject* bo = itr.get();
123✔
1305
      str->ref_arr.push_back( BObjectRef( new BObject( ( *bo )->copy() ) ) );
123✔
1306
    }
1307
    else
1308
    {
1309
      str->ref_arr.emplace_back();
×
1310
    }
1311
  }
1312
  /*
1313
  for (unsigned i = index; i < end; i++) {
1314
  BObject *bo = ref_arr[i];
1315
  if (bo != 0)
1316
  str->ref_arr.push_back( BObjectRef( new BObject( (*bo)->copy() ) ) );
1317
  else
1318
  result->ref_arr.push_back( BObjectRef() );
1319
  } */
1320
  //  return result.release();
1321
  return BObjectRef( str );
6✔
1322
}
9✔
1323

1324
BObjectRef ObjArray::OperSubscript( const BObject& rightobj )
2,996✔
1325
{
1326
  const BObjectImp& right = rightobj.impref();
2,996✔
1327
  if ( right.isa( OTLong ) )  // vector
2,996✔
1328
  {
1329
    BLong& lng = (BLong&)right;
2,996✔
1330

1331
    unsigned index = (unsigned)lng.value();
2,996✔
1332
    if ( index > ref_arr.size() )
2,996✔
1333
    {
1334
      return BObjectRef( new BError( "Array index out of bounds" ) );
17✔
1335
    }
1336
    if ( index <= 0 )
2,979✔
1337
      return BObjectRef( new BError( "Array index out of bounds" ) );
4✔
1338

1339
    BObjectRef& ref = ref_arr[index - 1];
2,975✔
1340
    if ( ref.get() == nullptr )
2,975✔
1341
      ref.set( new BObject( UninitObject::create() ) );
×
1342
    return ref;
2,975✔
1343
  }
1344
  if ( right.isa( OTString ) )
×
1345
  {
1346
    // TODO: search for named variables (structure members)
1347
    return BObjectRef( copy() );
×
1348
  }
1349

1350
  // TODO: crap out
1351
  return BObjectRef( copy() );
×
1352
}
1353

1354
BObjectRef ObjArray::get_member( const char* membername )
60✔
1355
{
1356
  int i = 0;
60✔
1357
  for ( const_name_iterator itr = name_arr.begin(), end = name_arr.end(); itr != end; ++itr, ++i )
111✔
1358
  {
1359
    const std::string& name = ( *itr );
102✔
1360
    if ( stricmp( name.c_str(), membername ) == 0 )
102✔
1361
    {
1362
      return ref_arr[i];
102✔
1363
    }
1364
  }
1365

1366
  return BObjectRef( UninitObject::create() );
9✔
1367
}
1368

1369
BObjectRef ObjArray::set_member( const char* membername, BObjectImp* valueimp, bool copy )
12✔
1370
{
1371
  int i = 0;
12✔
1372
  for ( const_name_iterator itr = name_arr.begin(), end = name_arr.end(); itr != end; ++itr, ++i )
24✔
1373
  {
1374
    const std::string& name = ( *itr );
24✔
1375
    if ( stricmp( name.c_str(), membername ) == 0 )
24✔
1376
    {
1377
      BObjectImp* target = copy ? valueimp->copy() : valueimp;
12✔
1378
      ref_arr[i].get()->setimp( target );
12✔
1379
      return ref_arr[i];
24✔
1380
    }
1381
  }
1382
  return BObjectRef( UninitObject::create() );
×
1383
}
1384

1385
BObjectRef ObjArray::operDotPlus( const char* name )
27✔
1386
{
1387
  for ( auto& elem : name_arr )
36✔
1388
  {
1389
    if ( stricmp( name, elem.c_str() ) == 0 )
9✔
1390
    {
1391
      return BObjectRef( new BError( "Member already exists" ) );
×
1392
    }
1393
  }
1394
  name_arr.emplace_back( name );
27✔
1395
  auto pnewobj = new BObject( UninitObject::create() );
27✔
1396
  ref_arr.emplace_back( pnewobj );
27✔
1397
  return BObjectRef( pnewobj );
27✔
1398
}
1399

1400
void ObjArray::addElement( BObjectImp* imp )
44,214✔
1401
{
1402
  ref_arr.push_back( BObjectRef( new BObject( imp ) ) );
44,214✔
1403
}
44,214✔
1404

1405
std::string ObjArray::getStringRep() const
3,355✔
1406
{
1407
  OSTRINGSTREAM os;
3,355✔
1408
  os << "{ ";
3,355✔
1409
  bool any = false;
3,355✔
1410
  for ( const auto& elem : ref_arr )
17,521✔
1411
  {
1412
    if ( any )
14,166✔
1413
      os << ", ";
11,669✔
1414
    else
1415
      any = true;
2,497✔
1416

1417
    BObject* bo = elem.get();
14,166✔
1418

1419
    if ( bo != nullptr )
14,166✔
1420
    {
1421
      std::string tmp = bo->impptr()->getStringRep();
14,124✔
1422
      os << tmp;
14,124✔
1423
    }
14,124✔
1424
  }
1425
  os << " }";
3,355✔
1426

1427
  return OSTRINGSTREAM_STR( os );
6,710✔
1428
}
3,355✔
1429

1430
long ObjArray::contains( const BObjectImp& imp ) const
864✔
1431
{
1432
  for ( auto itr = ref_arr.begin(), end = ref_arr.end(); itr != end; ++itr )
1,676✔
1433
  {
1434
    if ( itr->get() )
1,085✔
1435
    {
1436
      BObject* bo = ( itr->get() );
1,085✔
1437
      if ( bo == nullptr )
1,085✔
1438
      {
1439
        INFO_PRINTLN( "{} - '{} in array{{}}' check. Invalid data at index {}",
×
1440
                      Clib::scripts_thread_script, imp, ( itr - ref_arr.begin() ) + 1 );
×
1441
        continue;
×
1442
      }
1443
      if ( *( bo->impptr() ) == imp )
1,085✔
1444
      {
1445
        return ( static_cast<long>( ( itr - ref_arr.begin() ) + 1 ) );
273✔
1446
      }
1447
    }
1448
  }
1449
  return 0;
591✔
1450
}
1451

1452
class objref_cmp
1453
{
1454
public:
1455
  bool operator()( const BObjectRef& x1, const BObjectRef& x2 ) const
551✔
1456
  {
1457
    const BObject* b1 = x1.get();
551✔
1458
    const BObject* b2 = x2.get();
551✔
1459
    if ( b1 == nullptr || b2 == nullptr )
551✔
1460
      return ( &x1 < &x2 );
×
1461

1462
    const BObject& r1 = *b1;
551✔
1463
    const BObject& r2 = *b2;
551✔
1464
    return ( r1 < r2 );
551✔
1465
  }
1466
};
1467

1468
BObjectImp* ObjArray::call_method_id( const int id, Executor& ex, bool /*forcebuiltin*/ )
10,241✔
1469
{
1470
  switch ( id )
10,241✔
1471
  {
1472
  case MTH_SIZE:
1,001✔
1473
    if ( ex.numParams() == 0 )
1,001✔
1474
      return new BLong( static_cast<int>( ref_arr.size() ) );
1,001✔
1475
    else
1476
      return new BError( "array.size() doesn't take parameters." );
×
1477

1478
  case MTH_ERASE:
31✔
1479
    if ( name_arr.empty() )
31✔
1480
    {
1481
      if ( ex.numParams() == 1 )
31✔
1482
      {
1483
        int idx;
1484
        if ( ex.getParam( 0, idx, 1, static_cast<int>( ref_arr.size() ) ) )  // 1-based index
31✔
1485
        {
1486
          ref_arr.erase( ref_arr.begin() + idx - 1 );
22✔
1487
          return new BLong( 1 );
22✔
1488
        }
1489

1490
        return nullptr;
9✔
1491
      }
1492
      return new BError( "array.erase(index) requires a parameter." );
×
1493
    }
1494
    break;
×
1495
  case MTH_EXISTS:
×
1496
    if ( name_arr.empty() )
×
1497
    {
1498
      if ( ex.numParams() == 1 )
×
1499
      {
1500
        int idx;
1501
        if ( ex.getParam( 0, idx ) && idx >= 0 )
×
1502
        {
1503
          bool exists = ( idx <= (int)ref_arr.size() );
×
1504
          return new BLong( exists ? 1 : 0 );
×
1505
        }
1506

1507
        return new BError( "Invalid parameter type" );
×
1508
      }
1509
      return new BError( "array.exists(index) requires a parameter." );
×
1510
    }
1511
    break;
×
1512
  case MTH_INSERT:
30✔
1513
    if ( name_arr.empty() )
30✔
1514
    {
1515
      if ( ex.numParams() == 2 )
30✔
1516
      {
1517
        int idx;
1518
        BObjectImp* imp = ex.getParamImp( 1 );
30✔
1519
        if ( ex.getParam( 0, idx, 1, static_cast<int>( ref_arr.size() + 1 ) ) &&
30✔
1520
             imp != nullptr )  // 1-based index
1521
        {
1522
          --idx;
30✔
1523
          BObjectRef tmp;
30✔
1524
          ref_arr.insert( ref_arr.begin() + idx, tmp );
30✔
1525
          BObjectRef& ref = ref_arr[idx];
30✔
1526
          ref.set( new BObject( imp->copy() ) );
30✔
1527
        }
30✔
1528
        else
1529
        {
1530
          return new BError( "Invalid parameter type" );
×
1531
        }
1532
      }
1533
      else
1534
        return new BError( "array.insert(index,value) requires two parameters." );
×
1535
    }
1536
    break;
30✔
1537
  case MTH_SHRINK:
247✔
1538
    if ( name_arr.empty() )
247✔
1539
    {
1540
      if ( ex.numParams() == 1 )
247✔
1541
      {
1542
        int idx;
1543
        if ( ex.getParam( 0, idx, 0, static_cast<int>( ref_arr.size() ) ) )  // 1-based index
247✔
1544
        {
1545
          ref_arr.erase( ref_arr.begin() + idx, ref_arr.end() );
241✔
1546
          return new BLong( 1 );
241✔
1547
        }
1548

1549
        return new BError( "Invalid parameter type" );
6✔
1550
      }
1551
      return new BError( "array.shrink(nelems) requires a parameter." );
×
1552
    }
1553
    break;
×
1554
  case MTH_APPEND:
7,916✔
1555
    if ( name_arr.empty() )
7,916✔
1556
    {
1557
      if ( ex.numParams() == 1 )
7,916✔
1558
      {
1559
        BObjectImp* imp = ex.getParamImp( 0 );
7,916✔
1560
        if ( imp )
7,916✔
1561
        {
1562
          ref_arr.push_back( BObjectRef( new BObject( imp->copy() ) ) );
7,916✔
1563

1564
          return new BLong( 1 );
7,916✔
1565
        }
1566

1567
        return new BError( "Invalid parameter type" );
×
1568
      }
1569
      return new BError( "array.append(value) requires a parameter." );
×
1570
    }
1571
    break;
×
1572
  case MTH_REVERSE:
9✔
1573
    if ( name_arr.empty() )
9✔
1574
    {
1575
      if ( ex.numParams() == 0 )
9✔
1576
      {
1577
        reverse( ref_arr.begin(), ref_arr.end() );
9✔
1578
        return new BLong( 1 );
9✔
1579
      }
1580
      return new BError( "array.reverse() doesn't take parameters." );
×
1581
    }
1582
    break;
×
1583
  case MTH_SORT:
52✔
1584
    if ( name_arr.empty() )
52✔
1585
    {
1586
      if ( ex.numParams() == 0 )
52✔
1587
      {
1588
        sort( ref_arr.begin(), ref_arr.end(), objref_cmp() );
23✔
1589
        return new BLong( 1 );
23✔
1590
      }
1591
      if ( ex.numParams() == 1 )
29✔
1592
      {
1593
        int sub_index;
1594
        if ( !ex.getParam( 0, sub_index ) )
29✔
1595
          return new BError( "Invalid parameter type" );
×
1596
        if ( sub_index < 1 )
29✔
1597
          return new BError( "Invalid sub_index value" );
3✔
1598
        for ( const auto& ref : ref_arr )
103✔
1599
        {
1600
          if ( ref.get() == nullptr || !ref.get()->isa( OTArray ) )
89✔
1601
            return new BError( "Invalid array" );
12✔
1602
          auto sub_arr = ref.get()->impptr<ObjArray>();
83✔
1603
          if ( sub_arr->ref_arr.size() < static_cast<size_t>( sub_index ) )
83✔
1604
            return new BError( "Subindex to large" );
6✔
1605
        }
1606
        sort( ref_arr.begin(), ref_arr.end(),
14✔
1607
              [=]( const BObjectRef& x1, const BObjectRef& x2 ) -> bool
75✔
1608
              {
1609
                auto sub_arr1 = x1.get()->impptr<ObjArray>();
75✔
1610
                auto sub_arr2 = x2.get()->impptr<ObjArray>();
75✔
1611
                auto sub1 = sub_arr1->ref_arr[sub_index - 1];
75✔
1612
                auto sub2 = sub_arr2->ref_arr[sub_index - 1];
75✔
1613
                const BObject* b1 = sub1.get();
75✔
1614
                const BObject* b2 = sub2.get();
75✔
1615
                if ( b1 == nullptr || b2 == nullptr )
75✔
1616
                  return ( &x1 < &x2 );
6✔
1617
                return ( *b1 < *b2 );
69✔
1618
              } );
75✔
1619
        return new BLong( 1 );
14✔
1620
      }
1621
      return new BError( "array.sort(sub_index=0) takes at most one parameter." );
×
1622
    }
1623
    break;
×
1624
  case MTH_RANDOMENTRY:
×
1625
    if ( name_arr.empty() )
×
1626
    {
1627
      if ( ex.numParams() == 0 )
×
1628
      {
1629
        if ( !ref_arr.empty() )
×
1630
        {
1631
          const BObjectRef& ref =
1632
              ref_arr[Clib::random_int( static_cast<int>( ref_arr.size() ) - 1 )];
×
1633
          if ( ref.get() == nullptr )
×
1634
            return nullptr;
×
1635
          return ref.get()->impptr();
×
1636
        }
1637
      }
1638
      else
1639
        return new BError( "array.randomentry() doesn't take parameters." );
×
1640
    }
1641
    break;
×
1642
  case MTH_FILTER:
193✔
1643
    if ( name_arr.empty() )
193✔
1644
    {
1645
      if ( ex.numParams() < 1 )
193✔
1646
        return new BError( "Invalid parameter type" );
3✔
1647

1648
      BObjectImp* param0 = ex.getParamImp( 0, BObjectType::OTFuncRef );
190✔
1649

1650
      if ( !param0 )
190✔
1651
        return new BError( "Invalid parameter type" );
3✔
1652

1653
      // The filter callback allows optional arguments, so no need to check the
1654
      // number of arguments for the passed function reference. Arguments passed
1655
      // will be shrunk and expanded (with uninit) as needed.
1656

1657
      // If nothing to filter, return an empty array, since nothing to call the function with.
1658
      if ( ref_arr.empty() )
187✔
1659
        return new ObjArray();
×
1660

1661
      // Arguments for user function call.
1662
      // - the element
1663
      // - the index of the element
1664
      // - the array itself
1665
      BObjectRefVec args;
187✔
1666
      args.push_back( ref_arr.front() );
187✔
1667
      args.push_back( BObjectRef( new BLong( 1 ) ) );
187✔
1668
      args.emplace_back( this );
187✔
1669

1670
      // The ContinuationCallback receives three arguments:
1671
      //
1672
      // - `Executor&`
1673
      // - `BContinuation* continuation`: The continuation, with methods to handle
1674
      //   the continuation (call the function again; finalize)
1675
      // - `BObjectRef result`: The result of the user function call specified in
1676
      //   `makeContinuation`.
1677
      //
1678
      // We pass to the lambda a reference to the element in case the user
1679
      // function modifies ref_arr.
1680
      //
1681
      // Returns a `BObjectImp`:
1682
      // - Call the user function again by returning the same continuation via
1683
      //   `ex.withContinuation`.
1684
      // - Return something else (in this case, the filtered array) to provide
1685
      //   that value back to the script.
1686
      auto callback = [elementRef = args[0], processed = 1, thisArray = args[2],
187✔
1687
                       filteredRef = BObjectRef( new ObjArray ),
×
1688
                       initialSize = static_cast<int>( ref_arr.size() )](
187✔
1689
                          Executor& ex, BContinuation* continuation,
1690
                          BObjectRef result ) mutable -> BObjectImp*
89,686✔
1691
      {
1692
        auto filtered = filteredRef->impptr<ObjArray>();
22,561✔
1693

1694
        // Do something with result.
1695
        // If the result is true, add it to the filtered array.
1696
        if ( result->isTrue() )
22,561✔
1697
        {
1698
          filtered->ref_arr.emplace_back( elementRef->impptr() );
14,841✔
1699
        }
1700

1701
        // If thisArray was modified for some reason to no longer be an array,
1702
        // return the filtered array.
1703
        if ( !thisArray->isa( OTArray ) )
22,561✔
1704
          return filtered;
×
1705

1706
        const auto& ref_arr = thisArray->impptr<ObjArray>()->ref_arr;
22,561✔
1707

1708
        // If the processed index is the last element, return the filtered
1709
        // array. Also check if the processed index is greater than the initial
1710
        // size of the array, as the user function may have modified the array.
1711
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
22,561✔
1712
        {
1713
          return filtered;
187✔
1714
        }
1715
        // Otherwise, increment the processed index and call the function again.
1716

1717
        // Increment the processed counter.
1718
        ++processed;
22,374✔
1719

1720
        BObjectRefVec args;
22,374✔
1721
        args.push_back( ref_arr[processed - 1] );
22,374✔
1722
        args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
22,374✔
1723
        args.push_back( thisArray );
22,374✔
1724

1725
        elementRef = args[0];
22,374✔
1726

1727
        // Return this continuation with the new arguments.
1728
        return ex.withContinuation( continuation, std::move( args ) );
22,374✔
1729
      };
22,561✔
1730

1731
      // Create a new continuation for a user function call.
1732
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
374✔
1733
                                  std::move( args ) );
374✔
1734
    }
187✔
1735
    break;
×
1736

1737
  case MTH_MAP:
506✔
1738
    if ( name_arr.empty() )
506✔
1739
    {
1740
      if ( ex.numParams() < 1 )
497✔
1741
        return new BError( "Invalid parameter type" );
3✔
1742

1743
      BObjectImp* param0 = ex.getParamImp( 0, BObjectType::OTFuncRef );
494✔
1744

1745
      if ( !param0 )
494✔
1746
        return new BError( "Invalid parameter type" );
3✔
1747

1748
      if ( ref_arr.empty() )
491✔
1749
        return new ObjArray();
105✔
1750

1751
      // Arguments for user function call.
1752
      // - the element
1753
      // - the index of the element
1754
      // - the array itself
1755
      BObjectRefVec args;
386✔
1756
      args.push_back( ref_arr.front() );
386✔
1757
      args.push_back( BObjectRef( new BLong( 1 ) ) );
386✔
1758
      args.emplace_back( this );
386✔
1759

1760
      auto callback = [elementRef = args[0], processed = 1, thisArray = args[2],
386✔
1761
                       mappedRef = BObjectRef( new ObjArray ),
×
1762
                       initialSize = static_cast<int>( ref_arr.size() )](
386✔
1763
                          Executor& ex, BContinuation* continuation,
1764
                          BObjectRef result ) mutable -> BObjectImp*
8,202✔
1765
      {
1766
        auto mapped = mappedRef->impptr<ObjArray>();
2,340✔
1767

1768
        mapped->ref_arr.emplace_back( result->impptr() );
2,340✔
1769

1770
        if ( !thisArray->isa( OTArray ) )
2,340✔
1771
          return mapped;
×
1772

1773
        const auto& ref_arr = thisArray->impptr<ObjArray>()->ref_arr;
2,340✔
1774

1775
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
2,340✔
1776
        {
1777
          return mapped;
386✔
1778
        }
1779

1780
        // Increment the processed counter.
1781
        ++processed;
1,954✔
1782

1783
        BObjectRefVec args;
1,954✔
1784
        args.push_back( ref_arr[processed - 1] );
1,954✔
1785
        args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
1,954✔
1786
        args.push_back( thisArray );
1,954✔
1787

1788
        elementRef = args[0];
1,954✔
1789

1790
        return ex.withContinuation( continuation, std::move( args ) );
1,954✔
1791
      };
2,340✔
1792

1793
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
772✔
1794
                                  std::move( args ) );
772✔
1795
    }
386✔
1796
    break;
9✔
1797

1798
  case MTH_REDUCE:
81✔
1799
    if ( name_arr.empty() )
81✔
1800
    {
1801
      if ( ex.numParams() < 1 )
78✔
1802
        return new BError( "Invalid parameter type" );
3✔
1803

1804
      BObjectImp* param0 = ex.getParamImp( 0, BObjectType::OTFuncRef );
75✔
1805

1806
      if ( !param0 )
75✔
1807
        return new BError( "Invalid parameter type" );
3✔
1808

1809
      BObjectImp* accumulator;
1810
      int processed;
1811

1812
      // If an initial accumulator value was passed in, use it. Otherwise, use
1813
      // the first element of the array, erroring if the array is empty.
1814
      if ( ex.numParams() > 1 )
72✔
1815
      {
1816
        accumulator = ex.getParamImp( 1 );
63✔
1817
        processed = 1;
63✔
1818
      }
1819
      else if ( ref_arr.empty() )
9✔
1820
      {
1821
        return new BError( "Reduce of empty array with no initial value" );
3✔
1822
      }
1823
      else
1824
      {
1825
        accumulator = ref_arr[0]->impptr();
6✔
1826
        processed = 2;
6✔
1827
      }
1828

1829
      // Return the accumulator if there is no more to process, eg:
1830
      // {}.reduce(@{}, "accum") or {"accum"}.reduce(@{})
1831
      if ( processed > static_cast<int>( ref_arr.size() ) )
69✔
1832
      {
1833
        return accumulator;
6✔
1834
      }
1835

1836
      // Arguments for user function call.
1837
      // - accumulator
1838
      // - current value
1839
      // - current index
1840
      // - the array itself
1841
      BObjectRefVec args;
63✔
1842
      args.emplace_back( accumulator );
63✔
1843
      args.emplace_back( ref_arr[processed - 1] );
63✔
1844
      args.push_back( BObjectRef( new BLong( processed ) ) );
63✔
1845
      args.emplace_back( this );
63✔
1846

1847
      auto callback = [thisArray = args[3], processed = processed,
63✔
1848
                       initialSize = static_cast<int>( ref_arr.size() )](
63✔
1849
                          Executor& ex, BContinuation* continuation,
1850
                          BObjectRef result /* accumulator */ ) mutable -> BObjectImp*
7,993✔
1851
      {
1852
        if ( !thisArray->isa( OTArray ) )
1,649✔
1853
          return result->impptr();
×
1854

1855
        const auto& ref_arr = thisArray->impptr<ObjArray>()->ref_arr;
1,649✔
1856

1857
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
1,649✔
1858
        {
1859
          return result->impptr();
63✔
1860
        }
1861

1862
        ++processed;
1,586✔
1863

1864
        BObjectRefVec args;
1,586✔
1865
        args.push_back( result );
1,586✔
1866
        args.push_back( ref_arr[processed - 1] );
1,586✔
1867
        args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
1,586✔
1868
        args.push_back( thisArray );
1,586✔
1869

1870
        return ex.withContinuation( continuation, std::move( args ) );
1,586✔
1871
      };
1,649✔
1872

1873
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
126✔
1874
                                  std::move( args ) );
126✔
1875
    }
63✔
1876
    break;
3✔
1877

1878
  case MTH_FIND:
25✔
1879
    if ( name_arr.empty() )
25✔
1880
    {
1881
      if ( ex.numParams() < 1 )
25✔
1882
        return new BError( "Invalid parameter type" );
3✔
1883

1884
      BObjectImp* param0 = ex.getParamImp( 0, BObjectType::OTFuncRef );
22✔
1885

1886
      if ( !param0 )
22✔
1887
        return new BError( "Invalid parameter type" );
3✔
1888

1889
      if ( ref_arr.empty() )
19✔
1890
        return new ObjArray();
6✔
1891

1892
      // Arguments for user function call.
1893
      // - the element
1894
      // - the index of the element
1895
      // - the array itself
1896
      BObjectRefVec args;
13✔
1897
      args.push_back( ref_arr.front() );
13✔
1898
      args.push_back( BObjectRef( new BLong( 1 ) ) );
13✔
1899
      args.emplace_back( this );
13✔
1900

1901
      auto callback = [elementRef = args[0], processed = 1, thisArray = args[2],
13✔
1902
                       initialSize = static_cast<int>( ref_arr.size() )](
13✔
1903
                          Executor& ex, BContinuation* continuation,
1904
                          BObjectRef result ) mutable -> BObjectImp*
115✔
1905
      {
1906
        if ( result->isTrue() )
41✔
1907
        {
1908
          return elementRef->impptr();
10✔
1909
        }
1910

1911
        if ( !thisArray->isa( OTArray ) )
31✔
1912
          return UninitObject::create();
×
1913

1914
        const auto& ref_arr = thisArray->impptr<ObjArray>()->ref_arr;
31✔
1915

1916
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
31✔
1917
        {
1918
          return UninitObject::create();
3✔
1919
        }
1920

1921
        ++processed;
28✔
1922

1923
        BObjectRefVec args;
28✔
1924
        args.push_back( ref_arr[processed - 1] );
28✔
1925
        args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
28✔
1926
        args.push_back( thisArray );
28✔
1927

1928
        elementRef = args[0];
28✔
1929

1930
        return ex.withContinuation( continuation, std::move( args ) );
28✔
1931
      };
41✔
1932

1933
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
26✔
1934
                                  std::move( args ) );
26✔
1935
    }
13✔
1936
    break;
×
1937

1938
  case MTH_FINDINDEX:
132✔
1939
    if ( name_arr.empty() )
132✔
1940
    {
1941
      if ( ex.numParams() < 1 )
129✔
1942
        return new BError( "Invalid parameter type" );
3✔
1943

1944
      BObjectImp* param0 = ex.getParamImp( 0, BObjectType::OTFuncRef );
126✔
1945

1946
      if ( !param0 )
126✔
1947
        return new BError( "Invalid parameter type" );
3✔
1948

1949
      if ( ref_arr.empty() )
123✔
1950
        return new BLong( 0 );
3✔
1951

1952
      // Arguments for user function call.
1953
      // - the element
1954
      // - the index of the element
1955
      // - the array itself
1956
      BObjectRefVec args;
120✔
1957
      args.push_back( ref_arr.front() );
120✔
1958
      args.push_back( BObjectRef( new BLong( 1 ) ) );
120✔
1959
      args.emplace_back( this );
120✔
1960

1961
      auto callback =
120✔
1962
          [processed = 1, thisArray = args[2], initialSize = static_cast<int>( ref_arr.size() )](
120✔
1963
              Executor& ex, BContinuation* continuation, BObjectRef result ) mutable -> BObjectImp*
36,692✔
1964
      {
1965
        if ( result->isTrue() )
9,263✔
1966
        {
1967
          return new BLong( processed );
117✔
1968
        }
1969

1970
        if ( !thisArray->isa( OTArray ) )
9,146✔
1971
          return new BLong( 0 );
×
1972

1973
        const auto& ref_arr = thisArray->impptr<ObjArray>()->ref_arr;
9,146✔
1974

1975
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
9,146✔
1976
        {
1977
          return new BLong( 0 );
3✔
1978
        }
1979

1980
        ++processed;
9,143✔
1981

1982
        BObjectRefVec args;
9,143✔
1983
        args.push_back( ref_arr[processed - 1] );
9,143✔
1984
        args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
9,143✔
1985
        args.push_back( thisArray );
9,143✔
1986

1987
        return ex.withContinuation( continuation, std::move( args ) );
9,143✔
1988
      };
9,263✔
1989

1990
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
240✔
1991
                                  std::move( args ) );
240✔
1992
    }
120✔
1993
    break;
3✔
1994

1995
  case MTH_CYCLE:
×
1996
    if ( name_arr.empty() )
×
1997
    {
1998
      int shift_by;
1999

2000
      if ( ex.numParams() > 0 )
×
2001
      {
2002
        if ( !ex.getParam( 0, shift_by ) )
×
2003
          return new BError( "Invalid parameter type" );
×
2004
        if ( shift_by == 0 )
×
2005
          return new BLong( 0 );
×
2006
      }
2007
      else
2008
        shift_by = 1;
×
2009

2010
      if ( ref_arr.empty() || std::abs( shift_by ) > (int)ref_arr.size() )
×
2011
        return new BLong( 0 );
×
2012

2013
      if ( shift_by > 0 )
×
2014
        std::rotate( ref_arr.begin(), ref_arr.end() - shift_by, ref_arr.end() );
×
2015
      else
2016
        std::rotate( ref_arr.begin(), ref_arr.begin() - shift_by, ref_arr.end() );
×
2017

2018
      return new BLong( 1 );
×
2019
    }
2020
    break;
×
2021

2022
  case MTH_SORTEDINSERT:
18✔
2023
  {
2024
    if ( !name_arr.empty() )
18✔
2025
      break;
×
2026
    if ( ex.numParams() == 0 )
18✔
2027
      return new BError(
2028
          "array.sorted_insert(obj, sub_index:=0, reverse:=0) takes at least one parameter." );
18✔
2029
    BObjectImp* imp = ex.getParamImp( 0 );
18✔
2030
    if ( !imp )
18✔
2031
      return new BError( "Invalid parameter type" );
×
2032
    bool reverse = false;
18✔
2033
    int sub_index = 0;
18✔
2034
    if ( ex.numParams() >= 2 )
18✔
2035
    {
2036
      if ( !ex.getParam( 1, sub_index ) )
15✔
2037
        return new BError( "Invalid parameter type" );
×
2038
      if ( sub_index < 0 )
15✔
2039
        return new BError( "Invalid sub_index value" );
×
2040
    }
2041
    if ( ex.numParams() >= 3 )
18✔
2042
    {
2043
      int reverseparam;
2044
      if ( !ex.getParam( 2, reverseparam ) )
9✔
2045
        return new BError( "Invalid parameter type" );
×
2046
      reverse = reverseparam != 0;
9✔
2047
    }
2048
    BObjectRef item( new BObject( imp->copy() ) );
18✔
2049
    if ( !sub_index )
18✔
2050
    {
2051
      if ( reverse )
9✔
2052
      {
2053
        ref_arr.insert( std::lower_bound( ref_arr.begin(), ref_arr.end(), item,
3✔
2054
                                          []( const BObjectRef& x1, const BObjectRef& x2 ) -> bool
9✔
2055
                                          {
2056
                                            const BObject* b1 = x1.get();
9✔
2057
                                            const BObject* b2 = x2.get();
9✔
2058
                                            if ( b1 == nullptr || b2 == nullptr )
9✔
2059
                                              return ( &x1 > &x2 );
×
2060
                                            const BObject& r1 = *b1;
9✔
2061
                                            const BObject& r2 = *b2;
9✔
2062
                                            return ( r1 > r2 );
9✔
2063
                                          } ),
2064
                        item );
2065
      }
2066
      else
2067
      {
2068
        ref_arr.insert( std::upper_bound( ref_arr.begin(), ref_arr.end(), item, objref_cmp() ),
6✔
2069
                        item );
2070
      }
2071
    }
2072
    else
2073
    {
2074
      auto cmp_func = [=]( const BObjectRef& x1, const BObjectRef& x2 ) -> bool
21✔
2075
      {
2076
        if ( x1.get() == nullptr || !x1.get()->isa( OTArray ) )
21✔
2077
          return false;
×
2078
        if ( x2.get() == nullptr || !x2.get()->isa( OTArray ) )
21✔
2079
          return false;
×
2080
        auto sub_arr1 = x1.get()->impptr<ObjArray>();
21✔
2081
        auto sub_arr2 = x2.get()->impptr<ObjArray>();
21✔
2082
        if ( sub_arr1->ref_arr.size() < static_cast<size_t>( sub_index ) )
21✔
2083
          return false;
×
2084
        if ( sub_arr2->ref_arr.size() < static_cast<size_t>( sub_index ) )
21✔
2085
          return false;
×
2086
        auto sub1 = sub_arr1->ref_arr[sub_index - 1];
21✔
2087
        auto sub2 = sub_arr2->ref_arr[sub_index - 1];
21✔
2088
        const BObject* b1 = sub1.get();
21✔
2089
        const BObject* b2 = sub2.get();
21✔
2090
        if ( !reverse )
21✔
2091
        {
2092
          if ( b1 == nullptr || b2 == nullptr )
15✔
2093
            return ( &x1 < &x2 );
×
2094
          return ( *b1 < *b2 );
15✔
2095
        }
2096

2097
        if ( b1 == nullptr || b2 == nullptr )
6✔
2098
          return ( &x1 > &x2 );
×
2099
        return ( *b1 > *b2 );
6✔
2100
      };
21✔
2101
      if ( reverse )
9✔
2102
      {
2103
        ref_arr.insert( std::lower_bound( ref_arr.begin(), ref_arr.end(), item, cmp_func ), item );
3✔
2104
      }
2105
      else
2106
      {
2107
        ref_arr.insert( std::upper_bound( ref_arr.begin(), ref_arr.end(), item, cmp_func ), item );
6✔
2108
      }
2109
    }
2110
    return new BLong( 1 );
18✔
2111
    break;
2112
  }
18✔
2113
  default:
×
2114
    return nullptr;
×
2115
  }
2116
  return nullptr;
45✔
2117
}
2118

2119
BObjectImp* ObjArray::call_method( const char* methodname, Executor& ex )
3✔
2120
{
2121
  ObjMethod* objmethod = getKnownObjMethod( methodname );
3✔
2122
  if ( objmethod != nullptr )
3✔
2123
    return this->call_method_id( objmethod->id, ex );
×
2124
  return nullptr;
3✔
2125
}
2126

2127
void ObjArray::packonto( std::ostream& os ) const
41✔
2128
{
2129
  os << "a" << ref_arr.size() << ":";
41✔
2130
  for ( const auto& elem : ref_arr )
173✔
2131
  {
2132
    if ( elem.get() )
132✔
2133
    {
2134
      BObject* bo = elem.get();
132✔
2135
      bo->impptr()->packonto( os );
132✔
2136
    }
2137
    else
2138
    {
2139
      os << "x";
×
2140
    }
2141
  }
2142
}
41✔
2143

2144
BObjectImp* ObjArray::unpack( std::istream& is )
19✔
2145
{
2146
  unsigned arrsize;
2147
  char colon;
2148
  if ( !( is >> arrsize >> colon ) )
19✔
2149
  {
2150
    return new BError( "Unable to unpack array elemcount" );
×
2151
  }
2152
  if ( (int)arrsize < 0 )
19✔
2153
  {
2154
    return new BError( "Unable to unpack array elemcount. Invalid length!" );
×
2155
  }
2156
  if ( colon != ':' )
19✔
2157
  {
2158
    return new BError( "Unable to unpack array elemcount. Bad format. Colon not found!" );
×
2159
  }
2160
  std::unique_ptr<ObjArray> arr( new ObjArray );
19✔
2161
  arr->ref_arr.resize( arrsize );
19✔
2162
  for ( unsigned i = 0; i < arrsize; ++i )
93✔
2163
  {
2164
    BObjectImp* imp = BObjectImp::unpack( is );
74✔
2165
    if ( imp != nullptr && !imp->isa( OTUninit ) )
74✔
2166
    {
2167
      arr->ref_arr[i].set( new BObject( imp ) );
74✔
2168
    }
2169
  }
2170
  return arr.release();
19✔
2171
}
19✔
2172

2173
BApplicPtr::BApplicPtr( const BApplicObjType* pointer_type, void* ptr )
×
2174
    : BObjectImp( OTApplicPtr ), ptr_( ptr ), pointer_type_( pointer_type )
×
2175
{
2176
}
×
2177

2178
BObjectImp* BApplicPtr::copy() const
×
2179
{
2180
  return new BApplicPtr( pointer_type_, ptr_ );
×
2181
}
2182

2183
size_t BApplicPtr::sizeEstimate() const
×
2184
{
2185
  return sizeof( BApplicPtr );
×
2186
}
2187

2188
const BApplicObjType* BApplicPtr::pointer_type() const
×
2189
{
2190
  return pointer_type_;
×
2191
}
2192

2193
void* BApplicPtr::ptr() const
×
2194
{
2195
  return ptr_;
×
2196
}
2197

2198
std::string BApplicPtr::getStringRep() const
×
2199
{
2200
  return "<appptr>";
×
2201
}
2202

2203

2204
void BApplicPtr::printOn( std::ostream& os ) const
×
2205
{
2206
  os << "<appptr>";
×
2207
}
×
2208

2209
std::string BApplicObjBase::getStringRep() const
191✔
2210
{
2211
  return std::string( "<appobj:" ) + typeOf() + ">";
382✔
2212
}
2213

2214
void BApplicObjBase::printOn( std::ostream& os ) const
×
2215
{
2216
  os << getStringRep();
×
2217
}
×
2218

2219
#if BOBJECTIMP_DEBUG
2220
BBoolean::BBoolean( bool bval ) : BObjectImp( OTBoolean ), bval_( bval ) {}
2221
BBoolean::BBoolean( const BBoolean& B ) : BBoolean( B.bval_ ) {}
2222
#endif
2223

2224
BObjectImp* BBoolean::unpack( std::istream& is )
12✔
2225
{
2226
  int lv;
2227
  if ( is >> lv )
12✔
2228
  {
2229
    return new BBoolean( lv != 0 );
12✔
2230
  }
2231

2232
  return new BError( "Error extracting Boolean value" );
×
2233
}
2234

2235
void BBoolean::packonto( std::ostream& os ) const
×
2236
{
2237
  os << "b" << ( bval_ ? 1 : 0 );
×
2238
}
×
2239

2240
std::string BBoolean::pack() const
24✔
2241
{
2242
  OSTRINGSTREAM os;
24✔
2243
  os << "b" << ( bval_ ? 1 : 0 );
24✔
2244
  return OSTRINGSTREAM_STR( os );
48✔
2245
}
24✔
2246

2247
BObjectImp* BBoolean::copy() const
240✔
2248
{
2249
  return new BBoolean( *this );
240✔
2250
}
2251

2252
size_t BBoolean::sizeEstimate() const
56✔
2253
{
2254
  return sizeof( BBoolean );
56✔
2255
}
2256

2257
bool BBoolean::isTrue() const
581✔
2258
{
2259
  return bval_;
581✔
2260
}
2261

2262
bool BBoolean::operator==( const BObjectImp& objimp ) const
42✔
2263
{
2264
  return bval_ == objimp.isTrue();
42✔
2265
}
2266

2267
std::string BBoolean::getStringRep() const
60✔
2268
{
2269
  return bval_ ? "true" : "false";
60✔
2270
}
2271

2272
BFunctionRef::BFunctionRef( ref_ptr<EScriptProgram> program, unsigned function_reference_index,
3,190✔
2273
                            std::shared_ptr<ValueStackCont> globals, ValueStackCont&& captures )
3,190✔
2274
    : BObjectImp( OTFuncRef ),
2275
      prog_( std::move( program ) ),
3,190✔
2276
      function_reference_index_( function_reference_index ),
3,190✔
2277
      globals( std::move( globals ) ),
3,190✔
2278
      captures( std::move( captures ) )
6,380✔
2279
{
2280
  passert( function_reference_index_ < prog_->function_references.size() );
3,190✔
2281
}
3,190✔
2282

2283
BFunctionRef::BFunctionRef( const BFunctionRef& B )
784✔
2284
    : BFunctionRef( B.prog_, B.function_reference_index_, B.globals, ValueStackCont( B.captures ) )
784✔
2285
{
2286
}
784✔
2287

2288
BObjectImp* BFunctionRef::copy() const
784✔
2289
{
2290
  return new BFunctionRef( *this );
784✔
2291
}
2292

2293
size_t BFunctionRef::sizeEstimate() const
99✔
2294
{
2295
  return sizeof( BFunctionRef ) + Clib::memsize( captures );
99✔
2296
}
2297

2298
bool BFunctionRef::isTrue() const
3✔
2299
{
2300
  return false;
3✔
2301
}
2302

2303
bool BFunctionRef::operator==( const BObjectImp& /*objimp*/ ) const
×
2304
{
2305
  return false;
×
2306
}
2307

2308
BObjectImp* BFunctionRef::selfIsObjImp( const BObjectImp& other ) const
94✔
2309
{
2310
  auto classinstref = dynamic_cast<const BClassInstanceRef*>( &other );
94✔
2311
  if ( !classinstref )
94✔
2312
    return new BLong( 0 );
×
2313

2314
  auto classinst = classinstref->instance();
94✔
2315

2316
  // Class index could be maxint if the function reference is not a class
2317
  // method.
2318
  if ( class_index() >= prog_->class_descriptors.size() )
94✔
2319
    return new BLong( 0 );
×
2320

2321
  const auto& my_constructors = prog_->class_descriptors.at( class_index() ).constructors;
94✔
2322
  passert( !my_constructors.empty() );
94✔
2323
  const auto& my_descriptor = my_constructors.front();
94✔
2324

2325
  const auto& other_descriptors =
2326
      classinst->prog()->class_descriptors.at( classinst->index() ).constructors;
94✔
2327

2328
  // An optimization for same program: since strings are never duplicated inside
2329
  // the data section, we can just check for offset equality.
2330
  if ( prog_ == classinst->prog() )
94✔
2331
  {
2332
    for ( const auto& other_descriptor : other_descriptors )
195✔
2333
    {
2334
      if ( my_descriptor.type_tag_offset == other_descriptor.type_tag_offset )
180✔
2335
        return new BLong( 1 );
54✔
2336
    }
2337
  }
2338
  // For different programs, we must check for string equality.
2339
  else
2340
  {
2341
    auto type_tag = prog_->symbols.array() + my_descriptor.type_tag_offset;
25✔
2342
    for ( const auto& other_descriptor : other_descriptors )
63✔
2343
    {
2344
      auto other_type_tag = classinst->prog()->symbols.array() + other_descriptor.type_tag_offset;
51✔
2345
      if ( strcmp( type_tag, other_type_tag ) == 0 )
51✔
2346
        return new BLong( 1 );
13✔
2347
    }
2348
  }
2349

2350
  return new BLong( 0 );
27✔
2351
}
2352

2353
std::string BFunctionRef::getStringRep() const
141✔
2354
{
2355
  return "FunctionObject";
141✔
2356
}
2357

2358
BObjectImp* BFunctionRef::call_method( const char* methodname, Executor& ex )
21✔
2359
{
2360
  ObjMethod* objmethod = getKnownObjMethod( methodname );
21✔
2361
  if ( objmethod != nullptr )
21✔
2362
    return call_method_id( objmethod->id, ex );
21✔
2363
  return nullptr;
×
2364
}
2365

2366
bool BFunctionRef::validCall( const int id, Executor& ex, Instruction* inst ) const
38,166✔
2367
{
2368
  auto passed_args = static_cast<int>( ex.numParams() );
38,166✔
2369

2370
  auto [expected_min_args, expected_max_args] = expected_args();
38,166✔
2371

2372
  if ( id != MTH_CALL && id != MTH_NEW && id != MTH_CALL_METHOD )
38,166✔
2373
    return false;
×
2374

2375
  if ( id == MTH_NEW && !constructor() )
38,166✔
2376
    return false;
27✔
2377

2378
  if ( passed_args < expected_min_args || ( passed_args > expected_max_args && !variadic() ) )
38,139✔
2379
    return false;
99✔
2380

2381
  inst->func = &Executor::ins_nop;
38,040✔
2382

2383
  if ( passed_args >= expected_max_args )
38,040✔
2384
  {
2385
    inst->token.lval = pc();
37,835✔
2386
  }
2387
  else
2388
  {
2389
    auto default_parameter_address_index = expected_max_args - passed_args - 1;
205✔
2390
    passert( default_parameter_address_index >= 0 &&
205✔
2391
             default_parameter_address_index <
2392
                 static_cast<int>( default_parameter_addresses().size() ) );
2393
    inst->token.lval = default_parameter_addresses().at( default_parameter_address_index );
205✔
2394
  }
2395

2396
  return true;
38,040✔
2397
}
2398

2399
bool BFunctionRef::validCall( const char* methodname, Executor& ex, Instruction* inst ) const
×
2400
{
2401
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
2402
  if ( objmethod == nullptr )
×
2403
    return false;
×
2404
  return validCall( objmethod->id, ex, inst );
×
2405
}
2406

2407
int BFunctionRef::numParams() const
111,385✔
2408
{
2409
  return prog_->function_references[function_reference_index_].parameter_count;
111,385✔
2410
}
2411

2412
unsigned BFunctionRef::pc() const
37,835✔
2413
{
2414
  return prog_->function_references[function_reference_index_].address;
37,835✔
2415
}
2416

2417
bool BFunctionRef::variadic() const
74,525✔
2418
{
2419
  return prog_->function_references[function_reference_index_].is_variadic;
74,525✔
2420
}
2421

2422
ref_ptr<EScriptProgram> BFunctionRef::prog() const
38,155✔
2423
{
2424
  return prog_;
38,155✔
2425
}
2426

2427
unsigned BFunctionRef::class_index() const
269✔
2428
{
2429
  return prog_->function_references[function_reference_index_].class_index;
269✔
2430
}
2431

2432
bool BFunctionRef::constructor() const
270✔
2433
{
2434
  return prog_->function_references[function_reference_index_].is_constructor;
270✔
2435
}
2436

2437
bool BFunctionRef::class_method() const
631✔
2438
{
2439
  return prog_->function_references[function_reference_index_].class_index <
631✔
2440
         std::numeric_limits<unsigned>::max();
631✔
2441
}
2442

2443
const std::vector<unsigned>& BFunctionRef::default_parameter_addresses() const
76,940✔
2444
{
2445
  return prog_->function_references[function_reference_index_].default_parameter_addresses;
76,940✔
2446
}
2447

2448
int BFunctionRef::default_parameter_count() const
76,530✔
2449
{
2450
  return static_cast<int>( default_parameter_addresses().size() );
76,530✔
2451
}
2452

2453
std::pair<int, int> BFunctionRef::expected_args() const
38,265✔
2454
{
2455
  auto expected_min_args = numParams() - default_parameter_count();  // remove default parameters
38,265✔
2456

2457
  return { expected_min_args, expected_min_args + default_parameter_count() };
38,265✔
2458
}
2459

2460
BObjectImp* BFunctionRef::call_method_id( const int id, Executor& ex, bool /*forcebuiltin*/ )
126✔
2461
{
2462
  bool adjust_for_this = false;
126✔
2463

2464
  // These are only entered if `ins_call_method_id` did _not_ do the call jump.
2465
  switch ( id )
126✔
2466
  {
2467
  case MTH_NEW:
54✔
2468
    if ( !constructor() )
54✔
2469
      return new BError( "Function is not a constructor" );
27✔
2470
    // intentional fallthrough
2471
  case MTH_CALL_METHOD:
2472
    adjust_for_this = true;
48✔
2473
    // intentional fallthrough
2474
  case MTH_CALL:
99✔
2475
  {
2476
    auto [expected_min_args, expected_max_args] = expected_args();
99✔
2477
    auto param_count = ex.numParams();
99✔
2478

2479
    if ( adjust_for_this )
99✔
2480
    {
2481
      --expected_min_args;
48✔
2482
      --expected_max_args;
48✔
2483
      --param_count;
48✔
2484
    }
2485

2486
    auto expected_arg_string = variadic() ? fmt::format( "{}+", expected_min_args )
99✔
2487
                               : ( expected_min_args == expected_max_args )
63✔
2488
                                   ? std::to_string( expected_min_args )
63✔
2489
                                   : fmt::format( "{}-{}", expected_min_args, expected_max_args );
159✔
2490

2491
    return new BError( fmt::format( "Invalid argument count: expected {}, got {}",
×
2492
                                    expected_arg_string, param_count ) );
198✔
2493
  }
99✔
2494
  default:
×
2495
    return nullptr;
×
2496
  }
2497
}
2498

2499
BSpread::BSpread( BObjectRef obj ) : BObjectImp( OTSpread ), object( std::move( obj ) ) {}
2,101✔
2500

2501
BSpread::BSpread( const BSpread& B ) : BObjectImp( OTSpread ), object( B.object ) {}
×
2502

2503
size_t BSpread::sizeEstimate() const
×
2504
{
2505
  return sizeof( BSpread ) + object.sizeEstimate();
×
2506
}
2507

2508
BObjectImp* BSpread::copy() const
×
2509
{
2510
  return new BSpread( *this );
×
2511
}
2512

2513
bool BSpread::isTrue() const
×
2514
{
2515
  return object->isTrue();
×
2516
}
2517

2518
std::string BSpread::getStringRep() const
×
2519
{
2520
  return "Spread";
×
2521
}
2522

2523
BSpecialUserFuncJump BSpecialUserFuncJump::imp_special_userjmp{};
2524
BSpecialUserFuncJump::BSpecialUserFuncJump() : BObjectImp( OTSpecialUserFuncJump ) {}
4,944✔
2525
size_t BSpecialUserFuncJump::sizeEstimate() const
×
2526
{
2527
  return sizeof( BSpecialUserFuncJump );
×
2528
};
2529
std::string BSpecialUserFuncJump::getStringRep() const
×
2530
{
2531
  return "BSpecialUserFuncJump";
×
2532
};
2533
BObjectImp* BSpecialUserFuncJump::copy() const
×
2534
{
2535
  return get();
×
2536
};
2537
BSpecialUserFuncJump* BSpecialUserFuncJump::get()
610✔
2538
{
2539
  return &imp_special_userjmp;
610✔
2540
}
2541

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