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-2017, 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 { chaiscript_preludechaiscript::ChaiScript_Prelude12 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_ */ 563