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

polserver / polserver / 20206938091

14 Dec 2025 10:58AM UTC coverage: 60.262% (+0.03%) from 60.234%
20206938091

push

github

web-flow
Fix sending of new objects for boat travellers and observers (#829)

* added debugs for boatmove

* log component send

* added option to resend components

* compilation fix

* activate by default

* cleanup fix no1
more debug logs

* test client now ignores/removes objects out of range
lets see what explodes

* syntax fix

* syntax fix..

* need a copy of the keys

* handle equipped items

* handle server side view range change

* test char on boat and move to npc

* compilation fix?

* more logs

* corrected logs

* the boat needs to move more

* change order, first smooth move then new objects

* correct fix I think
send new objects for all newer clients on the boat after the boat pkt is
send (which also updates the position for the client)

* cleanup, fixed first test by sending also the playerposition when a new
obj appears

* test for item on boat

* need to move the boat further so that components are in range

* is the test wrong or is it a bug?

* move further

* ability to disable auto delete of objects to be able to test serverside
remove pkts

* change start position of the boat

* cleanup and fixed tests?

* more cleanup

* docs

24 of 28 new or added lines in 3 files covered. (85.71%)

3 existing lines in 3 files now uncovered.

44272 of 73466 relevant lines covered (60.26%)

498519.42 hits per line

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

73.73
/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
namespace Pol
43
{
44
namespace Bscript
45
{
46
Clib::fixed_allocator<sizeof( BObject ), 256> bobject_alloc;
47
Clib::fixed_allocator<sizeof( UninitObject ), 256> uninit_alloc;
48
Clib::fixed_allocator<sizeof( BLong ), 256> blong_alloc;
49
Clib::fixed_allocator<sizeof( Double ), 256> double_alloc;
50

51
size_t BObjectRef::sizeEstimate() const
2,114✔
52
{
53
  if ( get() )
2,114✔
54
    return sizeof( BObjectRef ) + get()->sizeEstimate();
2,024✔
55
  else
56
    return sizeof( BObjectRef );
90✔
57
}
58
size_t BObject::sizeEstimate() const
4,551✔
59
{
60
  if ( objimp.get() )
4,551✔
61
    return sizeof( BObject ) + objimp.get()->sizeEstimate();
4,551✔
62
  else
63
    return sizeof( BObject );
×
64
}
65

66

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

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

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

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

135
bool BObject::operator!=( const BObject& obj ) const
7,568✔
136
{
137
  return *objimp != *( obj.objimp );
7,568✔
138
}
139
bool BObject::operator==( const BObject& obj ) const
8,086✔
140
{
141
  return *objimp == *( obj.objimp );
8,086✔
142
}
143
bool BObject::operator<( const BObject& obj ) const
7,469✔
144
{
145
  return *objimp < *( obj.objimp );
7,469✔
146
}
147
bool BObject::operator<=( const BObject& obj ) const
779✔
148
{
149
  return *objimp <= *( obj.objimp );
779✔
150
}
151
bool BObject::operator>( const BObject& obj ) const
6,033✔
152
{
153
  return *objimp > *( obj.objimp );
6,033✔
154
}
155
bool BObject::operator>=( const BObject& obj ) const
419✔
156
{
157
  return *objimp >= *( obj.objimp );
419✔
158
}
159

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

164

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

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

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

202
std::string BObjectImp::pack() const
53✔
203
{
204
  OSTRINGSTREAM os;
53✔
205
  packonto( os );
53✔
206
  return OSTRINGSTREAM_STR( os );
106✔
207
}
53✔
208

209
void BObjectImp::packonto( std::ostream& os ) const
6✔
210
{
211
  os << "u";
6✔
212
}
6✔
213

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

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

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

263

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

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

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

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

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

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

345
BObjectRef BObjectImp::OperMultiSubscriptAssign( std::stack<BObjectRef>& indices,
×
346
                                                 BObjectImp* target )
347
{
348
  BObjectRef index = indices.top();
×
349
  indices.pop();
×
350
  if ( indices.empty() )
×
351
  {
352
    BObjectImp* imp = array_assign( ( *index ).impptr(), target, false );
×
353
    return BObjectRef( imp );
×
354
  }
355
  else
356
  {
357
    BObjectRef ref = OperSubscript( *index );
×
358
    return ( *ref ).impptr()->OperMultiSubscript( indices );
×
359
  }
×
360
}
×
361

362
BObjectImp* BObjectImp::selfIsObjImp( const BObjectImp& objimp ) const
6✔
363
{
364
  return objimp.selfIsObj( *this );
6✔
365
}
366

367
BObjectImp* BObjectImp::selfIsObj( const BObjectImp& ) const
6✔
368
{
369
  return new BLong( 0 );
6✔
370
}
371

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

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

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

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

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

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

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

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

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

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

862
BObjectImp* BObjectImp::bitnot() const
132✔
863
{
864
  return copy();
132✔
865
}
866

867
void BObjectImp::operInsertInto( BObject& obj, const BObjectImp& /*objimp*/ )
×
868
{
869
  obj.setimp( new BError( "Object is not a 'container'" ) );
×
870
}
×
871

872

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

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

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

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

897
void BObjectImp::operModulusEqual( BObject& obj, BObjectImp& objimp )
381✔
898
{
899
  objimp.selfModulusObjImp( *this, obj );
381✔
900
  // obj.setimp( selfModulusObjImp( objimp ) );
901
}
381✔
902

903
BObject BObjectImp::operator-( void ) const
×
904
{
905
  BObjectImp* newobj = inverse();
×
906
  return BObject( newobj );
×
907
}
908

909
BObjectImp* BObjectImp::inverse() const
105✔
910
{
911
  return UninitObject::create();
105✔
912
}
913

914
void BObjectImp::selfPlusPlus() {}
18✔
915

916
void BObjectImp::selfMinusMinus() {}
9✔
917

918
BObjectRef BObjectImp::OperSubscript( const BObject& /*obj*/ )
25✔
919
{
920
  return BObjectRef( copy() );
25✔
921
}
922

923
/*
924
  "All Objects are inherently good."
925
  */
926
bool BObjectImp::isTrue( void ) const
2,332✔
927
{
928
  return true;
2,332✔
929
}
930

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

953
  return get_member( memb->code );
7,707✔
954
}
955
BObjectRef BObjectImp::set_member_id( const int id, BObjectImp* valueimp, bool copy )
190✔
956
{
957
  ObjMember* memb = getObjMember( id );
190✔
958

959
  return set_member( memb->code, valueimp, copy );
190✔
960
}
961
long BObjectImp::contains( const BObjectImp& /*imp*/ ) const
3✔
962
{
963
  return 0;
3✔
964
}
965

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

971
BObjectRef BObjectImp::operDotMinus( const char* /*name*/ )
78✔
972
{
973
  return BObjectRef( new BError( "Operator .- undefined" ) );
156✔
974
}
975

976
BObjectRef BObjectImp::operDotQMark( const char* /*name*/ )
4✔
977
{
978
  return BObjectRef( new BError( "Operator .? undefined" ) );
8✔
979
}
980

981
UninitObject* UninitObject::SharedInstance;
982
ref_ptr<BObjectImp> UninitObject::SharedInstanceOwner;
983

984
UninitObject::UninitObject() : BObjectImp( OTUninit ) {}
31,927✔
985

986
BObjectImp* UninitObject::copy( void ) const
1,002✔
987
{
988
  return create();
1,002✔
989
}
990

991
size_t UninitObject::sizeEstimate() const
151✔
992
{
993
  return sizeof( UninitObject );
151✔
994
}
995

996
bool UninitObject::isTrue() const
5,433✔
997
{
998
  return false;
5,433✔
999
}
1000

1001
/**
1002
 * An uninit is equal to any other error or uninit
1003
 */
1004
bool UninitObject::operator==( const BObjectImp& imp ) const
39✔
1005
{
1006
  return ( imp.isa( OTError ) || imp.isa( OTUninit ) );
39✔
1007
}
1008

1009
bool UninitObject::operator<( const BObjectImp& imp ) const
375✔
1010
{
1011
  if ( imp.isa( OTError ) || imp.isa( OTUninit ) )
375✔
1012
    return false;  // Because it's equal can't be lesser
366✔
1013

1014
  return true;
9✔
1015
}
1016

1017

1018
ObjArray::ObjArray() : BObjectImp( OTArray ), name_arr(), ref_arr() {}
6,587✔
1019

1020
ObjArray::ObjArray( BObjectType type ) : BObjectImp( type ), name_arr(), ref_arr() {}
×
1021

1022
ObjArray::ObjArray( const ObjArray& copyfrom )
4,835✔
1023
    : BObjectImp( copyfrom.type() ), name_arr( copyfrom.name_arr ), ref_arr( copyfrom.ref_arr )
4,835✔
1024
{
1025
  deepcopy();
4,835✔
1026
}
4,835✔
1027

1028
void ObjArray::deepcopy()
4,835✔
1029
{
1030
  for ( auto& elem : ref_arr )
53,213✔
1031
  {
1032
    if ( elem.get() )
48,378✔
1033
    {
1034
      /*
1035
          NOTE: all BObjectRefs in an ObjArray reference BNamedObjects not BObjects
1036
          HMMM, can this BNamedObject get destructed before we're done with it?
1037
          No, we're making a copy, leaving the original be.
1038
          (SO, bno's refcount should be >1 here)
1039
          */
1040

1041
      BObject* bo = elem.get();
48,366✔
1042
      elem.set( new BObject( bo->impptr()->copy() ) );
48,366✔
1043
    }
1044
  }
1045
}
4,835✔
1046

1047
BObjectImp* ObjArray::copy( void ) const
4,782✔
1048
{
1049
  auto nobj = new ObjArray( *this );
4,782✔
1050
  return nobj;
4,782✔
1051
}
1052

1053
size_t ObjArray::sizeEstimate() const
524✔
1054
{
1055
  size_t size = sizeof( ObjArray );
524✔
1056
  size += Clib::memsize( ref_arr );
524✔
1057
  for ( const auto& elem : ref_arr )
2,095✔
1058
  {
1059
    size += elem.sizeEstimate();
1,571✔
1060
  }
1061
  size += Clib::memsize( name_arr );
524✔
1062
  for ( const auto& elem : name_arr )
560✔
1063
  {
1064
    size += elem.capacity();
36✔
1065
  }
1066
  return size;
524✔
1067
}
1068

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

1082
  const ObjArray& thatarr = static_cast<const ObjArray&>( imp );
67✔
1083
  if ( thatarr.ref_arr.size() != ref_arr.size() )
67✔
1084
    return false;
3✔
1085

1086
  for ( unsigned i = 0; i < ref_arr.size(); ++i )
311✔
1087
  {
1088
    const BObjectRef& thisref = ref_arr[i];
250✔
1089
    const BObjectRef& thatref = thatarr.ref_arr[i];
250✔
1090

1091
    const BObject* thisobj = thisref.get();
250✔
1092
    const BObject* thatobj = thatref.get();
250✔
1093
    if ( thisobj != nullptr && thatobj != nullptr )
250✔
1094
    {
1095
      const BObjectImp& thisimp = thisobj->impref();
250✔
1096
      const BObjectImp& thatimp = thatobj->impref();
250✔
1097

1098
      if ( thisimp == thatimp )
250✔
1099
        continue;
247✔
1100
      else
1101
        return false;
3✔
1102
    }
1103
    else if ( thisobj == nullptr && thatobj == nullptr )
×
1104
    {
1105
      continue;
×
1106
    }
1107
    else
1108
    {
1109
      return false;
×
1110
    }
1111
  }
1112
  return true;
61✔
1113
}
1114

1115
const BObjectImp* ObjArray::imp_at( unsigned index /* 1-based */ ) const
×
1116
{
1117
  assert( index > 0 );
1118
  if ( index > ref_arr.size() )
×
1119
    return nullptr;
×
1120
  const BObjectRef& ref = ref_arr[index - 1];
×
1121
  if ( ref.get() == nullptr )
×
1122
    return nullptr;
×
1123
  return ref.get()->impptr();
×
1124
}
1125

1126
BObjectImp* ObjArray::array_assign( BObjectImp* idx, BObjectImp* target, bool copy )
525✔
1127
{
1128
  if ( idx->isa( OTLong ) )
525✔
1129
  {
1130
    BLong& lng = (BLong&)*idx;
525✔
1131

1132
    unsigned index = (unsigned)lng.value();
525✔
1133
    if ( index > ref_arr.size() )
525✔
1134
      ref_arr.resize( index );
300✔
1135
    else if ( index <= 0 )
225✔
1136
      return new BError( "Array index out of bounds" );
×
1137

1138
    BObjectRef& ref = ref_arr[index - 1];
525✔
1139
    BObject* refobj = ref.get();
525✔
1140

1141
    BObjectImp* new_target = copy ? target->copy() : target;
525✔
1142

1143
    if ( refobj != nullptr )
525✔
1144
    {
1145
      refobj->setimp( new_target );
219✔
1146
    }
1147
    else
1148
    {
1149
      ref.set( new BObject( new_target ) );
306✔
1150
    }
1151
    return ref->impptr();
525✔
1152
  }
1153
  else
1154
  {
1155
    return UninitObject::create();
×
1156
  }
1157
}
1158

1159
void ObjArray::operInsertInto( BObject& /*obj*/, const BObjectImp& objimp )
9,010✔
1160
{
1161
  ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
9,010✔
1162
}
9,010✔
1163

1164
BObjectImp* ObjArray::selfPlusObj( const BObjectImp& objimp ) const
9✔
1165
{
1166
  std::unique_ptr<ObjArray> result( new ObjArray( *this ) );
9✔
1167
  result->ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
9✔
1168
  return result.release();
18✔
1169
}
9✔
1170
BObjectImp* ObjArray::selfPlusObj( const BLong& objimp ) const
6✔
1171
{
1172
  std::unique_ptr<ObjArray> result( new ObjArray( *this ) );
6✔
1173
  result->ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
6✔
1174
  return result.release();
12✔
1175
}
6✔
1176
BObjectImp* ObjArray::selfPlusObj( const Double& objimp ) const
3✔
1177
{
1178
  std::unique_ptr<ObjArray> result( new ObjArray( *this ) );
3✔
1179
  result->ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
3✔
1180
  return result.release();
6✔
1181
}
3✔
1182
BObjectImp* ObjArray::selfPlusObj( const String& objimp ) const
9✔
1183
{
1184
  std::unique_ptr<ObjArray> result( new ObjArray( *this ) );
9✔
1185
  result->ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
9✔
1186
  return result.release();
18✔
1187
}
9✔
1188

1189
BObjectImp* ObjArray::selfPlusObj( const ObjArray& objimp ) const
23✔
1190
{
1191
  std::unique_ptr<ObjArray> result( new ObjArray( *this ) );
23✔
1192

1193
  for ( const auto& elem : objimp.ref_arr )
56✔
1194
  {
1195
    if ( elem.get() )
33✔
1196
    {
1197
      /*
1198
          NOTE: all BObjectRefs in an ObjArray reference BNamedObjects not BObjects
1199
          HMMM, can this BNamedObject get destructed before we're done with it?
1200
          No, we're making a copy, leaving the original be.
1201
          (SO, bno's refcount should be >1 here)
1202
          */
1203
      BObject* bo = elem.get();
24✔
1204

1205
      result->ref_arr.push_back( BObjectRef( new BObject( ( *bo )->copy() ) ) );
24✔
1206
    }
1207
    else
1208
    {
1209
      result->ref_arr.push_back( BObjectRef() );
9✔
1210
    }
1211
  }
1212
  return result.release();
46✔
1213
}
23✔
1214

1215
BObjectImp* ObjArray::selfPlusObjImp( const BObjectImp& other ) const
221✔
1216
{
1217
  return other.selfPlusObj( *this );
221✔
1218
}
1219
void ObjArray::selfPlusObjImp( BObjectImp& objimp, BObject& obj )
27✔
1220
{
1221
  objimp.selfPlusObj( *this, obj );
27✔
1222
}
27✔
1223
void ObjArray::selfPlusObj( BObjectImp& objimp, BObject& /*obj*/ )
9✔
1224
{
1225
  ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
9✔
1226
}
9✔
1227
void ObjArray::selfPlusObj( BLong& objimp, BObject& /*obj*/ )
3✔
1228
{
1229
  ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
3✔
1230
}
3✔
1231
void ObjArray::selfPlusObj( Double& objimp, BObject& /*obj*/ )
3✔
1232
{
1233
  ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
3✔
1234
}
3✔
1235
void ObjArray::selfPlusObj( String& objimp, BObject& /*obj*/ )
3✔
1236
{
1237
  ref_arr.push_back( BObjectRef( new BObject( objimp.copy() ) ) );
3✔
1238
}
3✔
1239
void ObjArray::selfPlusObj( ObjArray& objimp, BObject& /*obj*/ )
3✔
1240
{
1241
  for ( const_iterator itr = objimp.ref_arr.begin(), itrend = objimp.ref_arr.end(); itr != itrend;
3✔
1242
        ++itr )
×
1243
  {
1244
    if ( itr->get() )
×
1245
    {
1246
      /*
1247
          NOTE: all BObjectRefs in an ObjArray reference BNamedObjects not BObjects
1248
          HMMM, can this BNamedObject get destructed before we're done with it?
1249
          No, we're making a copy, leaving the original be.
1250
          (SO, bno's refcount should be >1 here)
1251
          */
1252
      BObject* bo = itr->get();
×
1253

1254
      ref_arr.push_back( BObjectRef( new BObject( ( *bo )->copy() ) ) );
×
1255
    }
1256
    else
1257
    {
1258
      ref_arr.push_back( BObjectRef() );
×
1259
    }
1260
  }
1261
}
3✔
1262

1263
BObjectRef ObjArray::OperMultiSubscript( std::stack<BObjectRef>& indices )
3✔
1264
{
1265
  BObjectRef start_ref = indices.top();
3✔
1266
  indices.pop();
3✔
1267
  BObjectRef length_ref = indices.top();
3✔
1268
  indices.pop();
3✔
1269

1270
  BObject& length_obj = *length_ref;
3✔
1271
  BObject& start_obj = *start_ref;
3✔
1272

1273
  BObjectImp& length = length_obj.impref();
3✔
1274
  BObjectImp& start = start_obj.impref();
3✔
1275

1276
  // first deal with the start position.
1277
  // return BObjectRef(new BError( "Subscript out of range" ));
1278

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

1290
  // now the end index
1291

1292
  unsigned end;
1293
  if ( length.isa( OTLong ) )
3✔
1294
  {
1295
    BLong& lng = (BLong&)length;
×
1296
    end = (unsigned)lng.value();
×
1297
    if ( end == 0 || end > ref_arr.size() )
×
1298
      return BObjectRef( new BError( "Array end index out of bounds" ) );
×
1299
  }
1300
  else
1301
    return BObjectRef( copy() );
3✔
1302

1303
  auto str = new ObjArray();
×
1304

1305

1306
  // std::unique_ptr<ObjArray> result (new ObjArray());
1307
  unsigned i = 0;
×
1308
  for ( const_iterator itr = ref_arr.begin(), itrend = ref_arr.end(); itr != itrend; ++itr )
×
1309
  {
1310
    if ( ++i < index )
×
1311
      continue;
×
1312
    if ( i > end )
×
1313
      break;
×
1314
    if ( itr->get() )
×
1315
    {
1316
      BObject* bo = itr->get();
×
1317
      str->ref_arr.push_back( BObjectRef( new BObject( ( *bo )->copy() ) ) );
×
1318
    }
1319
    else
1320
    {
1321
      str->ref_arr.push_back( BObjectRef() );
×
1322
    }
1323
  }
1324
  /*
1325
  for (unsigned i = index; i < end; i++) {
1326
  BObject *bo = ref_arr[i];
1327
  if (bo != 0)
1328
  str->ref_arr.push_back( BObjectRef( new BObject( (*bo)->copy() ) ) );
1329
  else
1330
  result->ref_arr.push_back( BObjectRef() );
1331
  } */
1332
  //  return result.release();
1333
  return BObjectRef( str );
×
1334
}
3✔
1335

1336
BObjectRef ObjArray::OperSubscript( const BObject& rightobj )
2,918✔
1337
{
1338
  const BObjectImp& right = rightobj.impref();
2,918✔
1339
  if ( right.isa( OTLong ) )  // vector
2,918✔
1340
  {
1341
    BLong& lng = (BLong&)right;
2,918✔
1342

1343
    unsigned index = (unsigned)lng.value();
2,918✔
1344
    if ( index > ref_arr.size() )
2,918✔
1345
    {
1346
      return BObjectRef( new BError( "Array index out of bounds" ) );
17✔
1347
    }
1348
    else if ( index <= 0 )
2,901✔
1349
      return BObjectRef( new BError( "Array index out of bounds" ) );
4✔
1350

1351
    BObjectRef& ref = ref_arr[index - 1];
2,897✔
1352
    if ( ref.get() == nullptr )
2,897✔
1353
      ref.set( new BObject( UninitObject::create() ) );
×
1354
    return ref;
2,897✔
1355
  }
1356
  else if ( right.isa( OTString ) )
×
1357
  {
1358
    // TODO: search for named variables (structure members)
1359
    return BObjectRef( copy() );
×
1360
  }
1361
  else
1362
  {
1363
    // TODO: crap out
1364
    return BObjectRef( copy() );
×
1365
  }
1366
}
1367

1368
BObjectRef ObjArray::get_member( const char* membername )
60✔
1369
{
1370
  int i = 0;
60✔
1371
  for ( const_name_iterator itr = name_arr.begin(), end = name_arr.end(); itr != end; ++itr, ++i )
111✔
1372
  {
1373
    const std::string& name = ( *itr );
102✔
1374
    if ( stricmp( name.c_str(), membername ) == 0 )
102✔
1375
    {
1376
      return ref_arr[i];
102✔
1377
    }
1378
  }
1379

1380
  return BObjectRef( UninitObject::create() );
9✔
1381
}
1382

1383
BObjectRef ObjArray::set_member( const char* membername, BObjectImp* valueimp, bool copy )
12✔
1384
{
1385
  int i = 0;
12✔
1386
  for ( const_name_iterator itr = name_arr.begin(), end = name_arr.end(); itr != end; ++itr, ++i )
24✔
1387
  {
1388
    const std::string& name = ( *itr );
24✔
1389
    if ( stricmp( name.c_str(), membername ) == 0 )
24✔
1390
    {
1391
      BObjectImp* target = copy ? valueimp->copy() : valueimp;
12✔
1392
      ref_arr[i].get()->setimp( target );
12✔
1393
      return ref_arr[i];
24✔
1394
    }
1395
  }
1396
  return BObjectRef( UninitObject::create() );
×
1397
}
1398

1399
BObjectRef ObjArray::operDotPlus( const char* name )
27✔
1400
{
1401
  for ( auto& elem : name_arr )
36✔
1402
  {
1403
    if ( stricmp( name, elem.c_str() ) == 0 )
9✔
1404
    {
1405
      return BObjectRef( new BError( "Member already exists" ) );
×
1406
    }
1407
  }
1408
  name_arr.push_back( name );
27✔
1409
  auto pnewobj = new BObject( UninitObject::create() );
27✔
1410
  ref_arr.push_back( BObjectRef( pnewobj ) );
27✔
1411
  return BObjectRef( pnewobj );
27✔
1412
}
1413

1414
void ObjArray::addElement( BObjectImp* imp )
34,662✔
1415
{
1416
  ref_arr.push_back( BObjectRef( new BObject( imp ) ) );
34,662✔
1417
}
34,662✔
1418

1419
std::string ObjArray::getStringRep() const
3,314✔
1420
{
1421
  OSTRINGSTREAM os;
3,314✔
1422
  os << "{ ";
3,314✔
1423
  bool any = false;
3,314✔
1424
  for ( const auto& elem : ref_arr )
17,387✔
1425
  {
1426
    if ( any )
14,073✔
1427
      os << ", ";
11,617✔
1428
    else
1429
      any = true;
2,456✔
1430

1431
    BObject* bo = elem.get();
14,073✔
1432

1433
    if ( bo != nullptr )
14,073✔
1434
    {
1435
      std::string tmp = bo->impptr()->getStringRep();
14,031✔
1436
      os << tmp;
14,031✔
1437
    }
14,031✔
1438
  }
1439
  os << " }";
3,314✔
1440

1441
  return OSTRINGSTREAM_STR( os );
6,628✔
1442
}
3,314✔
1443

1444
long ObjArray::contains( const BObjectImp& imp ) const
865✔
1445
{
1446
  for ( auto itr = ref_arr.begin(), end = ref_arr.end(); itr != end; ++itr )
1,680✔
1447
  {
1448
    if ( itr->get() )
1,088✔
1449
    {
1450
      BObject* bo = ( itr->get() );
1,088✔
1451
      if ( bo == nullptr )
1,088✔
1452
      {
1453
        INFO_PRINTLN( "{} - '{} in array{{}}' check. Invalid data at index {}",
×
1454
                      Clib::scripts_thread_script, imp, ( itr - ref_arr.begin() ) + 1 );
×
1455
        continue;
×
1456
      }
1457
      else if ( *( bo->impptr() ) == imp )
1,088✔
1458
      {
1459
        return ( static_cast<long>( ( itr - ref_arr.begin() ) + 1 ) );
273✔
1460
      }
1461
    }
1462
  }
1463
  return 0;
592✔
1464
}
1465

1466
class objref_cmp
1467
{
1468
public:
1469
  bool operator()( const BObjectRef& x1, const BObjectRef& x2 ) const
548✔
1470
  {
1471
    const BObject* b1 = x1.get();
548✔
1472
    const BObject* b2 = x2.get();
548✔
1473
    if ( b1 == nullptr || b2 == nullptr )
548✔
1474
      return ( &x1 < &x2 );
×
1475

1476
    const BObject& r1 = *b1;
548✔
1477
    const BObject& r2 = *b2;
548✔
1478
    return ( r1 < r2 );
548✔
1479
  }
1480
};
1481

1482
BObjectImp* ObjArray::call_method_id( const int id, Executor& ex, bool /*forcebuiltin*/ )
9,933✔
1483
{
1484
  switch ( id )
9,933✔
1485
  {
1486
  case MTH_SIZE:
897✔
1487
    if ( ex.numParams() == 0 )
897✔
1488
      return new BLong( static_cast<int>( ref_arr.size() ) );
897✔
1489
    else
1490
      return new BError( "array.size() doesn't take parameters." );
×
1491

1492
  case MTH_ERASE:
31✔
1493
    if ( name_arr.empty() )
31✔
1494
    {
1495
      if ( ex.numParams() == 1 )
31✔
1496
      {
1497
        int idx;
1498
        if ( ex.getParam( 0, idx, 1, static_cast<int>( ref_arr.size() ) ) )  // 1-based index
31✔
1499
        {
1500
          ref_arr.erase( ref_arr.begin() + idx - 1 );
22✔
1501
          return new BLong( 1 );
22✔
1502
        }
1503
        else
1504
        {
1505
          return nullptr;
9✔
1506
        }
1507
      }
1508
      else
1509
        return new BError( "array.erase(index) requires a parameter." );
×
1510
    }
1511
    break;
×
1512
  case MTH_EXISTS:
×
1513
    if ( name_arr.empty() )
×
1514
    {
1515
      if ( ex.numParams() == 1 )
×
1516
      {
1517
        int idx;
1518
        if ( ex.getParam( 0, idx ) && idx >= 0 )
×
1519
        {
1520
          bool exists = ( idx <= (int)ref_arr.size() );
×
1521
          return new BLong( exists ? 1 : 0 );
×
1522
        }
1523
        else
1524
        {
1525
          return new BError( "Invalid parameter type" );
×
1526
        }
1527
      }
1528
      else
1529
        return new BError( "array.exists(index) requires a parameter." );
×
1530
    }
1531
    break;
×
1532
  case MTH_INSERT:
30✔
1533
    if ( name_arr.empty() )
30✔
1534
    {
1535
      if ( ex.numParams() == 2 )
30✔
1536
      {
1537
        int idx;
1538
        BObjectImp* imp = ex.getParamImp( 1 );
30✔
1539
        if ( ex.getParam( 0, idx, 1, static_cast<int>( ref_arr.size() + 1 ) ) &&
30✔
1540
             imp != nullptr )  // 1-based index
1541
        {
1542
          --idx;
30✔
1543
          BObjectRef tmp;
30✔
1544
          ref_arr.insert( ref_arr.begin() + idx, tmp );
30✔
1545
          BObjectRef& ref = ref_arr[idx];
30✔
1546
          ref.set( new BObject( imp->copy() ) );
30✔
1547
        }
30✔
1548
        else
1549
        {
1550
          return new BError( "Invalid parameter type" );
×
1551
        }
1552
      }
1553
      else
1554
        return new BError( "array.insert(index,value) requires two parameters." );
×
1555
    }
1556
    break;
30✔
1557
  case MTH_SHRINK:
199✔
1558
    if ( name_arr.empty() )
199✔
1559
    {
1560
      if ( ex.numParams() == 1 )
199✔
1561
      {
1562
        int idx;
1563
        if ( ex.getParam( 0, idx, 0, static_cast<int>( ref_arr.size() ) ) )  // 1-based index
199✔
1564
        {
1565
          ref_arr.erase( ref_arr.begin() + idx, ref_arr.end() );
193✔
1566
          return new BLong( 1 );
193✔
1567
        }
1568
        else
1569
        {
1570
          return new BError( "Invalid parameter type" );
6✔
1571
        }
1572
      }
1573
      else
1574
        return new BError( "array.shrink(nelems) requires a parameter." );
×
1575
    }
1576
    break;
×
1577
  case MTH_APPEND:
7,892✔
1578
    if ( name_arr.empty() )
7,892✔
1579
    {
1580
      if ( ex.numParams() == 1 )
7,892✔
1581
      {
1582
        BObjectImp* imp = ex.getParamImp( 0 );
7,892✔
1583
        if ( imp )
7,892✔
1584
        {
1585
          ref_arr.push_back( BObjectRef( new BObject( imp->copy() ) ) );
7,892✔
1586

1587
          return new BLong( 1 );
7,892✔
1588
        }
1589
        else
1590
        {
1591
          return new BError( "Invalid parameter type" );
×
1592
        }
1593
      }
1594
      else
UNCOV
1595
        return new BError( "array.append(value) requires a parameter." );
×
1596
    }
1597
    break;
×
1598
  case MTH_REVERSE:
9✔
1599
    if ( name_arr.empty() )
9✔
1600
    {
1601
      if ( ex.numParams() == 0 )
9✔
1602
      {
1603
        reverse( ref_arr.begin(), ref_arr.end() );
9✔
1604
        return new BLong( 1 );
9✔
1605
      }
1606
      else
1607
        return new BError( "array.reverse() doesn't take parameters." );
×
1608
    }
1609
    break;
×
1610
  case MTH_SORT:
52✔
1611
    if ( name_arr.empty() )
52✔
1612
    {
1613
      if ( ex.numParams() == 0 )
52✔
1614
      {
1615
        sort( ref_arr.begin(), ref_arr.end(), objref_cmp() );
23✔
1616
        return new BLong( 1 );
23✔
1617
      }
1618
      else if ( ex.numParams() == 1 )
29✔
1619
      {
1620
        int sub_index;
1621
        if ( !ex.getParam( 0, sub_index ) )
29✔
1622
          return new BError( "Invalid parameter type" );
×
1623
        if ( sub_index < 1 )
29✔
1624
          return new BError( "Invalid sub_index value" );
3✔
1625
        for ( const auto& ref : ref_arr )
103✔
1626
        {
1627
          if ( ref.get() == nullptr || !ref.get()->isa( OTArray ) )
89✔
1628
            return new BError( "Invalid array" );
12✔
1629
          auto sub_arr = ref.get()->impptr<ObjArray>();
83✔
1630
          if ( sub_arr->ref_arr.size() < static_cast<size_t>( sub_index ) )
83✔
1631
            return new BError( "Subindex to large" );
6✔
1632
        }
1633
        sort( ref_arr.begin(), ref_arr.end(),
14✔
1634
              [=]( const BObjectRef& x1, const BObjectRef& x2 ) -> bool
75✔
1635
              {
1636
                auto sub_arr1 = x1.get()->impptr<ObjArray>();
75✔
1637
                auto sub_arr2 = x2.get()->impptr<ObjArray>();
75✔
1638
                auto sub1 = sub_arr1->ref_arr[sub_index - 1];
75✔
1639
                auto sub2 = sub_arr2->ref_arr[sub_index - 1];
75✔
1640
                const BObject* b1 = sub1.get();
75✔
1641
                const BObject* b2 = sub2.get();
75✔
1642
                if ( b1 == nullptr || b2 == nullptr )
75✔
1643
                  return ( &x1 < &x2 );
6✔
1644
                return ( *b1 < *b2 );
69✔
1645
              } );
75✔
1646
        return new BLong( 1 );
14✔
1647
      }
1648
      else
1649
        return new BError( "array.sort(sub_index=0) takes at most one parameter." );
×
1650
    }
1651
    break;
×
1652
  case MTH_RANDOMENTRY:
×
1653
    if ( name_arr.empty() )
×
1654
    {
1655
      if ( ex.numParams() == 0 )
×
1656
      {
1657
        if ( !ref_arr.empty() )
×
1658
        {
1659
          const BObjectRef& ref =
1660
              ref_arr[Clib::random_int( static_cast<int>( ref_arr.size() ) - 1 )];
×
1661
          if ( ref.get() == nullptr )
×
1662
            return nullptr;
×
1663
          return ref.get()->impptr();
×
1664
        }
1665
      }
1666
      else
1667
        return new BError( "array.randomentry() doesn't take parameters." );
×
1668
    }
1669
    break;
×
1670
  case MTH_FILTER:
115✔
1671
    if ( name_arr.empty() )
115✔
1672
    {
1673
      if ( ex.numParams() < 1 )
115✔
1674
        return new BError( "Invalid parameter type" );
3✔
1675

1676
      BObjectImp* param0 = ex.getParamImp( 0, BObjectType::OTFuncRef );
112✔
1677

1678
      if ( !param0 )
112✔
1679
        return new BError( "Invalid parameter type" );
3✔
1680

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

1685
      // If nothing to filter, return an empty array, since nothing to call the function with.
1686
      if ( ref_arr.empty() )
109✔
1687
        return new ObjArray();
×
1688

1689
      // Arguments for user function call.
1690
      // - the element
1691
      // - the index of the element
1692
      // - the array itself
1693
      BObjectRefVec args;
109✔
1694
      args.push_back( ref_arr.front() );
109✔
1695
      args.push_back( BObjectRef( new BLong( 1 ) ) );
109✔
1696
      args.push_back( BObjectRef( this ) );
109✔
1697

1698
      // The ContinuationCallback receives three arguments:
1699
      //
1700
      // - `Executor&`
1701
      // - `BContinuation* continuation`: The continuation, with methods to handle
1702
      //   the continuation (call the function again; finalize)
1703
      // - `BObjectRef result`: The result of the user function call specified in
1704
      //   `makeContinuation`.
1705
      //
1706
      // We pass to the lambda a reference to the element in case the user
1707
      // function modifies ref_arr.
1708
      //
1709
      // Returns a `BObjectImp`:
1710
      // - Call the user function again by returning the same continuation via
1711
      //   `ex.withContinuation`.
1712
      // - Return something else (in this case, the filtered array) to provide
1713
      //   that value back to the script.
1714
      auto callback = [elementRef = args[0], processed = 1, thisArray = args[2],
109✔
1715
                       filteredRef = BObjectRef( new ObjArray ),
×
1716
                       initialSize = static_cast<int>( ref_arr.size() )](
109✔
1717
                          Executor& ex, BContinuation* continuation,
1718
                          BObjectRef result ) mutable -> BObjectImp*
11,072✔
1719
      {
1720
        auto filtered = filteredRef->impptr<ObjArray>();
2,849✔
1721

1722
        // Do something with result.
1723
        // If the result is true, add it to the filtered array.
1724
        if ( result->isTrue() )
2,849✔
1725
        {
1726
          filtered->ref_arr.push_back( BObjectRef( elementRef->impptr() ) );
1,789✔
1727
        }
1728

1729
        // If thisArray was modified for some reason to no longer be an array,
1730
        // return the filtered array.
1731
        if ( !thisArray->isa( OTArray ) )
2,849✔
1732
          return filtered;
×
1733

1734
        const auto& ref_arr = thisArray->impptr<ObjArray>()->ref_arr;
2,849✔
1735

1736
        // If the processed index is the last element, return the filtered
1737
        // array. Also check if the processed index is greater than the initial
1738
        // size of the array, as the user function may have modified the array.
1739
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
2,849✔
1740
        {
1741
          return filtered;
109✔
1742
        }
1743
        // Otherwise, increment the processed index and call the function again.
1744
        else
1745
        {
1746
          // Increment the processed counter.
1747
          ++processed;
2,740✔
1748

1749
          BObjectRefVec args;
2,740✔
1750
          args.push_back( ref_arr[processed - 1] );
2,740✔
1751
          args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
2,740✔
1752
          args.push_back( thisArray );
2,740✔
1753

1754
          elementRef = args[0];
2,740✔
1755

1756
          // Return this continuation with the new arguments.
1757
          return ex.withContinuation( continuation, std::move( args ) );
2,740✔
1758
        }
2,740✔
1759
      };
109✔
1760

1761
      // Create a new continuation for a user function call.
1762
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
218✔
1763
                                  std::move( args ) );
218✔
1764
    }
109✔
1765
    break;
×
1766

1767
  case MTH_MAP:
506✔
1768
    if ( name_arr.empty() )
506✔
1769
    {
1770
      if ( ex.numParams() < 1 )
497✔
1771
        return new BError( "Invalid parameter type" );
3✔
1772

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

1775
      if ( !param0 )
494✔
1776
        return new BError( "Invalid parameter type" );
3✔
1777

1778
      if ( ref_arr.empty() )
491✔
1779
        return new ObjArray();
105✔
1780

1781
      // Arguments for user function call.
1782
      // - the element
1783
      // - the index of the element
1784
      // - the array itself
1785
      BObjectRefVec args;
386✔
1786
      args.push_back( ref_arr.front() );
386✔
1787
      args.push_back( BObjectRef( new BLong( 1 ) ) );
386✔
1788
      args.push_back( BObjectRef( this ) );
386✔
1789

1790
      auto callback = [elementRef = args[0], processed = 1, thisArray = args[2],
386✔
1791
                       mappedRef = BObjectRef( new ObjArray ),
×
1792
                       initialSize = static_cast<int>( ref_arr.size() )](
386✔
1793
                          Executor& ex, BContinuation* continuation,
1794
                          BObjectRef result ) mutable -> BObjectImp*
8,202✔
1795
      {
1796
        auto mapped = mappedRef->impptr<ObjArray>();
2,340✔
1797

1798
        mapped->ref_arr.push_back( BObjectRef( result->impptr() ) );
2,340✔
1799

1800
        if ( !thisArray->isa( OTArray ) )
2,340✔
1801
          return mapped;
×
1802

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

1805
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
2,340✔
1806
        {
1807
          return mapped;
386✔
1808
        }
1809
        else
1810
        {
1811
          // Increment the processed counter.
1812
          ++processed;
1,954✔
1813

1814
          BObjectRefVec args;
1,954✔
1815
          args.push_back( ref_arr[processed - 1] );
1,954✔
1816
          args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
1,954✔
1817
          args.push_back( thisArray );
1,954✔
1818

1819
          elementRef = args[0];
1,954✔
1820

1821
          return ex.withContinuation( continuation, std::move( args ) );
1,954✔
1822
        }
1,954✔
1823
      };
386✔
1824

1825
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
772✔
1826
                                  std::move( args ) );
772✔
1827
    }
386✔
1828
    break;
9✔
1829

1830
  case MTH_REDUCE:
81✔
1831
    if ( name_arr.empty() )
81✔
1832
    {
1833
      if ( ex.numParams() < 1 )
78✔
1834
        return new BError( "Invalid parameter type" );
3✔
1835

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

1838
      if ( !param0 )
75✔
1839
        return new BError( "Invalid parameter type" );
3✔
1840

1841
      BObjectImp* accumulator;
1842
      int processed;
1843

1844
      // If an initial accumulator value was passed in, use it. Otherwise, use
1845
      // the first element of the array, erroring if the array is empty.
1846
      if ( ex.numParams() > 1 )
72✔
1847
      {
1848
        accumulator = ex.getParamImp( 1 );
63✔
1849
        processed = 1;
63✔
1850
      }
1851
      else if ( ref_arr.empty() )
9✔
1852
      {
1853
        return new BError( "Reduce of empty array with no initial value" );
3✔
1854
      }
1855
      else
1856
      {
1857
        accumulator = ref_arr[0]->impptr();
6✔
1858
        processed = 2;
6✔
1859
      }
1860

1861
      // Return the accumulator if there is no more to process, eg:
1862
      // {}.reduce(@{}, "accum") or {"accum"}.reduce(@{})
1863
      if ( processed > static_cast<int>( ref_arr.size() ) )
69✔
1864
      {
1865
        return accumulator;
6✔
1866
      }
1867

1868
      // Arguments for user function call.
1869
      // - accumulator
1870
      // - current value
1871
      // - current index
1872
      // - the array itself
1873
      BObjectRefVec args;
63✔
1874
      args.push_back( BObjectRef( accumulator ) );
63✔
1875
      args.push_back( BObjectRef( ref_arr[processed - 1] ) );
63✔
1876
      args.push_back( BObjectRef( new BLong( processed ) ) );
63✔
1877
      args.push_back( BObjectRef( this ) );
63✔
1878

1879
      auto callback = [thisArray = args[3], processed = processed,
63✔
1880
                       initialSize = static_cast<int>( ref_arr.size() )](
63✔
1881
                          Executor& ex, BContinuation* continuation,
1882
                          BObjectRef result /* accumulator */ ) mutable -> BObjectImp*
7,993✔
1883
      {
1884
        if ( !thisArray->isa( OTArray ) )
1,649✔
1885
          return result->impptr();
×
1886

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

1889
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
1,649✔
1890
        {
1891
          return result->impptr();
63✔
1892
        }
1893
        else
1894
        {
1895
          ++processed;
1,586✔
1896

1897
          BObjectRefVec args;
1,586✔
1898
          args.push_back( result );
1,586✔
1899
          args.push_back( ref_arr[processed - 1] );
1,586✔
1900
          args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
1,586✔
1901
          args.push_back( thisArray );
1,586✔
1902

1903
          return ex.withContinuation( continuation, std::move( args ) );
1,586✔
1904
        }
1,586✔
1905
      };
63✔
1906

1907
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
126✔
1908
                                  std::move( args ) );
126✔
1909
    }
63✔
1910
    break;
3✔
1911

1912
  case MTH_FIND:
25✔
1913
    if ( name_arr.empty() )
25✔
1914
    {
1915
      if ( ex.numParams() < 1 )
25✔
1916
        return new BError( "Invalid parameter type" );
3✔
1917

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

1920
      if ( !param0 )
22✔
1921
        return new BError( "Invalid parameter type" );
3✔
1922

1923
      if ( ref_arr.empty() )
19✔
1924
        return new ObjArray();
6✔
1925

1926
      // Arguments for user function call.
1927
      // - the element
1928
      // - the index of the element
1929
      // - the array itself
1930
      BObjectRefVec args;
13✔
1931
      args.push_back( ref_arr.front() );
13✔
1932
      args.push_back( BObjectRef( new BLong( 1 ) ) );
13✔
1933
      args.push_back( BObjectRef( this ) );
13✔
1934

1935
      auto callback = [elementRef = args[0], processed = 1, thisArray = args[2],
13✔
1936
                       initialSize = static_cast<int>( ref_arr.size() )](
13✔
1937
                          Executor& ex, BContinuation* continuation,
1938
                          BObjectRef result ) mutable -> BObjectImp*
115✔
1939
      {
1940
        if ( result->isTrue() )
41✔
1941
        {
1942
          return elementRef->impptr();
10✔
1943
        }
1944

1945
        if ( !thisArray->isa( OTArray ) )
31✔
1946
          return UninitObject::create();
×
1947

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

1950
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
31✔
1951
        {
1952
          return UninitObject::create();
3✔
1953
        }
1954
        else
1955
        {
1956
          ++processed;
28✔
1957

1958
          BObjectRefVec args;
28✔
1959
          args.push_back( ref_arr[processed - 1] );
28✔
1960
          args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
28✔
1961
          args.push_back( thisArray );
28✔
1962

1963
          elementRef = args[0];
28✔
1964

1965
          return ex.withContinuation( continuation, std::move( args ) );
28✔
1966
        }
28✔
1967
      };
13✔
1968

1969
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
26✔
1970
                                  std::move( args ) );
26✔
1971
    }
13✔
1972
    break;
×
1973

1974
  case MTH_FINDINDEX:
78✔
1975
    if ( name_arr.empty() )
78✔
1976
    {
1977
      if ( ex.numParams() < 1 )
75✔
1978
        return new BError( "Invalid parameter type" );
3✔
1979

1980
      BObjectImp* param0 = ex.getParamImp( 0, BObjectType::OTFuncRef );
72✔
1981

1982
      if ( !param0 )
72✔
1983
        return new BError( "Invalid parameter type" );
3✔
1984

1985
      if ( ref_arr.empty() )
69✔
1986
        return new BLong( 0 );
3✔
1987

1988
      // Arguments for user function call.
1989
      // - the element
1990
      // - the index of the element
1991
      // - the array itself
1992
      BObjectRefVec args;
66✔
1993
      args.push_back( ref_arr.front() );
66✔
1994
      args.push_back( BObjectRef( new BLong( 1 ) ) );
66✔
1995
      args.push_back( BObjectRef( this ) );
66✔
1996

1997
      auto callback =
66✔
1998
          [processed = 1, thisArray = args[2], initialSize = static_cast<int>( ref_arr.size() )](
66✔
1999
              Executor& ex, BContinuation* continuation, BObjectRef result ) mutable -> BObjectImp*
11,210✔
2000
      {
2001
        if ( result->isTrue() )
2,852✔
2002
        {
2003
          return new BLong( processed );
63✔
2004
        }
2005

2006
        if ( !thisArray->isa( OTArray ) )
2,789✔
2007
          return new BLong( 0 );
×
2008

2009
        const auto& ref_arr = thisArray->impptr<ObjArray>()->ref_arr;
2,789✔
2010

2011
        if ( processed >= initialSize || processed >= static_cast<int>( ref_arr.size() ) )
2,789✔
2012
        {
2013
          return new BLong( 0 );
3✔
2014
        }
2015
        else
2016
        {
2017
          ++processed;
2,786✔
2018

2019
          BObjectRefVec args;
2,786✔
2020
          args.push_back( ref_arr[processed - 1] );
2,786✔
2021
          args.push_back( BObjectRef( new BObject( new BLong( processed ) ) ) );
2,786✔
2022
          args.push_back( thisArray );
2,786✔
2023

2024
          return ex.withContinuation( continuation, std::move( args ) );
2,786✔
2025
        }
2,786✔
2026
      };
66✔
2027

2028
      return ex.makeContinuation( BObjectRef( new BObject( param0 ) ), std::move( callback ),
132✔
2029
                                  std::move( args ) );
132✔
2030
    }
66✔
2031
    break;
3✔
2032

2033
  case MTH_CYCLE:
×
2034
    if ( name_arr.empty() )
×
2035
    {
2036
      int shift_by;
2037

2038
      if ( ex.numParams() > 0 )
×
2039
      {
2040
        if ( !ex.getParam( 0, shift_by ) )
×
2041
          return new BError( "Invalid parameter type" );
×
2042
        if ( shift_by == 0 )
×
2043
          return new BLong( 0 );
×
2044
      }
2045
      else
2046
        shift_by = 1;
×
2047

2048
      if ( ref_arr.empty() || std::abs( shift_by ) > (int)ref_arr.size() )
×
2049
        return new BLong( 0 );
×
2050

2051
      if ( shift_by > 0 )
×
2052
        std::rotate( ref_arr.begin(), ref_arr.end() - shift_by, ref_arr.end() );
×
2053
      else
2054
        std::rotate( ref_arr.begin(), ref_arr.begin() - shift_by, ref_arr.end() );
×
2055

2056
      return new BLong( 1 );
×
2057
    }
2058
    break;
×
2059

2060
  case MTH_SORTEDINSERT:
18✔
2061
  {
2062
    if ( !name_arr.empty() )
18✔
2063
      break;
×
2064
    if ( ex.numParams() == 0 )
18✔
2065
      return new BError(
2066
          "array.sorted_insert(obj, sub_index:=0, reverse:=0) takes at least one parameter." );
18✔
2067
    BObjectImp* imp = ex.getParamImp( 0 );
18✔
2068
    if ( !imp )
18✔
2069
      return new BError( "Invalid parameter type" );
×
2070
    bool reverse = false;
18✔
2071
    int sub_index = 0;
18✔
2072
    if ( ex.numParams() >= 2 )
18✔
2073
    {
2074
      if ( !ex.getParam( 1, sub_index ) )
15✔
2075
        return new BError( "Invalid parameter type" );
×
2076
      if ( sub_index < 0 )
15✔
2077
        return new BError( "Invalid sub_index value" );
×
2078
    }
2079
    if ( ex.numParams() >= 3 )
18✔
2080
    {
2081
      int reverseparam;
2082
      if ( !ex.getParam( 2, reverseparam ) )
9✔
2083
        return new BError( "Invalid parameter type" );
×
2084
      reverse = reverseparam != 0;
9✔
2085
    }
2086
    BObjectRef item( new BObject( imp->copy() ) );
18✔
2087
    if ( !sub_index )
18✔
2088
    {
2089
      if ( reverse )
9✔
2090
      {
2091
        ref_arr.insert( std::lower_bound( ref_arr.begin(), ref_arr.end(), item,
3✔
2092
                                          []( const BObjectRef& x1, const BObjectRef& x2 ) -> bool
9✔
2093
                                          {
2094
                                            const BObject* b1 = x1.get();
9✔
2095
                                            const BObject* b2 = x2.get();
9✔
2096
                                            if ( b1 == nullptr || b2 == nullptr )
9✔
2097
                                              return ( &x1 > &x2 );
×
2098
                                            const BObject& r1 = *b1;
9✔
2099
                                            const BObject& r2 = *b2;
9✔
2100
                                            return ( r1 > r2 );
9✔
2101
                                          } ),
2102
                        item );
2103
      }
2104
      else
2105
      {
2106
        ref_arr.insert( std::upper_bound( ref_arr.begin(), ref_arr.end(), item, objref_cmp() ),
6✔
2107
                        item );
2108
      }
2109
    }
2110
    else
2111
    {
2112
      auto cmp_func = [=]( const BObjectRef& x1, const BObjectRef& x2 ) -> bool
21✔
2113
      {
2114
        if ( x1.get() == nullptr || !x1.get()->isa( OTArray ) )
21✔
2115
          return false;
×
2116
        if ( x2.get() == nullptr || !x2.get()->isa( OTArray ) )
21✔
2117
          return false;
×
2118
        auto sub_arr1 = x1.get()->impptr<ObjArray>();
21✔
2119
        auto sub_arr2 = x2.get()->impptr<ObjArray>();
21✔
2120
        if ( sub_arr1->ref_arr.size() < static_cast<size_t>( sub_index ) )
21✔
2121
          return false;
×
2122
        if ( sub_arr2->ref_arr.size() < static_cast<size_t>( sub_index ) )
21✔
2123
          return false;
×
2124
        auto sub1 = sub_arr1->ref_arr[sub_index - 1];
21✔
2125
        auto sub2 = sub_arr2->ref_arr[sub_index - 1];
21✔
2126
        const BObject* b1 = sub1.get();
21✔
2127
        const BObject* b2 = sub2.get();
21✔
2128
        if ( !reverse )
21✔
2129
        {
2130
          if ( b1 == nullptr || b2 == nullptr )
15✔
2131
            return ( &x1 < &x2 );
×
2132
          return ( *b1 < *b2 );
15✔
2133
        }
2134
        else
2135
        {
2136
          if ( b1 == nullptr || b2 == nullptr )
6✔
2137
            return ( &x1 > &x2 );
×
2138
          return ( *b1 > *b2 );
6✔
2139
        }
2140
      };
21✔
2141
      if ( reverse )
9✔
2142
      {
2143
        ref_arr.insert( std::lower_bound( ref_arr.begin(), ref_arr.end(), item, cmp_func ), item );
3✔
2144
      }
2145
      else
2146
      {
2147
        ref_arr.insert( std::upper_bound( ref_arr.begin(), ref_arr.end(), item, cmp_func ), item );
6✔
2148
      }
2149
    }
2150
    return new BLong( 1 );
18✔
2151
    break;
2152
  }
18✔
2153
  default:
×
2154
    return nullptr;
×
2155
  }
2156
  return nullptr;
45✔
2157
}
2158

2159
BObjectImp* ObjArray::call_method( const char* methodname, Executor& ex )
3✔
2160
{
2161
  ObjMethod* objmethod = getKnownObjMethod( methodname );
3✔
2162
  if ( objmethod != nullptr )
3✔
2163
    return this->call_method_id( objmethod->id, ex );
×
2164
  else
2165
    return nullptr;
3✔
2166
}
2167

2168
void ObjArray::packonto( std::ostream& os ) const
41✔
2169
{
2170
  os << "a" << ref_arr.size() << ":";
41✔
2171
  for ( const auto& elem : ref_arr )
173✔
2172
  {
2173
    if ( elem.get() )
132✔
2174
    {
2175
      BObject* bo = elem.get();
132✔
2176
      bo->impptr()->packonto( os );
132✔
2177
    }
2178
    else
2179
    {
2180
      os << "x";
×
2181
    }
2182
  }
2183
}
41✔
2184

2185
BObjectImp* ObjArray::unpack( std::istream& is )
19✔
2186
{
2187
  unsigned arrsize;
2188
  char colon;
2189
  if ( !( is >> arrsize >> colon ) )
19✔
2190
  {
2191
    return new BError( "Unable to unpack array elemcount" );
×
2192
  }
2193
  if ( (int)arrsize < 0 )
19✔
2194
  {
2195
    return new BError( "Unable to unpack array elemcount. Invalid length!" );
×
2196
  }
2197
  if ( colon != ':' )
19✔
2198
  {
2199
    return new BError( "Unable to unpack array elemcount. Bad format. Colon not found!" );
×
2200
  }
2201
  std::unique_ptr<ObjArray> arr( new ObjArray );
19✔
2202
  arr->ref_arr.resize( arrsize );
19✔
2203
  for ( unsigned i = 0; i < arrsize; ++i )
93✔
2204
  {
2205
    BObjectImp* imp = BObjectImp::unpack( is );
74✔
2206
    if ( imp != nullptr && !imp->isa( OTUninit ) )
74✔
2207
    {
2208
      arr->ref_arr[i].set( new BObject( imp ) );
74✔
2209
    }
2210
  }
2211
  return arr.release();
19✔
2212
}
19✔
2213

2214
BApplicPtr::BApplicPtr( const BApplicObjType* pointer_type, void* ptr )
×
2215
    : BObjectImp( OTApplicPtr ), ptr_( ptr ), pointer_type_( pointer_type )
×
2216
{
2217
}
×
2218

2219
BObjectImp* BApplicPtr::copy() const
×
2220
{
2221
  return new BApplicPtr( pointer_type_, ptr_ );
×
2222
}
2223

2224
size_t BApplicPtr::sizeEstimate() const
×
2225
{
2226
  return sizeof( BApplicPtr );
×
2227
}
2228

2229
const BApplicObjType* BApplicPtr::pointer_type() const
×
2230
{
2231
  return pointer_type_;
×
2232
}
2233

2234
void* BApplicPtr::ptr() const
×
2235
{
2236
  return ptr_;
×
2237
}
2238

2239
std::string BApplicPtr::getStringRep() const
×
2240
{
2241
  return "<appptr>";
×
2242
}
2243

2244

2245
void BApplicPtr::printOn( std::ostream& os ) const
×
2246
{
2247
  os << "<appptr>";
×
2248
}
×
2249

2250
std::string BApplicObjBase::getStringRep() const
161✔
2251
{
2252
  return std::string( "<appobj:" ) + typeOf() + ">";
322✔
2253
}
2254

2255
void BApplicObjBase::printOn( std::ostream& os ) const
×
2256
{
2257
  os << getStringRep();
×
2258
}
×
2259

2260
#if BOBJECTIMP_DEBUG
2261
BBoolean::BBoolean( bool bval ) : BObjectImp( OTBoolean ), bval_( bval ) {}
2262
BBoolean::BBoolean( const BBoolean& B ) : BBoolean( B.bval_ ) {}
2263
#endif
2264

2265
BObjectImp* BBoolean::unpack( std::istream& is )
12✔
2266
{
2267
  int lv;
2268
  if ( is >> lv )
12✔
2269
  {
2270
    return new BBoolean( lv != 0 );
12✔
2271
  }
2272
  else
2273
  {
2274
    return new BError( "Error extracting Boolean value" );
×
2275
  }
2276
}
2277

2278
void BBoolean::packonto( std::ostream& os ) const
×
2279
{
2280
  os << "b" << ( bval_ ? 1 : 0 );
×
2281
}
×
2282

2283
std::string BBoolean::pack() const
24✔
2284
{
2285
  OSTRINGSTREAM os;
24✔
2286
  os << "b" << ( bval_ ? 1 : 0 );
24✔
2287
  return OSTRINGSTREAM_STR( os );
48✔
2288
}
24✔
2289

2290
BObjectImp* BBoolean::copy() const
238✔
2291
{
2292
  return new BBoolean( *this );
238✔
2293
}
2294

2295
size_t BBoolean::sizeEstimate() const
56✔
2296
{
2297
  return sizeof( BBoolean );
56✔
2298
}
2299

2300
bool BBoolean::isTrue() const
525✔
2301
{
2302
  return bval_;
525✔
2303
}
2304

2305
bool BBoolean::operator==( const BObjectImp& objimp ) const
42✔
2306
{
2307
  return bval_ == objimp.isTrue();
42✔
2308
}
2309

2310
std::string BBoolean::getStringRep() const
60✔
2311
{
2312
  return bval_ ? "true" : "false";
60✔
2313
}
2314

2315
BFunctionRef::BFunctionRef( ref_ptr<EScriptProgram> program, unsigned function_reference_index,
2,933✔
2316
                            std::shared_ptr<ValueStackCont> globals, ValueStackCont&& captures )
2,933✔
2317
    : BObjectImp( OTFuncRef ),
2318
      prog_( std::move( program ) ),
2,933✔
2319
      function_reference_index_( function_reference_index ),
2,933✔
2320
      globals( std::move( globals ) ),
2,933✔
2321
      captures( std::move( captures ) )
5,866✔
2322
{
2323
  passert( function_reference_index_ < prog_->function_references.size() );
2,933✔
2324
}
2,933✔
2325

2326
BFunctionRef::BFunctionRef( const BFunctionRef& B )
688✔
2327
    : BFunctionRef( B.prog_, B.function_reference_index_, B.globals, ValueStackCont( B.captures ) )
688✔
2328
{
2329
}
688✔
2330

2331
BObjectImp* BFunctionRef::copy() const
688✔
2332
{
2333
  return new BFunctionRef( *this );
688✔
2334
}
2335

2336
size_t BFunctionRef::sizeEstimate() const
96✔
2337
{
2338
  return sizeof( BFunctionRef ) + Clib::memsize( captures ) + prog_->sizeEstimate();
96✔
2339
}
2340

2341
bool BFunctionRef::isTrue() const
3✔
2342
{
2343
  return false;
3✔
2344
}
2345

2346
bool BFunctionRef::operator==( const BObjectImp& /*objimp*/ ) const
×
2347
{
2348
  return false;
×
2349
}
2350

2351
BObjectImp* BFunctionRef::selfIsObjImp( const BObjectImp& other ) const
94✔
2352
{
2353
  auto classinstref = dynamic_cast<const BClassInstanceRef*>( &other );
94✔
2354
  if ( !classinstref )
94✔
2355
    return new BLong( 0 );
×
2356

2357
  auto classinst = classinstref->instance();
94✔
2358

2359
  // Class index could be maxint if the function reference is not a class
2360
  // method.
2361
  if ( class_index() >= prog_->class_descriptors.size() )
94✔
2362
    return new BLong( 0 );
×
2363

2364
  const auto& my_constructors = prog_->class_descriptors.at( class_index() ).constructors;
94✔
2365
  passert( !my_constructors.empty() );
94✔
2366
  const auto& my_descriptor = my_constructors.front();
94✔
2367

2368
  const auto& other_descriptors =
2369
      classinst->prog()->class_descriptors.at( classinst->index() ).constructors;
94✔
2370

2371
  // An optimization for same program: since strings are never duplicated inside
2372
  // the data section, we can just check for offset equality.
2373
  if ( prog_ == classinst->prog() )
94✔
2374
  {
2375
    for ( const auto& other_descriptor : other_descriptors )
195✔
2376
    {
2377
      if ( my_descriptor.type_tag_offset == other_descriptor.type_tag_offset )
180✔
2378
        return new BLong( 1 );
54✔
2379
    }
2380
  }
2381
  // For different programs, we must check for string equality.
2382
  else
2383
  {
2384
    auto type_tag = prog_->symbols.array() + my_descriptor.type_tag_offset;
25✔
2385
    for ( const auto& other_descriptor : other_descriptors )
63✔
2386
    {
2387
      auto other_type_tag = classinst->prog()->symbols.array() + other_descriptor.type_tag_offset;
51✔
2388
      if ( strcmp( type_tag, other_type_tag ) == 0 )
51✔
2389
        return new BLong( 1 );
13✔
2390
    }
2391
  }
2392

2393
  return new BLong( 0 );
27✔
2394
}
2395

2396
std::string BFunctionRef::getStringRep() const
117✔
2397
{
2398
  return "FunctionObject";
117✔
2399
}
2400

2401
BObjectImp* BFunctionRef::call_method( const char* methodname, Executor& ex )
21✔
2402
{
2403
  ObjMethod* objmethod = getKnownObjMethod( methodname );
21✔
2404
  if ( objmethod != nullptr )
21✔
2405
    return call_method_id( objmethod->id, ex );
21✔
2406
  return nullptr;
×
2407
}
2408

2409
bool BFunctionRef::validCall( const int id, Executor& ex, Instruction* inst ) const
11,987✔
2410
{
2411
  auto passed_args = static_cast<int>( ex.numParams() );
11,987✔
2412

2413
  auto [expected_min_args, expected_max_args] = expected_args();
11,987✔
2414

2415
  if ( id != MTH_CALL && id != MTH_NEW && id != MTH_CALL_METHOD )
11,987✔
2416
    return false;
×
2417

2418
  if ( id == MTH_NEW && !constructor() )
11,987✔
2419
    return false;
27✔
2420

2421
  if ( passed_args < expected_min_args || ( passed_args > expected_max_args && !variadic() ) )
11,960✔
2422
    return false;
99✔
2423

2424
  inst->func = &Executor::ins_nop;
11,861✔
2425

2426
  if ( passed_args >= expected_max_args )
11,861✔
2427
  {
2428
    inst->token.lval = pc();
11,680✔
2429
  }
2430
  else
2431
  {
2432
    auto default_parameter_address_index = expected_max_args - passed_args - 1;
181✔
2433
    passert( default_parameter_address_index >= 0 &&
181✔
2434
             default_parameter_address_index <
2435
                 static_cast<int>( default_parameter_addresses().size() ) );
2436
    inst->token.lval = default_parameter_addresses().at( default_parameter_address_index );
181✔
2437
  }
2438

2439
  return true;
11,861✔
2440
}
2441

2442
bool BFunctionRef::validCall( const char* methodname, Executor& ex, Instruction* inst ) const
×
2443
{
2444
  ObjMethod* objmethod = getKnownObjMethod( methodname );
×
2445
  if ( objmethod == nullptr )
×
2446
    return false;
×
2447
  return validCall( objmethod->id, ex, inst );
×
2448
}
2449

2450
int BFunctionRef::numParams() const
32,960✔
2451
{
2452
  return prog_->function_references[function_reference_index_].parameter_count;
32,960✔
2453
}
2454

2455
unsigned BFunctionRef::pc() const
11,680✔
2456
{
2457
  return prog_->function_references[function_reference_index_].address;
11,680✔
2458
}
2459

2460
bool BFunctionRef::variadic() const
22,223✔
2461
{
2462
  return prog_->function_references[function_reference_index_].is_variadic;
22,223✔
2463
}
2464

2465
ref_ptr<EScriptProgram> BFunctionRef::prog() const
11,952✔
2466
{
2467
  return prog_;
11,952✔
2468
}
2469

2470
unsigned BFunctionRef::class_index() const
269✔
2471
{
2472
  return prog_->function_references[function_reference_index_].class_index;
269✔
2473
}
2474

2475
bool BFunctionRef::constructor() const
270✔
2476
{
2477
  return prog_->function_references[function_reference_index_].is_constructor;
270✔
2478
}
2479

2480
bool BFunctionRef::class_method() const
599✔
2481
{
2482
  return prog_->function_references[function_reference_index_].class_index <
599✔
2483
         std::numeric_limits<unsigned>::max();
599✔
2484
}
2485

2486
const std::vector<unsigned>& BFunctionRef::default_parameter_addresses() const
24,534✔
2487
{
2488
  return prog_->function_references[function_reference_index_].default_parameter_addresses;
24,534✔
2489
}
2490

2491
int BFunctionRef::default_parameter_count() const
24,172✔
2492
{
2493
  return static_cast<int>( default_parameter_addresses().size() );
24,172✔
2494
}
2495

2496
std::pair<int, int> BFunctionRef::expected_args() const
12,086✔
2497
{
2498
  auto expected_min_args = numParams() - default_parameter_count();  // remove default parameters
12,086✔
2499

2500
  return { expected_min_args, expected_min_args + default_parameter_count() };
12,086✔
2501
}
2502

2503
BObjectImp* BFunctionRef::call_method_id( const int id, Executor& ex, bool /*forcebuiltin*/ )
126✔
2504
{
2505
  bool adjust_for_this = false;
126✔
2506

2507
  // These are only entered if `ins_call_method_id` did _not_ do the call jump.
2508
  switch ( id )
126✔
2509
  {
2510
  case MTH_NEW:
54✔
2511
    if ( !constructor() )
54✔
2512
      return new BError( "Function is not a constructor" );
27✔
2513
    // intentional fallthrough
2514
  case MTH_CALL_METHOD:
2515
    adjust_for_this = true;
48✔
2516
    // intentional fallthrough
2517
  case MTH_CALL:
99✔
2518
  {
2519
    auto [expected_min_args, expected_max_args] = expected_args();
99✔
2520
    auto param_count = ex.numParams();
99✔
2521

2522
    if ( adjust_for_this )
99✔
2523
    {
2524
      --expected_min_args;
48✔
2525
      --expected_max_args;
48✔
2526
      --param_count;
48✔
2527
    }
2528

2529
    auto expected_arg_string = variadic() ? fmt::format( "{}+", expected_min_args )
99✔
2530
                               : ( expected_min_args == expected_max_args )
63✔
2531
                                   ? std::to_string( expected_min_args )
63✔
2532
                                   : fmt::format( "{}-{}", expected_min_args, expected_max_args );
159✔
2533

2534
    return new BError( fmt::format( "Invalid argument count: expected {}, got {}",
×
2535
                                    expected_arg_string, param_count ) );
198✔
2536
  }
99✔
2537
  default:
×
2538
    return nullptr;
×
2539
  }
2540
}
2541

2542
BSpread::BSpread( BObjectRef obj ) : BObjectImp( OTSpread ), object( obj ) {}
2,101✔
2543

2544
BSpread::BSpread( const BSpread& B ) : BObjectImp( OTSpread ), object( B.object ) {}
×
2545

2546
size_t BSpread::sizeEstimate() const
×
2547
{
2548
  return sizeof( BSpread ) + object.sizeEstimate();
×
2549
}
2550

2551
BObjectImp* BSpread::copy() const
×
2552
{
2553
  return new BSpread( *this );
×
2554
}
2555

2556
bool BSpread::isTrue() const
×
2557
{
2558
  return object->isTrue();
×
2559
}
2560

2561
std::string BSpread::getStringRep() const
×
2562
{
2563
  return "Spread";
×
2564
}
2565

2566
}  // namespace Bscript
2567
}  // namespace Pol
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