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

polserver / polserver / 24035539233

06 Apr 2026 02:21PM UTC coverage: 60.76% (+0.06%) from 60.696%
24035539233

push

github

web-flow
using fmt instead of ostringstream (#873)

* using fmt instead of ostringstream

misc cleanup

* missing external libs for clang tidy check

* added test for cprops ignore while stacking
door descriptor

* use contains instead of count, removed disabled ancient code

* pack/packonto simplification/speedup

instead of using ostream and convert to string, use format and directly
a string

90 of 141 new or added lines in 17 files covered. (63.83%)

17 existing lines in 10 files now uncovered.

44503 of 73244 relevant lines covered (60.76%)

514255.82 hits per line

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

75.56
/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 <fmt/compile.h>
13
#include <istream>
14
#include <iterator>
15
#include <limits>
16
#include <stddef.h>
17
#include <string>
18

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

39
#if BOBJECTIMP_DEBUG
40
#include "escriptv.h"
41
#include <unordered_map>
42
#endif
43

44

45
namespace Pol::Bscript
46
{
47
using namespace fmt::literals;
48

49
Clib::fixed_allocator<sizeof( BObject ), 256> bobject_alloc;
50
Clib::fixed_allocator<sizeof( UninitObject ), 256> uninit_alloc;
51
Clib::fixed_allocator<sizeof( BLong ), 256> blong_alloc;
52
Clib::fixed_allocator<sizeof( Double ), 256> double_alloc;
53

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

67

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

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

125
BObjectImp* BObjectImp::unpack( const char* pstr )
179✔
126
{
127
  ISTRINGSTREAM is( pstr );
179✔
128
  return unpack( is );
358✔
129
}
179✔
130

131
BObject* BObject::clone() const
486✔
132
{
133
  return new BObject( objimp->copy() );
486✔
134
}
135

136
bool BObject::operator!=( const BObject& obj ) const
27,340✔
137
{
138
  return *objimp != *( obj.objimp );
27,340✔
139
}
140
bool BObject::operator==( const BObject& obj ) const
8,110✔
141
{
142
  return *objimp == *( obj.objimp );
8,110✔
143
}
144
bool BObject::operator<( const BObject& obj ) const
7,482✔
145
{
146
  return *objimp < *( obj.objimp );
7,482✔
147
}
148
bool BObject::operator<=( const BObject& obj ) const
803✔
149
{
150
  return *objimp <= *( obj.objimp );
803✔
151
}
152
bool BObject::operator>( const BObject& obj ) const
6,042✔
153
{
154
  return *objimp > *( obj.objimp );
6,042✔
155
}
156
bool BObject::operator>=( const BObject& obj ) const
418✔
157
{
158
  return *objimp >= *( obj.objimp );
418✔
159
}
160

161
////////////////////// BObjectImp //////////////////////
162
#if BOBJECTIMP_DEBUG
163
typedef std::unordered_map<unsigned int, BObjectImp*> bobjectimps;
164

165

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

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

195
BObjectImp::~BObjectImp()
196
{
197
  Clib::SpinLockGuard lock( bobjectimp_lock );
198
  bobjectimp_instances.erase( instance_ );
199
  --eobject_imp_count;
200
}
201
#endif
202

203
std::string BObjectImp::pack() const
178✔
204
{
205
  std::string str;
178✔
206
  packonto( str );
178✔
207
  return str;
178✔
UNCOV
208
}
×
209

210
void BObjectImp::packonto( std::string& str ) const
6✔
211
{
212
  str += "u";
6✔
213
}
6✔
214

215
std::string BObjectImp::getFormattedStringRep() const
1,087✔
216
{
217
  return getStringRep();
1,087✔
218
}
219

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

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

262

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

868

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

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

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

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

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

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

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

910
void BObjectImp::selfPlusPlus() {}
18✔
911

912
void BObjectImp::selfMinusMinus() {}
9✔
913

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

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

927
BObjectImp* BObjectImp::call_method( const char* methodname, Executor& /*ex*/ )
25✔
928
{
929
  return new BError( std::string( "Method '" ) + methodname + "' not found" );
25✔
930
}
931
BObjectImp* BObjectImp::call_method_id( const int id, Executor& /*ex*/, bool /*forcebuiltin*/ )
3✔
932
{
933
  return new BError( fmt::format( "Method id '{}' ({}) not found", id, getObjMethod( id )->code ) );
6✔
934
}
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,750✔
944
{
945
  ObjMember* memb = getObjMember( id );
7,750✔
946

947
  return get_member( memb->code );
7,750✔
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,415✔
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,829✔
1013

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

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

1022
void ObjArray::deepcopy()
4,967✔
1023
{
1024
  for ( auto& elem : ref_arr )
53,694✔
1025
  {
1026
    if ( elem.get() )
48,727✔
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,715✔
1036
      elem.set( new BObject( bo->impptr()->copy() ) );
48,715✔
1037
    }
1038
  }
1039
}
4,967✔
1040

1041
BObjectImp* ObjArray::copy() const
4,911✔
1042
{
1043
  auto nobj = new ObjArray( *this );
4,911✔
1044
  return nobj;
4,911✔
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
115✔
1072
{
1073
  if ( !imp.isa( OTArray ) )
115✔
1074
    return false;
27✔
1075

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

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

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

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

1101
    return false;
×
1102
  }
1103
  return true;
82✔
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,172✔
1149
{
1150
  ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
9,172✔
1151
}
9,172✔
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
  {
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
          */
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 )
3,079✔
1325
{
1326
  const BObjectImp& right = rightobj.impref();
3,079✔
1327
  if ( right.isa( OTLong ) )  // vector
3,079✔
1328
  {
1329
    BLong& lng = (BLong&)right;
3,079✔
1330

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

1339
    BObjectRef& ref = ref_arr[index - 1];
3,058✔
1340
    if ( ref.get() == nullptr )
3,058✔
1341
      ref.set( new BObject( UninitObject::create() ) );
×
1342
    return ref;
3,058✔
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,278✔
1401
{
1402
  ref_arr.push_back( BObjectRef( new BObject( imp ) ) );
44,278✔
1403
}
44,278✔
1404

1405
std::string ObjArray::getStringRep() const
3,383✔
1406
{
1407
  std::string rep{ "{ " };
3,383✔
1408
  bool any = false;
3,383✔
1409
  for ( const auto& elem : ref_arr )
17,591✔
1410
  {
1411
    if ( any )
14,208✔
1412
      rep += ", ";
11,688✔
1413
    else
1414
      any = true;
2,520✔
1415

1416
    BObject* bo = elem.get();
14,208✔
1417

1418
    if ( bo != nullptr )
14,208✔
1419
      rep += bo->impptr()->getStringRep();
14,166✔
1420
  }
1421
  rep += " }";
3,383✔
1422

1423
  return rep;
3,383✔
UNCOV
1424
}
×
1425

1426
long ObjArray::contains( const BObjectImp& imp ) const
886✔
1427
{
1428
  for ( auto itr = ref_arr.begin(), end = ref_arr.end(); itr != end; ++itr )
1,713✔
1429
  {
1430
    if ( itr->get() )
1,119✔
1431
    {
1432
      BObject* bo = ( itr->get() );
1,119✔
1433
      if ( bo == nullptr )
1,119✔
1434
      {
1435
        INFO_PRINTLN( "{} - '{} in array{{}}' check. Invalid data at index {}",
×
1436
                      Clib::scripts_thread_script, imp, ( itr - ref_arr.begin() ) + 1 );
×
1437
        continue;
×
1438
      }
1439
      if ( *( bo->impptr() ) == imp )
1,119✔
1440
      {
1441
        return ( static_cast<long>( ( itr - ref_arr.begin() ) + 1 ) );
292✔
1442
      }
1443
    }
1444
  }
1445
  return 0;
594✔
1446
}
1447

1448
class objref_cmp
1449
{
1450
public:
1451
  bool operator()( const BObjectRef& x1, const BObjectRef& x2 ) const
498✔
1452
  {
1453
    const BObject* b1 = x1.get();
498✔
1454
    const BObject* b2 = x2.get();
498✔
1455
    if ( b1 == nullptr || b2 == nullptr )
498✔
1456
      return ( &x1 < &x2 );
×
1457

1458
    const BObject& r1 = *b1;
498✔
1459
    const BObject& r2 = *b2;
498✔
1460
    return ( r1 < r2 );
498✔
1461
  }
1462
};
1463

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

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

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

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

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

1560
          return new BLong( 1 );
7,942✔
1561
        }
1562

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

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

1646
      if ( !param0 )
190✔
1647
        return new BError( "Invalid parameter type" );
3✔
1648

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

1653
      // If nothing to filter, return an empty array, since nothing to call the function with.
1654
      if ( ref_arr.empty() )
187✔
1655
        return new ObjArray();
×
1656

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

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

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

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

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

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

1713
        // Increment the processed counter.
1714
        ++processed;
22,374✔
1715

1716
        BObjectRefVec args;
22,374✔
1717
        args.push_back( ref_arr[processed - 1] );
22,374✔
1718
        args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
22,374✔
1719
        args.push_back( thisArray );
22,374✔
1720

1721
        elementRef = args[0];
22,374✔
1722

1723
        // Return this continuation with the new arguments.
1724
        return ex.withContinuation( continuation, std::move( args ) );
22,374✔
1725
      };
22,561✔
1726

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

1733
  case MTH_MAP:
506✔
1734
    if ( name_arr.empty() )
506✔
1735
    {
1736
      if ( ex.numParams() < 1 )
497✔
1737
        return new BError( "Invalid parameter type" );
3✔
1738

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

1741
      if ( !param0 )
494✔
1742
        return new BError( "Invalid parameter type" );
3✔
1743

1744
      if ( ref_arr.empty() )
491✔
1745
        return new ObjArray();
105✔
1746

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

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

1764
        mapped->ref_arr.emplace_back( result->impptr() );
2,340✔
1765

1766
        if ( !thisArray->isa( OTArray ) )
2,340✔
1767
          return mapped;
×
1768

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

1771
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
2,340✔
1772
        {
1773
          return mapped;
386✔
1774
        }
1775

1776
        // Increment the processed counter.
1777
        ++processed;
1,954✔
1778

1779
        BObjectRefVec args;
1,954✔
1780
        args.push_back( ref_arr[processed - 1] );
1,954✔
1781
        args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
1,954✔
1782
        args.push_back( thisArray );
1,954✔
1783

1784
        elementRef = args[0];
1,954✔
1785

1786
        return ex.withContinuation( continuation, std::move( args ) );
1,954✔
1787
      };
2,340✔
1788

1789
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
772✔
1790
                                  std::move( args ) );
772✔
1791
    }
386✔
1792
    break;
9✔
1793

1794
  case MTH_REDUCE:
81✔
1795
    if ( name_arr.empty() )
81✔
1796
    {
1797
      if ( ex.numParams() < 1 )
78✔
1798
        return new BError( "Invalid parameter type" );
3✔
1799

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

1802
      if ( !param0 )
75✔
1803
        return new BError( "Invalid parameter type" );
3✔
1804

1805
      BObjectImp* accumulator;
1806
      int processed;
1807

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

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

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

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

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

1853
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
1,649✔
1854
        {
1855
          return result->impptr();
63✔
1856
        }
1857

1858
        ++processed;
1,586✔
1859

1860
        BObjectRefVec args;
1,586✔
1861
        args.push_back( result );
1,586✔
1862
        args.push_back( ref_arr[processed - 1] );
1,586✔
1863
        args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
1,586✔
1864
        args.push_back( thisArray );
1,586✔
1865

1866
        return ex.withContinuation( continuation, std::move( args ) );
1,586✔
1867
      };
1,649✔
1868

1869
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
126✔
1870
                                  std::move( args ) );
126✔
1871
    }
63✔
1872
    break;
3✔
1873

1874
  case MTH_FIND:
25✔
1875
    if ( name_arr.empty() )
25✔
1876
    {
1877
      if ( ex.numParams() < 1 )
25✔
1878
        return new BError( "Invalid parameter type" );
3✔
1879

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

1882
      if ( !param0 )
22✔
1883
        return new BError( "Invalid parameter type" );
3✔
1884

1885
      if ( ref_arr.empty() )
19✔
1886
        return new ObjArray();
6✔
1887

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

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

1907
        if ( !thisArray->isa( OTArray ) )
31✔
1908
          return UninitObject::create();
×
1909

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

1912
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
31✔
1913
        {
1914
          return UninitObject::create();
3✔
1915
        }
1916

1917
        ++processed;
28✔
1918

1919
        BObjectRefVec args;
28✔
1920
        args.push_back( ref_arr[processed - 1] );
28✔
1921
        args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
28✔
1922
        args.push_back( thisArray );
28✔
1923

1924
        elementRef = args[0];
28✔
1925

1926
        return ex.withContinuation( continuation, std::move( args ) );
28✔
1927
      };
41✔
1928

1929
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
26✔
1930
                                  std::move( args ) );
26✔
1931
    }
13✔
1932
    break;
×
1933

1934
  case MTH_FINDINDEX:
132✔
1935
    if ( name_arr.empty() )
132✔
1936
    {
1937
      if ( ex.numParams() < 1 )
129✔
1938
        return new BError( "Invalid parameter type" );
3✔
1939

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

1942
      if ( !param0 )
126✔
1943
        return new BError( "Invalid parameter type" );
3✔
1944

1945
      if ( ref_arr.empty() )
123✔
1946
        return new BLong( 0 );
3✔
1947

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

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

1966
        if ( !thisArray->isa( OTArray ) )
9,146✔
1967
          return new BLong( 0 );
×
1968

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

1971
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
9,146✔
1972
        {
1973
          return new BLong( 0 );
3✔
1974
        }
1975

1976
        ++processed;
9,143✔
1977

1978
        BObjectRefVec args;
9,143✔
1979
        args.push_back( ref_arr[processed - 1] );
9,143✔
1980
        args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
9,143✔
1981
        args.push_back( thisArray );
9,143✔
1982

1983
        return ex.withContinuation( continuation, std::move( args ) );
9,143✔
1984
      };
9,263✔
1985

1986
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
240✔
1987
                                  std::move( args ) );
240✔
1988
    }
120✔
1989
    break;
3✔
1990

1991
  case MTH_CYCLE:
×
1992
    if ( name_arr.empty() )
×
1993
    {
1994
      int shift_by;
1995

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

2006
      if ( ref_arr.empty() || std::abs( shift_by ) > (int)ref_arr.size() )
×
2007
        return new BLong( 0 );
×
2008

2009
      if ( shift_by > 0 )
×
2010
        std::rotate( ref_arr.begin(), ref_arr.end() - shift_by, ref_arr.end() );
×
2011
      else
2012
        std::rotate( ref_arr.begin(), ref_arr.begin() - shift_by, ref_arr.end() );
×
2013

2014
      return new BLong( 1 );
×
2015
    }
2016
    break;
×
2017

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

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

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

2123
void ObjArray::packonto( std::string& str ) const
41✔
2124
{
2125
  fmt::format_to( std::back_inserter( str ), "a{}:"_cf, ref_arr.size() );
41✔
2126
  for ( const auto& elem : ref_arr )
173✔
2127
  {
2128
    if ( elem.get() )
132✔
2129
    {
2130
      BObject* bo = elem.get();
132✔
2131
      bo->impptr()->packonto( str );
132✔
2132
    }
2133
    else
2134
    {
NEW
2135
      str += "x";
×
2136
    }
2137
  }
2138
}
41✔
2139

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

2169
std::string BApplicObjBase::getStringRep() const
208✔
2170
{
2171
  return std::string( "<appobj:" ) + typeOf() + ">";
416✔
2172
}
2173

2174
void BApplicObjBase::printOn( std::ostream& os ) const
×
2175
{
2176
  os << getStringRep();
×
2177
}
×
2178

2179
#if BOBJECTIMP_DEBUG
2180
BBoolean::BBoolean( bool bval ) : BObjectImp( OTBoolean ), bval_( bval ) {}
2181
BBoolean::BBoolean( const BBoolean& B ) : BBoolean( B.bval_ ) {}
2182
#endif
2183

2184
BObjectImp* BBoolean::unpack( std::istream& is )
12✔
2185
{
2186
  int lv;
2187
  if ( is >> lv )
12✔
2188
  {
2189
    return new BBoolean( lv != 0 );
12✔
2190
  }
2191

2192
  return new BError( "Error extracting Boolean value" );
×
2193
}
2194

2195
void BBoolean::packonto( std::string& str ) const
24✔
2196
{
2197
  fmt::format_to( std::back_inserter( str ), "b{}"_cf, bval_ ? 1 : 0 );
24✔
2198
}
24✔
2199

2200
BObjectImp* BBoolean::copy() const
242✔
2201
{
2202
  return new BBoolean( *this );
242✔
2203
}
2204

2205
size_t BBoolean::sizeEstimate() const
56✔
2206
{
2207
  return sizeof( BBoolean );
56✔
2208
}
2209

2210
bool BBoolean::isTrue() const
598✔
2211
{
2212
  return bval_;
598✔
2213
}
2214

2215
bool BBoolean::operator==( const BObjectImp& objimp ) const
42✔
2216
{
2217
  return bval_ == objimp.isTrue();
42✔
2218
}
2219

2220
std::string BBoolean::getStringRep() const
60✔
2221
{
2222
  return bval_ ? "true" : "false";
60✔
2223
}
2224

2225
BFunctionRef::BFunctionRef( ref_ptr<EScriptProgram> program, unsigned function_reference_index,
3,248✔
2226
                            std::shared_ptr<ValueStackCont> globals, ValueStackCont&& captures )
3,248✔
2227
    : BObjectImp( OTFuncRef ),
2228
      prog_( std::move( program ) ),
3,248✔
2229
      function_reference_index_( function_reference_index ),
3,248✔
2230
      globals( std::move( globals ) ),
3,248✔
2231
      captures( std::move( captures ) )
6,496✔
2232
{
2233
  passert( function_reference_index_ < prog_->function_references.size() );
3,248✔
2234
}
3,248✔
2235

2236
BFunctionRef::BFunctionRef( const BFunctionRef& B )
828✔
2237
    : BFunctionRef( B.prog_, B.function_reference_index_, B.globals, ValueStackCont( B.captures ) )
828✔
2238
{
2239
}
828✔
2240

2241
BObjectImp* BFunctionRef::copy() const
828✔
2242
{
2243
  return new BFunctionRef( *this );
828✔
2244
}
2245

2246
size_t BFunctionRef::sizeEstimate() const
99✔
2247
{
2248
  return sizeof( BFunctionRef ) + Clib::memsize( captures );
99✔
2249
}
2250

2251
bool BFunctionRef::isTrue() const
3✔
2252
{
2253
  return false;
3✔
2254
}
2255

2256
bool BFunctionRef::operator==( const BObjectImp& /*objimp*/ ) const
×
2257
{
2258
  return false;
×
2259
}
2260

2261
BObjectImp* BFunctionRef::selfIsObjImp( const BObjectImp& other ) const
94✔
2262
{
2263
  auto classinstref = dynamic_cast<const BClassInstanceRef*>( &other );
94✔
2264
  if ( !classinstref )
94✔
2265
    return new BLong( 0 );
×
2266

2267
  auto classinst = classinstref->instance();
94✔
2268

2269
  // Class index could be maxint if the function reference is not a class
2270
  // method.
2271
  if ( class_index() >= prog_->class_descriptors.size() )
94✔
2272
    return new BLong( 0 );
×
2273

2274
  const auto& my_constructors = prog_->class_descriptors.at( class_index() ).constructors;
94✔
2275
  passert( !my_constructors.empty() );
94✔
2276
  const auto& my_descriptor = my_constructors.front();
94✔
2277

2278
  const auto& other_descriptors =
2279
      classinst->prog()->class_descriptors.at( classinst->index() ).constructors;
94✔
2280

2281
  // An optimization for same program: since strings are never duplicated inside
2282
  // the data section, we can just check for offset equality.
2283
  if ( prog_ == classinst->prog() )
94✔
2284
  {
2285
    for ( const auto& other_descriptor : other_descriptors )
195✔
2286
    {
2287
      if ( my_descriptor.type_tag_offset == other_descriptor.type_tag_offset )
180✔
2288
        return new BLong( 1 );
54✔
2289
    }
2290
  }
2291
  // For different programs, we must check for string equality.
2292
  else
2293
  {
2294
    auto type_tag = prog_->symbols.array() + my_descriptor.type_tag_offset;
25✔
2295
    for ( const auto& other_descriptor : other_descriptors )
63✔
2296
    {
2297
      auto other_type_tag = classinst->prog()->symbols.array() + other_descriptor.type_tag_offset;
51✔
2298
      if ( strcmp( type_tag, other_type_tag ) == 0 )
51✔
2299
        return new BLong( 1 );
13✔
2300
    }
2301
  }
2302

2303
  return new BLong( 0 );
27✔
2304
}
2305

2306
std::string BFunctionRef::getStringRep() const
155✔
2307
{
2308
  return "FunctionObject";
155✔
2309
}
2310

2311
BObjectImp* BFunctionRef::call_method( const char* methodname, Executor& ex )
21✔
2312
{
2313
  ObjMethod* objmethod = getKnownObjMethod( methodname );
21✔
2314
  if ( objmethod != nullptr )
21✔
2315
    return call_method_id( objmethod->id, ex );
21✔
2316
  return nullptr;
×
2317
}
2318

2319
bool BFunctionRef::validCall( const int id, Executor& ex, Instruction* inst ) const
38,199✔
2320
{
2321
  auto passed_args = static_cast<int>( ex.numParams() );
38,199✔
2322

2323
  auto [expected_min_args, expected_max_args] = expected_args();
38,199✔
2324

2325
  if ( id != MTH_CALL && id != MTH_NEW && id != MTH_CALL_METHOD )
38,199✔
2326
    return false;
×
2327

2328
  if ( id == MTH_NEW && !constructor() )
38,199✔
2329
    return false;
27✔
2330

2331
  if ( passed_args < expected_min_args || ( passed_args > expected_max_args && !variadic() ) )
38,172✔
2332
    return false;
99✔
2333

2334
  inst->func = &Executor::ins_nop;
38,073✔
2335

2336
  if ( passed_args >= expected_max_args )
38,073✔
2337
  {
2338
    inst->token.lval = pc();
37,857✔
2339
  }
2340
  else
2341
  {
2342
    auto default_parameter_address_index = expected_max_args - passed_args - 1;
216✔
2343
    passert( default_parameter_address_index >= 0 &&
216✔
2344
             default_parameter_address_index <
2345
                 static_cast<int>( default_parameter_addresses().size() ) );
2346
    inst->token.lval = default_parameter_addresses().at( default_parameter_address_index );
216✔
2347
  }
2348

2349
  return true;
38,073✔
2350
}
2351

2352
bool BFunctionRef::validCall( const char* methodname, Executor& ex, Instruction* inst ) const
×
2353
{
2354
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
2355
  if ( objmethod == nullptr )
×
2356
    return false;
×
2357
  return validCall( objmethod->id, ex, inst );
×
2358
}
2359

2360
int BFunctionRef::numParams() const
111,418✔
2361
{
2362
  return prog_->function_references[function_reference_index_].parameter_count;
111,418✔
2363
}
2364

2365
unsigned BFunctionRef::pc() const
37,857✔
2366
{
2367
  return prog_->function_references[function_reference_index_].address;
37,857✔
2368
}
2369

2370
bool BFunctionRef::variadic() const
74,558✔
2371
{
2372
  return prog_->function_references[function_reference_index_].is_variadic;
74,558✔
2373
}
2374

2375
ref_ptr<EScriptProgram> BFunctionRef::prog() const
38,199✔
2376
{
2377
  return prog_;
38,199✔
2378
}
2379

2380
unsigned BFunctionRef::class_index() const
269✔
2381
{
2382
  return prog_->function_references[function_reference_index_].class_index;
269✔
2383
}
2384

2385
bool BFunctionRef::constructor() const
270✔
2386
{
2387
  return prog_->function_references[function_reference_index_].is_constructor;
270✔
2388
}
2389

2390
bool BFunctionRef::class_method() const
653✔
2391
{
2392
  return prog_->function_references[function_reference_index_].class_index <
653✔
2393
         std::numeric_limits<unsigned>::max();
653✔
2394
}
2395

2396
const std::vector<unsigned>& BFunctionRef::default_parameter_addresses() const
77,028✔
2397
{
2398
  return prog_->function_references[function_reference_index_].default_parameter_addresses;
77,028✔
2399
}
2400

2401
int BFunctionRef::default_parameter_count() const
76,596✔
2402
{
2403
  return static_cast<int>( default_parameter_addresses().size() );
76,596✔
2404
}
2405

2406
std::pair<int, int> BFunctionRef::expected_args() const
38,298✔
2407
{
2408
  auto expected_min_args = numParams() - default_parameter_count();  // remove default parameters
38,298✔
2409

2410
  return { expected_min_args, expected_min_args + default_parameter_count() };
38,298✔
2411
}
2412

2413
BObjectImp* BFunctionRef::call_method_id( const int id, Executor& ex, bool /*forcebuiltin*/ )
126✔
2414
{
2415
  bool adjust_for_this = false;
126✔
2416

2417
  // These are only entered if `ins_call_method_id` did _not_ do the call jump.
2418
  switch ( id )
126✔
2419
  {
2420
  case MTH_NEW:
54✔
2421
    if ( !constructor() )
54✔
2422
      return new BError( "Function is not a constructor" );
27✔
2423
    // intentional fallthrough
2424
  case MTH_CALL_METHOD:
2425
    adjust_for_this = true;
48✔
2426
    // intentional fallthrough
2427
  case MTH_CALL:
99✔
2428
  {
2429
    auto [expected_min_args, expected_max_args] = expected_args();
99✔
2430
    auto param_count = ex.numParams();
99✔
2431

2432
    if ( adjust_for_this )
99✔
2433
    {
2434
      --expected_min_args;
48✔
2435
      --expected_max_args;
48✔
2436
      --param_count;
48✔
2437
    }
2438

2439
    auto expected_arg_string = variadic() ? fmt::format( "{}+", expected_min_args )
99✔
2440
                               : ( expected_min_args == expected_max_args )
63✔
2441
                                   ? std::to_string( expected_min_args )
63✔
2442
                                   : fmt::format( "{}-{}", expected_min_args, expected_max_args );
159✔
2443

2444
    return new BError( fmt::format( "Invalid argument count: expected {}, got {}",
×
2445
                                    expected_arg_string, param_count ) );
198✔
2446
  }
99✔
2447
  default:
×
2448
    return nullptr;
×
2449
  }
2450
}
2451

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

2454
BSpread::BSpread( const BSpread& B ) : BObjectImp( OTSpread ), object( B.object ) {}
×
2455

2456
size_t BSpread::sizeEstimate() const
×
2457
{
2458
  return sizeof( BSpread ) + object.sizeEstimate();
×
2459
}
2460

2461
BObjectImp* BSpread::copy() const
×
2462
{
2463
  return new BSpread( *this );
×
2464
}
2465

2466
bool BSpread::isTrue() const
×
2467
{
2468
  return object->isTrue();
×
2469
}
2470

2471
std::string BSpread::getStringRep() const
×
2472
{
2473
  return "Spread";
×
2474
}
2475

2476
std::unique_ptr<BSpecialUserFuncJump> BSpecialUserFuncJump::imp_special_userjmp =
2477
    std::make_unique<BSpecialUserFuncJump>();
2478

2479
BSpecialUserFuncJump::BSpecialUserFuncJump() : BObjectImp( OTSpecialUserFuncJump ) {}
4,944✔
2480

2481
size_t BSpecialUserFuncJump::sizeEstimate() const
×
2482
{
2483
  return sizeof( BSpecialUserFuncJump );
×
2484
};
2485

2486
std::string BSpecialUserFuncJump::getStringRep() const
×
2487
{
2488
  return "BSpecialUserFuncJump";
×
2489
};
2490

2491
BObjectImp* BSpecialUserFuncJump::copy() const
×
2492
{
2493
  return get();
×
2494
};
2495

2496
BSpecialUserFuncJump* BSpecialUserFuncJump::get()
632✔
2497
{
2498
  return imp_special_userjmp.get();
632✔
2499
}
2500

2501
void BSpecialUserFuncJump::ReleaseSharedInstance()
3✔
2502
{
2503
  imp_special_userjmp.reset();
3✔
2504
}
3✔
2505

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