ChaiScript / ChaiScript
1
// This file is distributed under the BSD License.
2
// See "license.txt" for details.
3
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
4
// and 2009-2018, Jason Turner (jason@emptycrate.com)
5
// http://www.chaiscript.com
6

7
#ifndef CHAISCRIPT_PRELUDE_HPP_
8
#define CHAISCRIPT_PRELUDE_HPP_
9

10
namespace chaiscript {
11
struct ChaiScript_Prelude {
12 1
  static std::string chaiscript_prelude() {  return R"chaiscript(
13

14
def lt(l, r) {
15
  if (call_exists(`<`, l, r)) {
16
    l < r
17
  } else {
18
    type_name(l) < type_name(r)
19
  }
20
}
21

22

23
def gt(l, r) {
24
  if (call_exists(`>`, l, r)) {
25
    l > r
26
  } else {
27
    type_name(l) > type_name(r)
28
  }
29
}
30

31
def eq(l, r) {
32
  if (call_exists(`==`, l, r)) {
33
    l == r
34
  } else {
35
    false
36
  }
37
}
38

39
def new(x) {
40
  eval(type_name(x))();
41
}
42

43
def clone(double x) {
44
  double(x).clone_var_attrs(x)
45
}
46

47
def clone(string x) {
48
  string(x).clone_var_attrs(x)
49
}
50

51
def clone(vector x) {
52
  vector(x).clone_var_attrs(x)
53
}
54

55

56
def clone(int x) {
57
  int(x).clone_var_attrs(x)
58
}
59

60
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
61
{
62
  eval(type_name(x))(x).clone_var_attrs(x);
63
}
64

65

66
# to_string for Pair()
67
def to_string(x) : call_exists(first, x) && call_exists(second, x) {
68
  "<" + x.first.to_string() + ", " + x.second.to_string() + ">";
69
}
70

71
# to_string for containers
72
def to_string(x) : call_exists(range, x) && !x.is_type("string"){
73
  "[" + x.join(", ") + "]";
74
}
75

76
# Prints to console with no carriage return
77
def puts(x) {
78
  print_string(x.to_string());
79
}
80

81
# Prints to console with carriage return
82
def print(x) {
83
  println_string(x.to_string());
84
}
85

86
# Returns the maximum value of two numbers
87
def max(a, b) {
88
  if (a>b) {
89
    a
90
  } else {
91
    b
92
  }
93
}
94

95
# Returns the minimum value of two numbers
96
def min(a, b)
97
{
98
  if (a<b)
99
  {
100
    a
101
  } else {
102
    b
103
  }
104
}
105

106

107
# Returns true if the value is odd
108
def odd(x)  {
109
  if (x % 2 == 1)
110
  {
111
    true
112
  } else {
113
    false
114
  }
115
}
116

117

118
# Returns true if the value is even
119
def even(x)
120
{
121
  if (x % 2 == 0)
122
  {
123
    true
124
  } else {
125
    false
126
  }
127
}
128

129

130
# Inserts the third value at the position of the second value into the container of the first
131
# while making a clone.
132
def insert_at(container, pos, x)
133
{
134
  container.insert_ref_at(pos, clone(x));
135
}
136

137
# Returns the reverse of the given container
138
def reverse(container) {
139
  auto retval := new(container);
140
  auto r := range(container);
141
  while (!r.empty()) {
142
    retval.push_back(r.back());
143
    r.pop_back();
144
  }
145
  retval;
146
}
147

148

149
def range(r) : call_exists(range_internal, r)
150
{
151
  var ri := range_internal(r);
152
  ri.get_var_attr("internal_obj") := r;
153
  ri;
154
}
155

156
# Return a range from a range
157
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
158
{
159
  clone(r);
160
}
161

162

163
# The retro attribute that contains the underlying range
164
attr retro::m_range;
165

166
# Creates a retro from a retro by returning the original range
167
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro"
168
{
169
  clone(r.m_range)
170
}
171

172

173
# Creates a retro range from a range
174
def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
175
{
176
  this.m_range = r;
177
}
178

179
# Returns the first value of a retro
180
def retro::front()
181
{
182
  back(this.m_range)
183
}
184

185
# Returns the last value of a retro
186
def retro::back()
187
{
188
  front(this.m_range)
189
}
190

191
# Moves the back iterator of a retro towards the front by one
192
def retro::pop_back()
193
{
194
  pop_front(this.m_range)
195
}
196

197
# Moves the front iterator of a retro towards the back by one
198
def retro::pop_front()
199
{
200
  pop_back(this.m_range)
201
}
202

203
# returns true if the retro is out of elements
204
def retro::empty()
205
{
206
  empty(this.m_range);
207
}
208

209
# Performs the second value function over the container first value
210
def for_each(container, func) : call_exists(range, container) {
211
  var t_range := range(container);
212
  while (!t_range.empty()) {
213
    func(t_range.front());
214
    t_range.pop_front();
215
  }
216
}
217

218
def any_of(container, func) : call_exists(range, container) {
219
  var t_range := range(container);
220
  while (!t_range.empty()) {
221
    if (func(t_range.front())) {
222
      return true;
223
    }
224
    t_range.pop_front();
225
  }
226
  false;
227
}
228

229
def all_of(container, func) : call_exists(range, container) {
230
  var t_range := range(container);
231
  while (!t_range.empty()) {
232
    if (!func(t_range.front())) {
233
      return false;
234
    }
235
    t_range.pop_front();
236
  }
237

238
  true;
239
}
240

241
def back_inserter(container) {
242
  bind(push_back, container, _);
243
}
244

245
def contains(container, item, compare_func) : call_exists(range, container) {
246
  auto t_range := range(container);
247
  while (!t_range.empty()) {
248
    if ( compare_func(t_range.front(), item) ) {
249
      return true;
250
    }
251

252
    t_range.pop_front();
253
  }
254
  false;
255
}
256

257
def contains(container, item) {
258
  contains(container, item, eq)
259
}
260

261
def map(container, func, inserter) : call_exists(range, container) {
262
  auto range := range(container);
263
  while (!range.empty()) {
264
    inserter(func(range.front()));
265
    range.pop_front();
266
  }
267
}
268

269
# Performs the second value function over the container first value. Creates a new container with the results
270
def map(container, func) {
271
  auto retval := new(container);
272
  map(container, func, back_inserter(retval));
273
  retval;
274
}
275

276
# Performs the second value function over the container first value. Starts with initial and continues with each element.
277
def foldl(container, func, initial) : call_exists(range, container){
278
  auto retval = initial;
279
  auto range := range(container);
280
  while (!range.empty()) {
281
    retval = (func(range.front(), retval));
282
    range.pop_front();
283
  }
284
  retval;
285
}
286

287
# Returns the sum of the elements of the given value
288
def sum(container) {
289
  foldl(container, `+`, 0.0)
290
}
291

292
# Returns the product of the elements of the given value
293
def product(container) {
294
  foldl(container, `*`, 1.0)
295
}
296

297
# Returns a new container with the elements of the first value concatenated with the elements of the second value
298
def concat(x, y) : call_exists(clone, x) {
299
  auto retval = x;
300
  auto inserter := back_inserter(retval);
301
  auto range := range(y);
302
  while (!range.empty()) {
303
    inserter(range.front());
304
    range.pop_front();
305
  }
306
  retval;
307
}
308

309

310
def take(container, num, inserter) : call_exists(range, container) {
311
  auto r := range(container);
312
  auto i = num;
313
  while ((i > 0) && (!r.empty())) {
314
    inserter(r.front());
315
    r.pop_front();
316
    --i;
317
  }
318
}
319

320

321
# Returns a new container with the given number of elements taken from the container
322
def take(container, num) {
323
  auto retval := new(container);
324
  take(container, num, back_inserter(retval));
325
  retval;
326
}
327

328

329
def take_while(container, f, inserter) : call_exists(range, container) {
330
  auto r := range(container);
331
  while ((!r.empty()) && f(r.front())) {
332
    inserter(r.front());
333
    r.pop_front();
334
  }
335
}
336

337

338
# Returns a new container with the given elements match the second value function
339
def take_while(container, f) {
340
  auto retval := new(container);
341
  take_while(container, f, back_inserter(retval));
342
  retval;
343
}
344

345

346
def drop(container, num, inserter) : call_exists(range, container) {
347
  auto r := range(container);
348
  auto i = num;
349
  while ((i > 0) && (!r.empty())) {
350
    r.pop_front();
351
    --i;
352
  }
353
  while (!r.empty()) {
354
    inserter(r.front());
355
    r.pop_front();
356
  }
357
}
358

359

360
# Returns a new container with the given number of elements dropped from the given container
361
def drop(container, num) {
362
  auto retval := new(container);
363
  drop(container, num, back_inserter(retval));
364
  retval;
365
}
366

367

368
def drop_while(container, f, inserter) : call_exists(range, container) {
369
  auto r := range(container);
370
  while ((!r.empty())&& f(r.front())) {
371
    r.pop_front();
372
  }
373
  while (!r.empty()) {
374
    inserter(r.front());
375
    r.pop_front();
376
  }
377
}
378

379

380
# Returns a new container with the given elements dropped that match the second value function
381
def drop_while(container, f) {
382
  auto retval := new(container);
383
  drop_while(container, f, back_inserter(retval));
384
  retval;
385
}
386

387

388
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.
389
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
390
  auto r := range(container);
391
  auto retval = r.front();
392
  r.pop_front();
393
  retval = func(retval, r.front());
394
  r.pop_front();
395
  while (!r.empty()) {
396
    retval = func(retval, r.front());
397
    r.pop_front();
398
  }
399
  retval;
400
}
401

402

403
# Returns a string of the elements in container delimited by the second value string
404
def join(container, delim) {
405
  auto retval = "";
406
  auto range := range(container);
407
  if (!range.empty()) {
408
    retval += to_string(range.front());
409
    range.pop_front();
410
    while (!range.empty()) {
411
      retval += delim;
412
      retval += to_string(range.front());
413
      range.pop_front();
414
    }
415
  }
416
  retval;
417
}
418

419

420
def filter(container, f, inserter) : call_exists(range, container) {
421
  auto r := range(container);
422
  while (!r.empty()) {
423
    if (f(r.front())) {
424
      inserter(r.front());
425
    }
426
    r.pop_front();
427
  }
428
}
429

430

431
# Returns a new Vector which match the second value function
432
def filter(container, f) {
433
  auto retval := new(container);
434
  filter(container, f, back_inserter(retval));
435
  retval;
436
}
437

438

439
def generate_range(x, y, inserter) {
440
  auto i = x;
441
  while (i <= y) {
442
    inserter(i);
443
    ++i;
444
  }
445
}
446

447

448
# Returns a new Vector which represents the range from the first value to the second value
449
def generate_range(x, y) {
450
  auto retval := Vector();
451
  generate_range(x,y,back_inserter(retval));
452
  retval;
453
}
454

455

456
# Returns a new Vector with the first value to the second value as its elements
457
def collate(x, y) {
458
  return [x, y];
459
}
460

461

462
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) {
463
  auto r_x := range(x);
464
  auto r_y := range(y);
465
  while (!r_x.empty() && !r_y.empty()) {
466
    inserter(f(r_x.front(), r_y.front()));
467
    r_x.pop_front();
468
    r_y.pop_front();
469
  }
470
}
471

472

473
# Returns a new Vector which joins matching elements of the second and third value with the first value function
474
def zip_with(f, x, y) {
475
  auto retval := Vector();
476
  zip_with(f,x,y,back_inserter(retval));
477
  retval;
478
}
479

480

481
# Returns a new Vector which joins matching elements of the first and second
482
def zip(x, y) {
483
  zip_with(collate, x, y);
484
}
485

486

487
# Returns the position of the second value string in the first value string
488
def string::find(string substr) {
489
  find(this, substr, size_t(0));
490
}
491

492

493
# Returns the position of last match of the second value string in the first value string
494
def string::rfind(string substr) {
495
  rfind(this, substr, size_t(-1));
496
}
497

498

499
# Returns the position of the first match of elements in the second value string in the first value string
500
def string::find_first_of(string list) {
501
  find_first_of(this, list, size_t(0));
502
}
503

504

505
# Returns the position of the last match of elements in the second value string in the first value string
506
def string::find_last_of(string list) {
507
  find_last_of(this, list, size_t(-1));
508
}
509

510

511
# Returns the position of the first non-matching element in the second value string in the first value string
512
def string::find_first_not_of(string list) {
513
  find_first_not_of(this, list, size_t(0));
514
}
515

516

517
# Returns the position of the last non-matching element in the second value string in the first value string
518
def string::find_last_not_of(string list) {
519
  find_last_not_of(this, list, size_t(-1));
520
}
521

522

523
def string::ltrim() {
524
  drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'});
525
}
526

527

528
def string::rtrim() {
529
  reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}));
530
}
531

532

533
def string::trim() {
534
  ltrim(rtrim(this));
535
}
536

537

538
def find(container, value, Function compare_func) : call_exists(range, container) {
539
  auto range := range(container);
540
  while (!range.empty()) {
541
    if (compare_func(range.front(), value)) {
542
      return range;
543
    } else {
544
      range.pop_front();
545
    }
546
  }
547
  range;
548
}
549

550

551
def find(container, value) {
552
  find(container, value, eq)
553
}
554

555

556
)chaiscript";
557
}
558

559
};
560
}
561

562
#endif /* CHAISCRIPT_PRELUDE_HPP_ */

Read our documentation on viewing source code .

Loading