ChaiScript
chaiscript_prelude.hpp
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 {
12  static std::string chaiscript_prelude() {
13  return R"chaiscript(
14 
15 def lt(l, r) {
16  if (call_exists(`<`, l, r)) {
17  l < r
18  } else {
19  type_name(l) < type_name(r)
20  }
21 }
22 
23 
24 def gt(l, r) {
25  if (call_exists(`>`, l, r)) {
26  l > r
27  } else {
28  type_name(l) > type_name(r)
29  }
30 }
31 
32 def eq(l, r) {
33  if (call_exists(`==`, l, r)) {
34  l == r
35  } else {
36  false
37  }
38 }
39 
40 def new(x) {
41  eval(type_name(x))();
42 }
43 
44 def clone(double x) {
45  double(x).clone_var_attrs(x)
46 }
47 
48 def clone(string x) {
49  string(x).clone_var_attrs(x)
50 }
51 
52 def clone(vector x) {
53  vector(x).clone_var_attrs(x)
54 }
55 
56 
57 def clone(int x) {
58  int(x).clone_var_attrs(x)
59 }
60 
61 def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
62 {
63  eval(type_name(x))(x).clone_var_attrs(x);
64 }
65 
66 
67 # to_string for Pair()
68 def to_string(x) : call_exists(first, x) && call_exists(second, x) {
69  "<" + x.first.to_string() + ", " + x.second.to_string() + ">";
70 }
71 
72 # to_string for containers
73 def to_string(x) : call_exists(range, x) && !x.is_type("string"){
74  "[" + x.join(", ") + "]";
75 }
76 
77 # Prints to console with no carriage return
78 def puts(x) {
79  print_string(x.to_string());
80 }
81 
82 # Prints to console with carriage return
83 def print(x) {
84  println_string(x.to_string());
85 }
86 
87 # Returns the maximum value of two numbers
88 def max(a, b) {
89  if (a>b) {
90  a
91  } else {
92  b
93  }
94 }
95 
96 # Returns the minimum value of two numbers
97 def min(a, b)
98 {
99  if (a<b)
100  {
101  a
102  } else {
103  b
104  }
105 }
106 
107 
108 # Returns true if the value is odd
109 def odd(x) {
110  if (x % 2 == 1)
111  {
112  true
113  } else {
114  false
115  }
116 }
117 
118 
119 # Returns true if the value is even
120 def even(x)
121 {
122  if (x % 2 == 0)
123  {
124  true
125  } else {
126  false
127  }
128 }
129 
130 
131 # Inserts the third value at the position of the second value into the container of the first
132 # while making a clone.
133 def insert_at(container, pos, x)
134 {
135  container.insert_ref_at(pos, clone(x));
136 }
137 
138 # Returns the reverse of the given container
139 def reverse(container) {
140  auto retval := new(container);
141  auto r := range(container);
142  while (!r.empty()) {
143  retval.push_back(r.back());
144  r.pop_back();
145  }
146  retval;
147 }
148 
149 
150 def range(r) : call_exists(range_internal, r)
151 {
152  var ri := range_internal(r);
153  ri.get_var_attr("internal_obj") := r;
154  ri;
155 }
156 
157 # Return a range from a range
158 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)
159 {
160  clone(r);
161 }
162 
163 
164 # The retro attribute that contains the underlying range
165 attr retro::m_range;
166 
167 # Creates a retro from a retro by returning the original range
168 def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro"
169 {
170  clone(r.m_range)
171 }
172 
173 
174 # Creates a retro range from a range
175 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)
176 {
177  this.m_range = r;
178 }
179 
180 # Returns the first value of a retro
181 def retro::front()
182 {
183  back(this.m_range)
184 }
185 
186 # Returns the last value of a retro
187 def retro::back()
188 {
189  front(this.m_range)
190 }
191 
192 # Moves the back iterator of a retro towards the front by one
193 def retro::pop_back()
194 {
195  pop_front(this.m_range)
196 }
197 
198 # Moves the front iterator of a retro towards the back by one
199 def retro::pop_front()
200 {
201  pop_back(this.m_range)
202 }
203 
204 # returns true if the retro is out of elements
205 def retro::empty()
206 {
207  empty(this.m_range);
208 }
209 
210 # Performs the second value function over the container first value
211 def for_each(container, func) : call_exists(range, container) {
212  var t_range := range(container);
213  while (!t_range.empty()) {
214  func(t_range.front());
215  t_range.pop_front();
216  }
217 }
218 
219 def any_of(container, func) : call_exists(range, container) {
220  var t_range := range(container);
221  while (!t_range.empty()) {
222  if (func(t_range.front())) {
223  return true;
224  }
225  t_range.pop_front();
226  }
227  false;
228 }
229 
230 def all_of(container, func) : call_exists(range, container) {
231  var t_range := range(container);
232  while (!t_range.empty()) {
233  if (!func(t_range.front())) {
234  return false;
235  }
236  t_range.pop_front();
237  }
238 
239  true;
240 }
241 
242 def back_inserter(container) {
243  bind(push_back, container, _);
244 }
245 
246 def contains(container, item, compare_func) : call_exists(range, container) {
247  auto t_range := range(container);
248  while (!t_range.empty()) {
249  if ( compare_func(t_range.front(), item) ) {
250  return true;
251  }
252 
253  t_range.pop_front();
254  }
255  false;
256 }
257 
258 def contains(container, item) {
259  contains(container, item, eq)
260 }
261 
262 def map(container, func, inserter) : call_exists(range, container) {
263  auto range := range(container);
264  while (!range.empty()) {
265  inserter(func(range.front()));
266  range.pop_front();
267  }
268 }
269 
270 # Performs the second value function over the container first value. Creates a new container with the results
271 def map(container, func) {
272  auto retval := new(container);
273  map(container, func, back_inserter(retval));
274  retval;
275 }
276 
277 # Performs the second value function over the container first value. Starts with initial and continues with each element.
278 def foldl(container, func, initial) : call_exists(range, container){
279  auto retval = initial;
280  auto range := range(container);
281  while (!range.empty()) {
282  retval = (func(range.front(), retval));
283  range.pop_front();
284  }
285  retval;
286 }
287 
288 # Returns the sum of the elements of the given value
289 def sum(container) {
290  foldl(container, `+`, 0.0)
291 }
292 
293 # Returns the product of the elements of the given value
294 def product(container) {
295  foldl(container, `*`, 1.0)
296 }
297 
298 # Returns a new container with the elements of the first value concatenated with the elements of the second value
299 def concat(x, y) : call_exists(clone, x) {
300  auto retval = x;
301  auto inserter := back_inserter(retval);
302  auto range := range(y);
303  while (!range.empty()) {
304  inserter(range.front());
305  range.pop_front();
306  }
307  retval;
308 }
309 
310 
311 def take(container, num, inserter) : call_exists(range, container) {
312  auto r := range(container);
313  auto i = num;
314  while ((i > 0) && (!r.empty())) {
315  inserter(r.front());
316  r.pop_front();
317  --i;
318  }
319 }
320 
321 
322 # Returns a new container with the given number of elements taken from the container
323 def take(container, num) {
324  auto retval := new(container);
325  take(container, num, back_inserter(retval));
326  retval;
327 }
328 
329 
330 def take_while(container, f, inserter) : call_exists(range, container) {
331  auto r := range(container);
332  while ((!r.empty()) && f(r.front())) {
333  inserter(r.front());
334  r.pop_front();
335  }
336 }
337 
338 
339 # Returns a new container with the given elements match the second value function
340 def take_while(container, f) {
341  auto retval := new(container);
342  take_while(container, f, back_inserter(retval));
343  retval;
344 }
345 
346 
347 def drop(container, num, inserter) : call_exists(range, container) {
348  auto r := range(container);
349  auto i = num;
350  while ((i > 0) && (!r.empty())) {
351  r.pop_front();
352  --i;
353  }
354  while (!r.empty()) {
355  inserter(r.front());
356  r.pop_front();
357  }
358 }
359 
360 
361 # Returns a new container with the given number of elements dropped from the given container
362 def drop(container, num) {
363  auto retval := new(container);
364  drop(container, num, back_inserter(retval));
365  retval;
366 }
367 
368 
369 def drop_while(container, f, inserter) : call_exists(range, container) {
370  auto r := range(container);
371  while ((!r.empty())&& f(r.front())) {
372  r.pop_front();
373  }
374  while (!r.empty()) {
375  inserter(r.front());
376  r.pop_front();
377  }
378 }
379 
380 
381 # Returns a new container with the given elements dropped that match the second value function
382 def drop_while(container, f) {
383  auto retval := new(container);
384  drop_while(container, f, back_inserter(retval));
385  retval;
386 }
387 
388 
389 # Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.
390 def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
391  auto r := range(container);
392  auto retval = r.front();
393  r.pop_front();
394  retval = func(retval, r.front());
395  r.pop_front();
396  while (!r.empty()) {
397  retval = func(retval, r.front());
398  r.pop_front();
399  }
400  retval;
401 }
402 
403 
404 # Returns a string of the elements in container delimited by the second value string
405 def join(container, delim) {
406  auto retval = "";
407  auto range := range(container);
408  if (!range.empty()) {
409  retval += to_string(range.front());
410  range.pop_front();
411  while (!range.empty()) {
412  retval += delim;
413  retval += to_string(range.front());
414  range.pop_front();
415  }
416  }
417  retval;
418 }
419 
420 
421 def filter(container, f, inserter) : call_exists(range, container) {
422  auto r := range(container);
423  while (!r.empty()) {
424  if (f(r.front())) {
425  inserter(r.front());
426  }
427  r.pop_front();
428  }
429 }
430 
431 
432 # Returns a new Vector which match the second value function
433 def filter(container, f) {
434  auto retval := new(container);
435  filter(container, f, back_inserter(retval));
436  retval;
437 }
438 
439 
440 def generate_range(x, y, inserter) {
441  auto i = x;
442  while (i <= y) {
443  inserter(i);
444  ++i;
445  }
446 }
447 
448 
449 # Returns a new Vector which represents the range from the first value to the second value
450 def generate_range(x, y) {
451  auto retval := Vector();
452  generate_range(x,y,back_inserter(retval));
453  retval;
454 }
455 
456 
457 # Returns a new Vector with the first value to the second value as its elements
458 def collate(x, y) {
459  return [x, y];
460 }
461 
462 
463 def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) {
464  auto r_x := range(x);
465  auto r_y := range(y);
466  while (!r_x.empty() && !r_y.empty()) {
467  inserter(f(r_x.front(), r_y.front()));
468  r_x.pop_front();
469  r_y.pop_front();
470  }
471 }
472 
473 
474 # Returns a new Vector which joins matching elements of the second and third value with the first value function
475 def zip_with(f, x, y) {
476  auto retval := Vector();
477  zip_with(f,x,y,back_inserter(retval));
478  retval;
479 }
480 
481 
482 # Returns a new Vector which joins matching elements of the first and second
483 def zip(x, y) {
484  zip_with(collate, x, y);
485 }
486 
487 
488 # Returns the position of the second value string in the first value string
489 def string::find(string substr) {
490  find(this, substr, size_t(0));
491 }
492 
493 
494 # Returns the position of last match of the second value string in the first value string
495 def string::rfind(string substr) {
496  rfind(this, substr, size_t(-1));
497 }
498 
499 
500 # Returns the position of the first match of elements in the second value string in the first value string
501 def string::find_first_of(string list) {
502  find_first_of(this, list, size_t(0));
503 }
504 
505 
506 # Returns the position of the last match of elements in the second value string in the first value string
507 def string::find_last_of(string list) {
508  find_last_of(this, list, size_t(-1));
509 }
510 
511 
512 # Returns the position of the first non-matching element in the second value string in the first value string
513 def string::find_first_not_of(string list) {
514  find_first_not_of(this, list, size_t(0));
515 }
516 
517 
518 # Returns the position of the last non-matching element in the second value string in the first value string
519 def string::find_last_not_of(string list) {
520  find_last_not_of(this, list, size_t(-1));
521 }
522 
523 
524 def string::ltrim() {
525  drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'});
526 }
527 
528 
529 def string::rtrim() {
530  reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}));
531 }
532 
533 
534 def string::trim() {
535  ltrim(rtrim(this));
536 }
537 
538 
539 def find(container, value, Function compare_func) : call_exists(range, container) {
540  auto range := range(container);
541  while (!range.empty()) {
542  if (compare_func(range.front(), value)) {
543  return range;
544  } else {
545  range.pop_front();
546  }
547  }
548  range;
549 }
550 
551 
552 def find(container, value) {
553  find(container, value, eq)
554 }
555 
556 
557 )chaiscript";
558  }
559  };
560 } // namespace chaiscript
561 
562 #endif /* CHAISCRIPT_PRELUDE_HPP_ */
Namespace chaiscript contains every API call that the average user will be concerned with...
Definition: chaiscript_prelude.hpp:11