kghelpers.c (62538B)
1 /* 2 ** kghelpers.c 3 ** Helper macros and functions for the ground environment 4 ** See Copyright Notice in klisp.h 5 */ 6 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <stdbool.h> 10 #include <stdint.h> 11 12 #include "kghelpers.h" 13 #include "kstate.h" 14 #include "kobject.h" 15 #include "klisp.h" 16 #include "kerror.h" 17 #include "ksymbol.h" 18 #include "kenvironment.h" 19 #include "kinteger.h" 20 #include "krational.h" 21 #include "kapplicative.h" 22 #include "kbytevector.h" 23 #include "kvector.h" 24 #include "kstring.h" 25 #include "kpair.h" 26 #include "kcontinuation.h" 27 #include "kencapsulation.h" 28 #include "kpromise.h" 29 30 /* XXX lock? */ 31 /* Initialization of continuation names */ 32 void kinit_kghelpers_cont_names(klisp_State *K) 33 { 34 Table *t = tv2table(G(K)->cont_name_table); 35 add_cont_name(K, t, do_seq, "eval-sequence"); 36 add_cont_name(K, t, do_pass_value, "pass-value"); 37 add_cont_name(K, t, do_return_value, "return-value"); 38 add_cont_name(K, t, do_bind, "dynamic-bind"); 39 add_cont_name(K, t, do_bind, "dynamic-access"); 40 add_cont_name(K, t, do_bind, "dynamic-unbind"); 41 add_cont_name(K, t, do_bind, "dynamic-set!-pass"); 42 } 43 44 /* Type predicates */ 45 /* TODO these should be moved to either kobject.h or the corresponding 46 files (e.g. kbooleanp to kboolean.h */ 47 bool kbooleanp(TValue obj) { return ttisboolean(obj); } 48 bool kcombinerp(TValue obj) { return ttiscombiner(obj); } 49 bool knumberp(TValue obj) { return ttisnumber(obj); } 50 /* TEMP used (as a type predicate) in all predicates that need a primary value 51 (XXX it's not actually a type error, but it's close enough and otherwise 52 should define new predp & bpredp for numeric predicates...) */ 53 bool knumber_wpvp(TValue obj) 54 { 55 return ttisnumber(obj) && !ttisrwnpv(obj) && !ttisundef(obj); 56 } 57 /* This is used in gcd & lcm */ 58 bool kimp_intp(TValue obj) { return ttisinteger(obj) || ttisinf(obj); } 59 /* obj is known to be a number */ 60 bool kfinitep(TValue obj) { return !ttisinf(obj); } 61 /* fixint, bigints & inexact integers */ 62 bool kintegerp(TValue obj) { return ttisinteger(obj); } 63 /* only exact integers (like for indices), bigints & fixints */ 64 bool keintegerp(TValue obj) { return ttiseinteger(obj); } 65 /* exact integers between 0 and 255 inclusive */ 66 bool ku8p(TValue obj) { return ttisu8(obj); } 67 bool krationalp(TValue obj) { return ttisrational(obj); } 68 bool krealp(TValue obj) { return ttisreal(obj); } 69 /* TEMP used (as a type predicate) in all predicates that need a real with 70 primary value (XXX it's not actually a type error, but it's close enough 71 and otherwise should define new predp & bpredp for numeric predicates...) */ 72 bool kreal_wpvp(TValue obj) { return ttisreal(obj) && !ttisrwnpv(obj); } 73 74 bool kexactp(TValue obj) { return ttisexact(obj); } 75 bool kinexactp(TValue obj) { return ttisinexact(obj); } 76 bool kundefinedp(TValue obj) { return ttisundef(obj); } 77 bool krobustp(TValue obj) { return ttisrobust(obj); } 78 79 void enc_typep(klisp_State *K) 80 { 81 TValue *xparams = K->next_xparams; 82 TValue ptree = K->next_value; 83 TValue denv = K->next_env; 84 klisp_assert(ttisenvironment(K->next_env)); 85 UNUSED(denv); 86 /* 87 ** xparams[0]: encapsulation key 88 */ 89 TValue key = xparams[0]; 90 91 /* check the ptree is a list while checking the predicate. 92 Keep going even if the result is false to catch errors in 93 ptree structure */ 94 bool res = true; 95 96 TValue tail = ptree; 97 while(ttispair(tail) && kis_unmarked(tail)) { 98 kmark(tail); 99 res &= kis_encapsulation_type(kcar(tail), key); 100 tail = kcdr(tail); 101 } 102 unmark_list(K, ptree); 103 104 if (ttispair(tail) || ttisnil(tail)) { 105 kapply_cc(K, b2tv(res)); 106 } else { 107 /* try to get name from encapsulation */ 108 klispE_throw_simple(K, "expected list"); 109 return; 110 } 111 } 112 /* /Type predicates */ 113 114 /* some number functions */ 115 bool kpositivep(TValue n) 116 { 117 switch (ttype(n)) { 118 case K_TFIXINT: 119 case K_TEINF: 120 case K_TIINF: 121 return ivalue(n) > 0; 122 case K_TBIGINT: 123 return kbigint_positivep(n); 124 case K_TBIGRAT: 125 return kbigrat_positivep(n); 126 case K_TDOUBLE: 127 return dvalue(n) > 0.0; 128 /* real with no prim value, complex and undefined should be captured by 129 type predicate */ 130 default: 131 klisp_assert(0); 132 return false; 133 } 134 } 135 136 bool knegativep(TValue n) 137 { 138 switch (ttype(n)) { 139 case K_TFIXINT: 140 case K_TEINF: 141 case K_TIINF: 142 return ivalue(n) < 0; 143 case K_TBIGINT: 144 return kbigint_negativep(n); 145 case K_TBIGRAT: 146 return kbigrat_negativep(n); 147 case K_TDOUBLE: 148 return dvalue(n) < 0.0; 149 /* real with no prim value, complex and undefined should be captured by 150 type predicate */ 151 default: 152 klisp_assert(0); 153 return false; 154 } 155 } 156 /* /some number functions */ 157 158 void typep(klisp_State *K) 159 { 160 TValue *xparams = K->next_xparams; 161 TValue ptree = K->next_value; 162 TValue denv = K->next_env; 163 klisp_assert(ttisenvironment(K->next_env)); 164 /* 165 ** xparams[0]: name symbol 166 ** xparams[1]: type tag (as by i2tv) 167 */ 168 UNUSED(denv); 169 int32_t tag = ivalue(xparams[1]); 170 171 /* check the ptree is a list while checking the predicate. 172 Keep going even if the result is false to catch errors in 173 ptree structure */ 174 bool res = true; 175 176 TValue tail = ptree; 177 while(ttispair(tail) && kis_unmarked(tail)) { 178 kmark(tail); 179 res &= ttype(kcar(tail)) == tag; 180 tail = kcdr(tail); 181 } 182 unmark_list(K, ptree); 183 184 if (ttispair(tail) || ttisnil(tail)) { 185 kapply_cc(K, b2tv(res)); 186 } else { 187 klispE_throw_simple(K, "expected list"); 188 return; 189 } 190 } 191 192 void ftypep(klisp_State *K) 193 { 194 TValue *xparams = K->next_xparams; 195 TValue ptree = K->next_value; 196 TValue denv = K->next_env; 197 klisp_assert(ttisenvironment(K->next_env)); 198 (void) denv; 199 /* 200 ** xparams[0]: name symbol 201 ** xparams[1]: fn pointer (as a void * in a user TValue) 202 */ 203 bool (*fn)(TValue obj) = pvalue(xparams[1]); 204 205 /* check the ptree is a list while checking the predicate. 206 Keep going even if the result is false to catch errors in 207 ptree structure */ 208 bool res = true; 209 210 TValue tail = ptree; 211 while(ttispair(tail) && kis_unmarked(tail)) { 212 kmark(tail); 213 res &= (*fn)(kcar(tail)); 214 tail = kcdr(tail); 215 } 216 unmark_list(K, ptree); 217 218 if (ttispair(tail) || ttisnil(tail)) { 219 kapply_cc(K, b2tv(res)); 220 } else { 221 klispE_throw_simple(K, "expected list"); 222 return; 223 } 224 } 225 226 /* 227 ** REFACTOR: Change this to make it a single pass 228 */ 229 void ftyped_predp(klisp_State *K) 230 { 231 TValue *xparams = K->next_xparams; 232 TValue ptree = K->next_value; 233 TValue denv = K->next_env; 234 klisp_assert(ttisenvironment(K->next_env)); 235 (void) denv; 236 /* 237 ** xparams[0]: name symbol 238 ** xparams[1]: type fn pointer (as a void * in a user TValue) 239 ** xparams[2]: fn pointer (as a void * in a user TValue) 240 */ 241 bool (*typep)(TValue obj) = pvalue(xparams[1]); 242 bool (*predp)(TValue obj) = pvalue(xparams[2]); 243 244 /* check the ptree is a list first to allow the structure 245 errors to take precedence over the type errors. */ 246 int32_t pairs, cpairs; 247 check_list(K, true, ptree, &pairs, &cpairs); 248 249 TValue tail = ptree; 250 bool res = true; 251 252 /* check the type while checking the predicate. 253 Keep going even if the result is false to catch errors in 254 type */ 255 while(pairs--) { 256 TValue first = kcar(tail); 257 258 if (!(*typep)(first)) { 259 /* TODO show expected type */ 260 klispE_throw_simple(K, "bad argument type"); 261 return; 262 } 263 res &= (*predp)(first); 264 tail = kcdr(tail); 265 } 266 kapply_cc(K, b2tv(res)); 267 } 268 269 /* 270 ** REFACTOR: Change this to make it a single pass 271 */ 272 void ftyped_bpredp(klisp_State *K) 273 { 274 TValue *xparams = K->next_xparams; 275 TValue ptree = K->next_value; 276 TValue denv = K->next_env; 277 klisp_assert(ttisenvironment(K->next_env)); 278 (void) denv; 279 /* 280 ** xparams[0]: name symbol 281 ** xparams[1]: type fn pointer (as a void * in a user TValue) 282 ** xparams[2]: fn pointer (as a void * in a user TValue) 283 */ 284 bool (*typep)(TValue obj) = pvalue(xparams[1]); 285 bool (*predp)(TValue obj1, TValue obj2) = pvalue(xparams[2]); 286 287 /* check the ptree is a list first to allow the structure 288 errors to take precedence over the type errors. */ 289 int32_t pairs, cpairs; 290 check_list(K, true, ptree, &pairs, &cpairs); 291 292 /* cyclical list require an extra comparison of the last 293 & first element of the cycle */ 294 int32_t comps = cpairs? pairs : pairs - 1; 295 296 TValue tail = ptree; 297 bool res = true; 298 299 /* check the type while checking the predicate. 300 Keep going even if the result is false to catch errors in 301 type */ 302 303 if (comps == 0) { 304 /* this case has to be here because otherwise there is no check 305 for the type of the lone operand */ 306 TValue first = kcar(tail); 307 if (!(*typep)(first)) { 308 /* TODO show expected type */ 309 klispE_throw_simple(K, "bad argument type"); 310 return; 311 } 312 } 313 314 while(comps-- > 0) { /* comps could be -1 if ptree is () */ 315 TValue first = kcar(tail); 316 tail = kcdr(tail); /* tail only advances one place per iteration */ 317 TValue second = kcar(tail); 318 319 if (!(*typep)(first) || !(*typep)(second)) { 320 /* TODO show expected type */ 321 klispE_throw_simple(K, "bad argument type"); 322 return; 323 } 324 res &= (*predp)(first, second); 325 } 326 kapply_cc(K, b2tv(res)); 327 } 328 329 /* This is the same, but the comparison predicate takes a klisp_State */ 330 /* TODO unify them */ 331 void ftyped_kbpredp(klisp_State *K) 332 { 333 TValue *xparams = K->next_xparams; 334 TValue ptree = K->next_value; 335 TValue denv = K->next_env; 336 klisp_assert(ttisenvironment(K->next_env)); 337 (void) denv; 338 /* 339 ** xparams[0]: name symbol 340 ** xparams[1]: type fn pointer (as a void * in a user TValue) 341 ** xparams[2]: fn pointer (as a void * in a user TValue) 342 */ 343 bool (*typep)(TValue obj) = pvalue(xparams[1]); 344 bool (*predp)(klisp_State *K, TValue obj1, TValue obj2) = 345 pvalue(xparams[2]); 346 347 /* check the ptree is a list first to allow the structure 348 errors to take precedence over the type errors. */ 349 int32_t pairs, cpairs; 350 check_list(K, true, ptree, &pairs, &cpairs); 351 352 /* cyclical list require an extra comparison of the last 353 & first element of the cycle */ 354 int32_t comps = cpairs? pairs : pairs - 1; 355 356 TValue tail = ptree; 357 bool res = true; 358 359 /* check the type while checking the predicate. 360 Keep going even if the result is false to catch errors in 361 type */ 362 363 if (comps == 0) { 364 /* this case has to be here because otherwise there is no check 365 for the type of the lone operand */ 366 TValue first = kcar(tail); 367 if (!(*typep)(first)) { 368 /* TODO show expected type */ 369 klispE_throw_simple(K, "bad argument type"); 370 return; 371 } 372 } 373 374 while(comps-- > 0) { /* comps could be -1 if ptree is () */ 375 TValue first = kcar(tail); 376 tail = kcdr(tail); /* tail only advances one place per iteration */ 377 TValue second = kcar(tail); 378 379 if (!(*typep)(first) || !(*typep)(second)) { 380 /* TODO show expected type */ 381 klispE_throw_simple(K, "bad argument type"); 382 return; 383 } 384 res &= (*predp)(K, first, second); 385 } 386 kapply_cc(K, b2tv(res)); 387 } 388 389 /* typed finite list. Structure error should be throw before type errors */ 390 void check_typed_list(klisp_State *K, bool (*typep)(TValue), bool allow_infp, 391 TValue obj, int32_t *pairs, int32_t *cpairs) 392 { 393 TValue tail = obj; 394 int32_t p = 0; 395 bool type_errorp = false; 396 397 while(ttispair(tail) && !kis_marked(tail)) { 398 /* even if there is a type error continue checking the structure */ 399 type_errorp |= !(*typep)(kcar(tail)); 400 kset_mark(tail, i2tv(p)); 401 tail = kcdr(tail); 402 ++p; 403 } 404 405 if (pairs != NULL) *pairs = p; 406 if (cpairs != NULL) 407 *cpairs = ttispair(tail)? (p - ivalue(kget_mark(tail))) : 0; 408 409 unmark_list(K, obj); 410 411 if (!ttispair(tail) && !ttisnil(tail)) { 412 klispE_throw_simple(K, allow_infp? "expected list" : 413 "expected finite list"); 414 return; 415 } else if(ttispair(tail) && !allow_infp) { 416 klispE_throw_simple(K, "expected finite list"); 417 return; 418 } else if (type_errorp) { 419 /* TODO put type name too, should be extracted from a 420 table of type names */ 421 klispE_throw_simple(K, "bad operand type"); 422 return; 423 } 424 } 425 426 void check_list(klisp_State *K, bool allow_infp, TValue obj, 427 int32_t *pairs, int32_t *cpairs) 428 { 429 TValue tail = obj; 430 int32_t p = 0; 431 432 while(ttispair(tail) && !kis_marked(tail)) { 433 kset_mark(tail, i2tv(p)); 434 tail = kcdr(tail); 435 ++p; 436 } 437 438 if (pairs != NULL) *pairs = p; 439 if (cpairs != NULL) 440 *cpairs = ttispair(tail)? (p - ivalue(kget_mark(tail))) : 0; 441 442 unmark_list(K, obj); 443 444 if (!ttispair(tail) && !ttisnil(tail)) { 445 klispE_throw_simple(K, allow_infp? "expected list" : 446 "expected finite list"); 447 return; 448 } else if(ttispair(tail) && !allow_infp) { 449 klispE_throw_simple(K, "expected finite list"); 450 return; 451 } 452 } 453 454 455 TValue check_copy_list(klisp_State *K, TValue obj, bool force_copy, 456 int32_t *pairs, int32_t *cpairs) 457 { 458 int32_t p = 0; 459 if (ttisnil(obj)) { 460 if (pairs != NULL) *pairs = 0; 461 if (cpairs != NULL) *cpairs = 0; 462 return obj; 463 } 464 465 if (ttispair(obj) && kis_immutable(obj) && !force_copy) { 466 /* this will properly set pairs and cpairs */ 467 check_list(K, true, obj, pairs, cpairs); 468 return obj; 469 } else { 470 TValue copy = kcons(K, KNIL, KNIL); 471 krooted_vars_push(K, ©); 472 TValue last_pair = copy; 473 TValue tail = obj; 474 475 while(ttispair(tail) && !kis_marked(tail)) { 476 TValue new_pair = kcons(K, kcar(tail), KNIL); 477 /* record the corresponding pair to simplify cycle handling */ 478 kset_mark(tail, new_pair); 479 /* record the pair number in the new pair, to set cpairs */ 480 kset_mark(new_pair, i2tv(p)); 481 /* copy the source code info */ 482 TValue si = ktry_get_si(K, tail); 483 if (!ttisnil(si)) 484 kset_source_info(K, new_pair, si); 485 kset_cdr(last_pair, new_pair); 486 last_pair = new_pair; 487 tail = kcdr(tail); 488 ++p; 489 } 490 491 if (pairs != NULL) *pairs = p; 492 if (cpairs != NULL) 493 *cpairs = ttispair(tail)? 494 (p - ivalue(kget_mark(kget_mark(tail)))) : 495 0; 496 497 if (ttispair(tail)) { 498 /* complete the cycle */ 499 kset_cdr(last_pair, kget_mark(tail)); 500 } 501 502 unmark_list(K, obj); 503 unmark_list(K, kcdr(copy)); 504 505 if (!ttispair(tail) && !ttisnil(tail)) { 506 klispE_throw_simple(K, "expected list"); 507 return KINERT; 508 } 509 krooted_vars_pop(K); 510 return kcdr(copy); 511 } 512 } 513 514 /* GC: assumes ls is rooted */ 515 /* LOCK: This assumes ls isn't mutated, so no lock is acquired 516 (except the needed for car, cdr & set-cdr) */ 517 TValue reverse_copy_and_encycle(klisp_State *K, TValue ls, int32_t pairs, 518 int32_t cpairs) 519 { 520 if (pairs == 0) 521 return KNIL; 522 523 int32_t apairs = pairs - cpairs; 524 TValue last = kcons(K, kcar(ls), KNIL); 525 ls = kcdr(ls); 526 krooted_vars_push(K, &last); 527 528 if (cpairs > 0) { 529 --cpairs; 530 TValue last_cycle = last; 531 while (cpairs > 0) { 532 last = kcons(K, kcar(ls), last); 533 ls = kcdr(ls); 534 --cpairs; 535 } 536 kset_cdr(last_cycle, last); 537 } else { 538 --apairs; 539 } 540 541 while (apairs > 0) { 542 last = kcons(K, kcar(ls), last); 543 ls = kcdr(ls); 544 --apairs; 545 } 546 547 krooted_vars_pop(K); 548 return last; 549 } 550 551 TValue check_copy_env_list(klisp_State *K, TValue obj) 552 { 553 TValue copy = kcons(K, KNIL, KNIL); 554 krooted_vars_push(K, ©); 555 TValue last_pair = copy; 556 TValue tail = obj; 557 558 while(ttispair(tail) && !kis_marked(tail)) { 559 TValue first = kcar(tail); 560 if (!ttisenvironment(first)) { 561 klispE_throw_simple(K, "not an environment in parent list"); 562 return KINERT; 563 } 564 TValue new_pair = kcons(K, first, KNIL); 565 kmark(tail); 566 kset_cdr(last_pair, new_pair); 567 last_pair = new_pair; 568 tail = kcdr(tail); 569 } 570 571 /* even if there was a cycle, the copy ends with nil */ 572 unmark_list(K, obj); 573 574 if (!ttispair(tail) && !ttisnil(tail)) { 575 klispE_throw_simple(K, "expected list"); 576 return KINERT; 577 } 578 krooted_vars_pop(K); 579 return kcdr(copy); 580 } 581 582 /* Helpers for string, list->string, and string-map, 583 bytevector, list->bytevector, bytevector-map, 584 vector, list->vector, and vector-map */ 585 /* GC: Assume ls is rooted */ 586 /* ls should a list of length 'length' of the correct type 587 (chars for string, u8 for bytevector, any for vector) */ 588 /* these type checks each element */ 589 590 TValue list_to_string_h(klisp_State *K, TValue ls, int32_t length) 591 { 592 TValue new_str; 593 /* the if isn't strictly necessary but it's clearer this way */ 594 if (length == 0) { 595 return G(K)->empty_string; 596 } else { 597 new_str = kstring_new_s(K, length); 598 char *buf = kstring_buf(new_str); 599 while(length-- > 0) { 600 TValue head = kcar(ls); 601 if (!ttischar(head)) { 602 klispE_throw_simple_with_irritants(K, "Bad type (expected " 603 "char)", 1, head); 604 return KINERT; 605 } 606 *buf++ = chvalue(head); 607 ls = kcdr(ls); 608 } 609 return new_str; 610 } 611 } 612 613 TValue list_to_vector_h(klisp_State *K, TValue ls, int32_t length) 614 { 615 616 if (length == 0) { 617 return G(K)->empty_vector; 618 } else { 619 TValue new_vec = kvector_new_sf(K, length, KINERT); 620 TValue *buf = kvector_buf(new_vec); 621 while(length-- > 0) { 622 *buf++ = kcar(ls); 623 ls = kcdr(ls); 624 } 625 return new_vec; 626 } 627 } 628 629 TValue list_to_bytevector_h(klisp_State *K, TValue ls, int32_t length) 630 { 631 TValue new_bb; 632 /* the if isn't strictly necessary but it's clearer this way */ 633 if (length == 0) { 634 return G(K)->empty_bytevector; 635 } else { 636 new_bb = kbytevector_new_s(K, length); 637 uint8_t *buf = kbytevector_buf(new_bb); 638 while(length-- > 0) { 639 TValue head = kcar(ls); 640 if (!ttisu8(head)) { 641 klispE_throw_simple_with_irritants(K, "Bad type (expected " 642 "u8)", 1, head); 643 return KINERT; 644 } 645 *buf++ = ivalue(head); 646 ls = kcdr(ls); 647 } 648 return new_bb; 649 } 650 } 651 652 /* Helpers for string->list, string-map, string-foreach, 653 bytevector->list, bytevector-map, bytevector-foreach, 654 vector->list, vector-map, and vector-foreach */ 655 /* GC: Assume array is rooted */ 656 TValue string_to_list_h(klisp_State *K, TValue obj, int32_t *length) 657 { 658 if (!ttisstring(obj)) { 659 klispE_throw_simple_with_irritants(K, "Bad type (expected string)", 660 1, obj); 661 return KINERT; 662 } 663 664 int32_t pairs = kstring_size(obj); 665 if (length != NULL) *length = pairs; 666 667 char *buf = kstring_buf(obj) + pairs - 1; 668 TValue tail = KNIL; 669 krooted_vars_push(K, &tail); 670 while(pairs-- > 0) { 671 tail = kcons(K, ch2tv(*buf), tail); 672 --buf; 673 } 674 krooted_vars_pop(K); 675 return tail; 676 } 677 678 TValue vector_to_list_h(klisp_State *K, TValue obj, int32_t *length) 679 { 680 if (!ttisvector(obj)) { 681 klispE_throw_simple_with_irritants(K, "Bad type (expected vector)", 682 1, obj); 683 return KINERT; 684 } 685 686 int32_t pairs = kvector_size(obj); 687 if (length != NULL) *length = pairs; 688 689 TValue *buf = kvector_buf(obj) + pairs - 1; 690 TValue tail = KNIL; 691 krooted_vars_push(K, &tail); 692 while(pairs-- > 0) { 693 tail = kcons(K, *buf, tail); 694 --buf; 695 } 696 krooted_vars_pop(K); 697 return tail; 698 } 699 700 TValue bytevector_to_list_h(klisp_State *K, TValue obj, int32_t *length) 701 { 702 if (!ttisbytevector(obj)) { 703 klispE_throw_simple_with_irritants(K, "Bad type (expected bytevector)", 704 1, obj); 705 return KINERT; 706 } 707 708 int32_t pairs = kbytevector_size(obj); 709 if (length != NULL) *length = pairs; 710 711 uint8_t *buf = kbytevector_buf(obj) + pairs - 1; 712 TValue tail = KNIL; 713 krooted_vars_push(K, &tail); 714 while(pairs-- > 0) { 715 tail = kcons(K, i2tv(*buf), tail); 716 --buf; 717 } 718 krooted_vars_pop(K); 719 return tail; 720 } 721 722 /* Some helpers for working with fixints (signed 32 bits) */ 723 int64_t kgcd32_64(int32_t a_, int32_t b_) 724 { 725 /* this is a vanilla binary gcd algorithm */ 726 727 /* work with positive numbers, use unsigned numbers to 728 allow INT32_MIN to have an absolute value */ 729 uint32_t a = (uint32_t) kabs64(a_); 730 uint32_t b = (uint32_t) kabs64(b_); 731 732 int powerof2; 733 734 /* the easy cases first, unlike the general kernel gcd the 735 gcd2 of a number and zero is zero */ 736 if (a == 0) 737 return (int64_t) b; 738 else if (b == 0) 739 return (int64_t) a; 740 741 for (powerof2 = 0; ((a & 1) == 0) && 742 ((b & 1) == 0); ++powerof2, a >>= 1, b >>= 1) 743 ; 744 745 while(a != 0 && b!= 0) { 746 /* either a or b are odd, make them both odd */ 747 for (; (a & 1) == 0; a >>= 1) 748 ; 749 for (; (b & 1) == 0; b >>= 1) 750 ; 751 752 /* now the difference is sure to be even */ 753 if (a < b) { 754 b = (b - a) >> 1; 755 } else { 756 a = (a - b) >> 1; 757 } 758 } 759 760 return ((int64_t) (a == 0? b : a)) << powerof2; 761 } 762 763 int64_t klcm32_64(int32_t a_, int32_t b_) 764 { 765 int64_t gcd = kgcd32_64(a_, b_); 766 int64_t a = kabs64(a_); 767 int64_t b = kabs64(b_); 768 /* divide first to avoid possible overflow */ 769 return (a / gcd) * b; 770 } 771 772 /* This is needed in kstate & promises */ 773 void memoize(klisp_State *K) 774 { 775 TValue *xparams = K->next_xparams; 776 TValue ptree = K->next_value; 777 TValue denv = K->next_env; 778 klisp_assert(ttisenvironment(K->next_env)); 779 UNUSED(xparams); 780 UNUSED(denv); 781 782 bind_1p(K, ptree, exp); 783 TValue new_prom = kmake_promise(K, exp, KNIL); 784 kapply_cc(K, new_prom); 785 } 786 787 /* list applicative (used in kstate and kgpairs_lists) */ 788 void list(klisp_State *K) 789 { 790 TValue *xparams = K->next_xparams; 791 TValue ptree = K->next_value; 792 TValue denv = K->next_env; 793 klisp_assert(ttisenvironment(K->next_env)); 794 /* the underlying combiner of list return the complete ptree, the only list 795 checking is implicit in the applicative evaluation */ 796 UNUSED(xparams); 797 UNUSED(denv); 798 kapply_cc(K, ptree); 799 } 800 801 /* Helper for get-list-metrics, and list-tail, list-ref and list-set! 802 when receiving bigint indexes */ 803 void get_list_metrics_aux(klisp_State *K, TValue obj, int32_t *p, int32_t *n, 804 int32_t *a, int32_t *c) 805 { 806 TValue tail = obj; 807 int32_t pairs = 0; 808 809 while(ttispair(tail) && !kis_marked(tail)) { 810 /* record the pair number to simplify cycle pair counting */ 811 kset_mark(tail, i2tv(pairs)); 812 ++pairs; 813 tail = kcdr(tail); 814 } 815 int32_t apairs, cpairs, nils; 816 if (ttisnil(tail)) { 817 /* simple (possibly empty) list */ 818 apairs = pairs; 819 nils = 1; 820 cpairs = 0; 821 } else if (ttispair(tail)) { 822 /* cyclic (maybe circular) list */ 823 apairs = ivalue(kget_mark(tail)); 824 cpairs = pairs - apairs; 825 nils = 0; 826 } else { 827 apairs = pairs; 828 cpairs = 0; 829 nils = 0; 830 } 831 832 unmark_list(K, obj); 833 834 if (p != NULL) *p = pairs; 835 if (n != NULL) *n = nils; 836 if (a != NULL) *a = apairs; 837 if (c != NULL) *c = cpairs; 838 } 839 840 /* Helper for list-tail, list-ref and list-set! */ 841 /* Calculate the smallest i such that 842 (eq? (list-tail obj i) (list-tail obj tk)) 843 tk is a bigint and all lists have fixint range number of pairs, 844 so the list should cyclic and we should calculate an index that 845 doesn't go through the complete cycle not even once */ 846 int32_t ksmallest_index(klisp_State *K, TValue obj, TValue tk) 847 { 848 int32_t apairs, cpairs; 849 get_list_metrics_aux(K, obj, NULL, NULL, &apairs, &cpairs); 850 if (cpairs == 0) { 851 klispE_throw_simple(K, "non pair found while traversing " 852 "object"); 853 return 0; 854 } 855 TValue tv_apairs = i2tv(apairs); 856 TValue tv_cpairs = i2tv(cpairs); 857 858 /* all calculations will be done with bigints */ 859 kensure_bigint(tv_apairs); 860 kensure_bigint(tv_cpairs); 861 862 TValue idx = kbigint_minus(K, tk, tv_apairs); 863 krooted_tvs_push(K, idx); /* root idx if it is a bigint */ 864 /* idx may have become a fixint */ 865 kensure_bigint(idx); 866 UNUSED(kbigint_div_mod(K, idx, tv_cpairs, &idx)); 867 krooted_tvs_pop(K); 868 /* now idx is less than cpairs so it fits in a fixint */ 869 assert(ttisfixint(idx)); 870 return ivalue(idx) + apairs; 871 } 872 873 /* Helper for eq? and equal? */ 874 bool eq2p(klisp_State *K, TValue obj1, TValue obj2) 875 { 876 bool res = (tv_equal(obj1, obj2)); 877 if (!res && (ttype(obj1) == ttype(obj2))) { 878 switch (ttype(obj1)) { 879 case K_TSYMBOL: 880 /* symbols can't be compared with tv_equal! */ 881 res = tv_sym_equal(obj1, obj2); 882 break; 883 case K_TAPPLICATIVE: 884 while(ttisapplicative(obj1) && ttisapplicative(obj2)) { 885 obj1 = kunwrap(obj1); 886 obj2 = kunwrap(obj2); 887 } 888 res = (tv_equal(obj1, obj2)); 889 break; 890 case K_TBIGINT: 891 /* it's important to know that it can't be the case 892 that obj1 is bigint and obj is some other type and 893 (eq? obj1 obj2) */ 894 res = kbigint_eqp(obj1, obj2); 895 break; 896 case K_TBIGRAT: 897 /* it's important to know that it can't be the case 898 that obj1 is bigrat and obj is some other type and 899 (eq? obj1 obj2) */ 900 res = kbigrat_eqp(K, obj1, obj2); 901 break; 902 } /* immutable strings & bytevectors are interned so they are 903 covered already by tv_equalp */ 904 905 } 906 return res; 907 } 908 909 /* 910 ** Helpers for equal? algorithm 911 ** 912 ** See [2] for details of the list merging algorithm. 913 ** Here are the implementation details: 914 ** The marks of the pairs are used to store the nodes of the trees 915 ** that represent the set of previous comparations of each pair. 916 ** They serve the function of the array in [2]. 917 ** If a pair is unmarked, it was never compared (empty comparison set). 918 ** If a pair is marked, the mark object is either (#f . parent-node) 919 ** if the node is not the root, and (#t . n) where n is the number 920 ** of elements in the set, if the node is the root. 921 ** This pair also doubles as the "name" of the set in [2]. 922 ** 923 ** GC: all of these assume that arguments are rooted. 924 */ 925 926 /* find "name" of the set of this obj, if there isn't one create it, 927 if there is one, flatten its branch */ 928 static inline TValue equal_find(klisp_State *K, TValue obj) 929 { 930 /* GC: should root obj */ 931 if (kis_unmarked(obj)) { 932 /* object wasn't compared before, create new set */ 933 TValue new_node = kcons(K, KTRUE, i2tv(1)); 934 kset_mark(obj, new_node); 935 return new_node; 936 } else { 937 TValue node = kget_mark(obj); 938 939 /* First obtain the root and a list of all the other objects in this 940 branch, as said above the root is the one with #t in its car */ 941 /* NOTE: the stack is being used, so we must remember how many pairs we 942 push, we can't just pop 'till is empty */ 943 int np = 0; 944 while(kis_false(kcar(node))) { 945 ks_spush(K, node); 946 node = kcdr(node); 947 ++np; 948 } 949 TValue root = node; 950 951 /* set all parents to root, to flatten the branch */ 952 while(np--) { 953 node = ks_spop(K); 954 kset_cdr(node, root); 955 } 956 return root; 957 } 958 } 959 960 /* merge the smaller set into the big one, if both are equal just pick one */ 961 static inline void equal_merge(klisp_State *K, TValue root1, TValue root2) 962 { 963 /* K isn't needed but added for consistency */ 964 UNUSED(K); 965 int32_t size1 = ivalue(kcdr(root1)); 966 int32_t size2 = ivalue(kcdr(root2)); 967 TValue new_size = i2tv(size1 + size2); 968 969 if (size1 < size2) { 970 /* add root1 set (the smaller one) to root2 */ 971 kset_cdr(root2, new_size); 972 kset_car(root1, KFALSE); 973 kset_cdr(root1, root2); 974 } else { 975 /* add root2 set (the smaller one) to root1 */ 976 kset_cdr(root1, new_size); 977 kset_car(root2, KFALSE); 978 kset_cdr(root2, root1); 979 } 980 } 981 982 /* check to see if two objects were already compared, and return that. If they 983 weren't compared yet, merge their sets (and flatten their branches) */ 984 static inline bool equal_find2_mergep(klisp_State *K, TValue obj1, TValue obj2) 985 { 986 /* GC: should root root1 and root2 */ 987 TValue root1 = equal_find(K, obj1); 988 TValue root2 = equal_find(K, obj2); 989 if (tv_equal(root1, root2)) { 990 /* they are in the same set => they were already compared */ 991 return true; 992 } else { 993 equal_merge(K, root1, root2); 994 return false; 995 } 996 } 997 998 /* 999 ** See [1] for details, in this case the pairs form a possibly infinite "tree" 1000 ** structure, and that can be seen as a finite automata, where each node is a 1001 ** state, the car and the cdr are the transitions from that state to others, 1002 ** and the leaves (the non-pair objects) are the final states. 1003 ** Other way to see it is that, the key for determining equalness of two pairs 1004 ** is: Check to see if they were already compared to each other. 1005 ** If so, return #t, otherwise, mark them as compared to each other and 1006 ** recurse on both cars and both cdrs. 1007 ** The idea is that if assuming obj1 and obj2 are equal their components are 1008 ** equal then they are effectively equal to each other. 1009 */ 1010 bool equal2p(klisp_State *K, TValue obj1, TValue obj2) 1011 { 1012 assert(ks_sisempty(K)); 1013 1014 /* the stack has the elements to be compaired, always in pairs. 1015 So the top should be compared with the one below, the third with 1016 the fourth and so on */ 1017 ks_spush(K, obj1); 1018 ks_spush(K, obj2); 1019 1020 /* if the stacks becomes empty, all pairs of elements were equal */ 1021 bool result = true; 1022 TValue saved_obj1 = obj1; 1023 TValue saved_obj2 = obj2; 1024 1025 while(!ks_sisempty(K)) { 1026 obj2 = ks_spop(K); 1027 obj1 = ks_spop(K); 1028 1029 if (!eq2p(K, obj1, obj2)) { 1030 /* This type comparison works because we just care about 1031 pairs, vectors, strings & bytevectors */ 1032 if (ttype(obj1) == ttype(obj2)) { 1033 switch(ttype(obj1)) { 1034 case K_TPAIR: 1035 /* if they were already compaired, consider equal for 1036 now otherwise they are equal if both their cars 1037 and cdrs are */ 1038 if (!equal_find2_mergep(K, obj1, obj2)) { 1039 ks_spush(K, kcdr(obj1)); 1040 ks_spush(K, kcdr(obj2)); 1041 ks_spush(K, kcar(obj1)); 1042 ks_spush(K, kcar(obj2)); 1043 } 1044 break; 1045 case K_TVECTOR: 1046 if (kvector_size(obj1) == kvector_size(obj2)) { 1047 /* if they were already compaired, consider equal for 1048 now otherwise they are equal if all their elements 1049 are equal pairwise */ 1050 if (!equal_find2_mergep(K, obj1, obj2)) { 1051 uint32_t i = kvector_size(obj1); 1052 TValue *array1 = kvector_buf(obj1); 1053 TValue *array2 = kvector_buf(obj2); 1054 while(i-- > 0) { 1055 ks_spush(K, array1[i]); 1056 ks_spush(K, array2[i]); 1057 } 1058 } 1059 } else { 1060 result = false; 1061 goto end; 1062 } 1063 break; 1064 case K_TSTRING: 1065 if (!kstring_equalp(obj1, obj2)) { 1066 result = false; 1067 goto end; 1068 } 1069 break; 1070 case K_TBYTEVECTOR: 1071 if (!kbytevector_equalp(K, obj1, obj2)) { 1072 result = false; 1073 goto end; 1074 } 1075 break; 1076 default: 1077 result = false; 1078 goto end; 1079 } 1080 } else { 1081 result = false; 1082 goto end; 1083 } 1084 } 1085 } 1086 end: 1087 /* if result is false, the stack may not be empty */ 1088 ks_sclear(K); 1089 1090 unmark_tree(K, saved_obj1); 1091 unmark_tree(K, saved_obj2); 1092 1093 return result; 1094 } 1095 1096 /* 1097 ** This is in a helper method to use it from $lambda, $vau, etc 1098 ** 1099 ** We mark each seen mutable pair with the corresponding copied 1100 ** immutable pair to construct a structure that is isomorphic to 1101 ** the original. 1102 ** All objects that aren't mutable pairs are retained without 1103 ** copying 1104 ** sstack is used to keep track of pairs and tbstack is used 1105 ** to keep track of which of car or cdr we were copying, 1106 ** 0 means just pushed, 1 means return from car, 2 means return from cdr 1107 ** 1108 ** This also copies source code info 1109 ** 1110 */ 1111 1112 /* GC: assumes obj is rooted */ 1113 TValue copy_es_immutable_h(klisp_State *K, TValue obj, bool mut_flag) 1114 { 1115 TValue copy = obj; 1116 krooted_vars_push(K, ©); 1117 1118 assert(ks_sisempty(K)); 1119 assert(ks_tbisempty(K)); 1120 1121 ks_spush(K, obj); 1122 ks_tbpush(K, ST_PUSH); 1123 1124 while(!ks_sisempty(K)) { 1125 char state = ks_tbpop(K); 1126 TValue top = ks_spop(K); 1127 1128 if (state == ST_PUSH) { 1129 /* if the pair is immutable & we are constructing immutable 1130 pairs there is no need to copy */ 1131 if (ttispair(top) && (mut_flag || kis_mutable(top))) { 1132 if (kis_marked(top)) { 1133 /* this pair was already seen, use the same */ 1134 copy = kget_mark(top); 1135 } else { 1136 TValue new_pair = kcons_g(K, mut_flag, KINERT, KINERT); 1137 kset_mark(top, new_pair); 1138 /* save the source code info on the new pair */ 1139 /* MAYBE: only do it if mutable */ 1140 TValue si = ktry_get_si(K, top); 1141 if (!ttisnil(si)) 1142 kset_source_info(K, new_pair, si); 1143 /* leave the pair in the stack, continue with the car */ 1144 ks_spush(K, top); 1145 ks_tbpush(K, ST_CAR); 1146 1147 ks_spush(K, kcar(top)); 1148 ks_tbpush(K, ST_PUSH); 1149 } 1150 } else { 1151 copy = top; 1152 } 1153 } else { /* last action was a pop */ 1154 TValue new_pair = kget_mark(top); 1155 if (state == ST_CAR) { 1156 /* new_pair may be immutable */ 1157 kset_car_unsafe(K, new_pair, copy); 1158 /* leave the pair on the stack, continue with the cdr */ 1159 ks_spush(K, top); 1160 ks_tbpush(K, ST_CDR); 1161 1162 ks_spush(K, kcdr(top)); 1163 ks_tbpush(K, ST_PUSH); 1164 } else { 1165 /* new_pair may be immutable */ 1166 kset_cdr_unsafe(K, new_pair, copy); 1167 copy = new_pair; 1168 } 1169 } 1170 } 1171 unmark_tree(K, obj); 1172 krooted_vars_pop(K); 1173 return copy; 1174 } 1175 1176 /* ptree handling */ 1177 1178 /* 1179 ** Clear all the marks (symbols + pairs) & stacks. 1180 ** The stack should contain only pairs, sym_ls should be 1181 ** as above 1182 */ 1183 static inline void ptree_clear_all(klisp_State *K, TValue sym_ls) 1184 { 1185 while(!ttisnil(sym_ls)) { 1186 TValue first = sym_ls; 1187 sym_ls = kget_symbol_mark(first); 1188 kunmark_symbol(first); 1189 } 1190 1191 while(!ks_sisempty(K)) { 1192 kunmark(ks_sget(K)); 1193 ks_sdpop(K); 1194 } 1195 1196 ks_tbclear(K); 1197 } 1198 1199 /* GC: assumes env, ptree & obj are rooted */ 1200 void match(klisp_State *K, TValue env, TValue ptree, TValue obj) 1201 { 1202 assert(ks_sisempty(K)); 1203 ks_spush(K, obj); 1204 ks_spush(K, ptree); 1205 1206 while(!ks_sisempty(K)) { 1207 ptree = ks_spop(K); 1208 obj = ks_spop(K); 1209 1210 switch(ttype(ptree)) { 1211 case K_TNIL: 1212 if (!ttisnil(obj)) { 1213 /* TODO show ptree and arguments */ 1214 ks_sclear(K); 1215 klispE_throw_simple(K, "ptree doesn't match arguments"); 1216 return; 1217 } 1218 break; 1219 case K_TIGNORE: 1220 /* do nothing */ 1221 break; 1222 case K_TSYMBOL: 1223 kadd_binding(K, env, ptree, obj); 1224 break; 1225 case K_TPAIR: 1226 if (ttispair(obj)) { 1227 ks_spush(K, kcdr(obj)); 1228 ks_spush(K, kcdr(ptree)); 1229 ks_spush(K, kcar(obj)); 1230 ks_spush(K, kcar(ptree)); 1231 } else { 1232 /* TODO show ptree and arguments */ 1233 ks_sclear(K); 1234 klispE_throw_simple(K, "ptree doesn't match arguments"); 1235 return; 1236 } 1237 break; 1238 default: 1239 /* can't really happen */ 1240 break; 1241 } 1242 } 1243 } 1244 1245 /* GC: assumes ptree & penv are rooted */ 1246 TValue check_copy_ptree(klisp_State *K, TValue ptree, TValue penv) 1247 { 1248 /* copy is only valid if the state isn't ST_PUSH */ 1249 /* but init anyways for gc (and avoiding warnings) */ 1250 TValue copy = ptree; 1251 krooted_vars_push(K, ©); 1252 1253 /* 1254 ** NIL terminated singly linked list of symbols 1255 ** (using the mark as next pointer) 1256 */ 1257 TValue sym_ls = KNIL; 1258 1259 assert(ks_sisempty(K)); 1260 assert(ks_tbisempty(K)); 1261 1262 ks_tbpush(K, ST_PUSH); 1263 ks_spush(K, ptree); 1264 1265 while(!ks_sisempty(K)) { 1266 char state = ks_tbpop(K); 1267 TValue top = ks_spop(K); 1268 1269 if (state == ST_PUSH) { 1270 switch(ttype(top)) { 1271 case K_TIGNORE: 1272 case K_TNIL: 1273 copy = top; 1274 break; 1275 case K_TSYMBOL: { 1276 if (kis_symbol_marked(top)) { 1277 ptree_clear_all(K, sym_ls); 1278 klispE_throw_simple_with_irritants(K, "repeated symbol " 1279 "in ptree", 1, top); 1280 return KNIL; 1281 } else { 1282 copy = top; 1283 /* add it to the symbol list */ 1284 kset_symbol_mark(top, sym_ls); 1285 sym_ls = top; 1286 } 1287 break; 1288 } 1289 case K_TPAIR: { 1290 if (kis_unmarked(top)) { 1291 if (kis_immutable(top)) { 1292 /* don't copy mutable pairs, just use them */ 1293 /* NOTE: immutable pairs can't have mutable 1294 car or cdr */ 1295 /* we have to continue thou, because there could be a 1296 cycle */ 1297 kset_mark(top, top); 1298 } else { 1299 /* create a new pair as copy, save it in the mark */ 1300 TValue new_pair = kimm_cons(K, KNIL, KNIL); 1301 kset_mark(top, new_pair); 1302 /* copy the source code info */ 1303 TValue si = ktry_get_si(K, top); 1304 if (!ttisnil(si)) 1305 kset_source_info(K, new_pair, si); 1306 } 1307 /* keep the old pair and continue with the car */ 1308 ks_tbpush(K, ST_CAR); 1309 ks_spush(K, top); 1310 1311 ks_tbpush(K, ST_PUSH); 1312 ks_spush(K, kcar(top)); 1313 } else { 1314 /* marked pair means a cycle was found */ 1315 /* NOTE: the pair should be in the stack already so 1316 it isn't necessary to push it again to clear the mark */ 1317 ptree_clear_all(K, sym_ls); 1318 klispE_throw_simple(K, "cycle detected in ptree"); 1319 /* avoid warning */ 1320 return KNIL; 1321 } 1322 break; 1323 } 1324 default: 1325 ptree_clear_all(K, sym_ls); 1326 klispE_throw_simple(K, "bad object type in ptree"); 1327 /* avoid warning */ 1328 return KNIL; 1329 } 1330 } else { 1331 /* last operation was a pop */ 1332 /* top is a marked pair, the mark is the copied obj */ 1333 /* NOTE: if top is immutable the mark is also top 1334 we could still do the set-car/set-cdr because the 1335 copy would be the same as the car/cdr, but why bother */ 1336 if (state == ST_CAR) { 1337 /* only car was checked (not yet copied) */ 1338 if (kis_mutable(top)) { 1339 TValue copied_pair = kget_mark(top); 1340 /* copied_pair may be immutable */ 1341 kset_car_unsafe(K, copied_pair, copy); 1342 } 1343 /* put the copied pair again, continue with the cdr */ 1344 ks_tbpush(K, ST_CDR); 1345 ks_spush(K, top); 1346 1347 ks_tbpush(K, ST_PUSH); 1348 ks_spush(K, kcdr(top)); 1349 } else { 1350 /* both car & cdr were checked (cdr not yet copied) */ 1351 TValue copied_pair = kget_mark(top); 1352 /* the unmark is needed to allow diamonds */ 1353 kunmark(top); 1354 1355 if (kis_mutable(top)) { 1356 /* copied_pair may be immutable */ 1357 kset_cdr_unsafe(K, copied_pair, copy); 1358 } 1359 copy = copied_pair; 1360 } 1361 } 1362 } 1363 1364 if (ttissymbol(penv)) { 1365 if (kis_symbol_marked(penv)) { 1366 ptree_clear_all(K, sym_ls); 1367 klispE_throw_simple_with_irritants(K, "same symbol in both ptree " 1368 "and environment parameter", 1369 1, sym_ls); 1370 } 1371 } else if (!ttisignore(penv)) { 1372 ptree_clear_all(K, sym_ls); 1373 klispE_throw_simple(K, "symbol or #ignore expected as " 1374 "environment parmameter"); 1375 } 1376 ptree_clear_all(K, sym_ls); 1377 krooted_vars_pop(K); 1378 return copy; 1379 } 1380 1381 /* Helpers for map (also used by for each) */ 1382 void map_for_each_get_metrics(klisp_State *K, TValue lss, 1383 int32_t *app_apairs_out, int32_t *app_cpairs_out, 1384 int32_t *res_apairs_out, int32_t *res_cpairs_out) 1385 { 1386 /* avoid warnings (shouldn't happen if _No_return was used in throw) */ 1387 *app_apairs_out = 0; 1388 *app_cpairs_out = 0; 1389 *res_apairs_out = 0; 1390 *res_cpairs_out = 0; 1391 1392 /* get the metrics of the ptree of each call to app */ 1393 int32_t app_pairs, app_cpairs; 1394 check_list(K, true, lss, &app_pairs, &app_cpairs); 1395 int32_t app_apairs = app_pairs - app_cpairs; 1396 1397 /* get the metrics of the result list */ 1398 int32_t res_pairs, res_cpairs; 1399 /* We now that lss has at least one elem */ 1400 check_list(K, true, kcar(lss), &res_pairs, &res_cpairs); 1401 int32_t res_apairs = res_pairs - res_cpairs; 1402 1403 if (res_cpairs == 0) { 1404 /* finite list of length res_pairs (all lists should 1405 have the same structure: acyclic with same length) */ 1406 int32_t pairs = app_pairs - 1; 1407 TValue tail = kcdr(lss); 1408 while(pairs--) { 1409 int32_t first_pairs, first_cpairs; 1410 check_list(K, true, kcar(tail), &first_pairs, &first_cpairs); 1411 tail = kcdr(tail); 1412 1413 if (first_cpairs != 0) { 1414 klispE_throw_simple(K, "mixed finite and infinite lists"); 1415 return; 1416 } else if (first_pairs != res_pairs) { 1417 klispE_throw_simple(K, "lists of different length"); 1418 return; 1419 } 1420 } 1421 } else { 1422 /* cyclic list: all lists should be cyclic. 1423 result will have acyclic length equal to the 1424 max of all the lists and cyclic length equal to the lcm 1425 of all the lists. res_pairs may be broken but will be 1426 restored by after the loop */ 1427 int32_t pairs = app_pairs - 1; 1428 TValue tail = kcdr(lss); 1429 while(pairs--) { 1430 int32_t first_pairs, first_cpairs; 1431 check_list(K, true, kcar(tail), &first_pairs, &first_cpairs); 1432 int32_t first_apairs = first_pairs - first_cpairs; 1433 tail = kcdr(tail); 1434 1435 if (first_cpairs == 0) { 1436 klispE_throw_simple(K, "mixed finite and infinite lists"); 1437 return; 1438 } 1439 res_apairs = kmax32(res_apairs, first_apairs); 1440 /* this can throw an error if res_cpairs doesn't 1441 fit in 32 bits, which is a reasonable implementation 1442 restriction because the list wouldn't fit in memory 1443 anyways */ 1444 res_cpairs = kcheck32(K, "map/for-each: result list is too big", 1445 klcm32_64(res_cpairs, first_cpairs)); 1446 } 1447 res_pairs = kcheck32(K, "map/for-each: result list is too big", 1448 (int64_t) res_cpairs + (int64_t) res_apairs); 1449 UNUSED(res_pairs); 1450 } 1451 1452 *app_apairs_out = app_apairs; 1453 *app_cpairs_out = app_cpairs; 1454 *res_apairs_out = res_apairs; 1455 *res_cpairs_out = res_cpairs; 1456 } 1457 1458 /* Return two lists, isomorphic to lss: one list of cars and one list 1459 of cdrs (replacing the value of lss) */ 1460 1461 /* GC: assumes lss is rooted */ 1462 TValue map_for_each_get_cars_cdrs(klisp_State *K, TValue *lss, 1463 int32_t apairs, int32_t cpairs) 1464 { 1465 TValue tail = *lss; 1466 1467 TValue cars = kcons(K, KNIL, KNIL); 1468 krooted_vars_push(K, &cars); 1469 TValue lp_cars = cars; 1470 TValue lap_cars = lp_cars; 1471 1472 TValue cdrs = kcons(K, KNIL, KNIL); 1473 krooted_vars_push(K, &cdrs); 1474 TValue lp_cdrs = cdrs; 1475 TValue lap_cdrs = lp_cdrs; 1476 1477 while(apairs != 0 || cpairs != 0) { 1478 int32_t pairs; 1479 if (apairs != 0) { 1480 pairs = apairs; 1481 } else { 1482 /* remember last acyclic pair of both lists to to encycle! later */ 1483 lap_cars = lp_cars; 1484 lap_cdrs = lp_cdrs; 1485 pairs = cpairs; 1486 } 1487 1488 while(pairs--) { 1489 TValue first = kcar(tail); 1490 tail = kcdr(tail); 1491 1492 /* accumulate both cars and cdrs */ 1493 TValue np; 1494 np = kcons(K, kcar(first), KNIL); 1495 kset_cdr(lp_cars, np); 1496 lp_cars = np; 1497 1498 np = kcons(K, kcdr(first), KNIL); 1499 kset_cdr(lp_cdrs, np); 1500 lp_cdrs = np; 1501 } 1502 1503 if (apairs != 0) { 1504 apairs = 0; 1505 } else { 1506 cpairs = 0; 1507 /* encycle! the list of cars and the list of cdrs */ 1508 TValue fcp, lcp; 1509 fcp = kcdr(lap_cars); 1510 lcp = lp_cars; 1511 kset_cdr(lcp, fcp); 1512 1513 fcp = kcdr(lap_cdrs); 1514 lcp = lp_cdrs; 1515 kset_cdr(lcp, fcp); 1516 } 1517 } 1518 1519 krooted_vars_pop(K); 1520 krooted_vars_pop(K); 1521 *lss = kcdr(cdrs); 1522 return kcdr(cars); 1523 } 1524 1525 /* Transpose lss so that the result is a list of lists, each one having 1526 metrics (app_apairs, app_cpairs). The metrics of the returned list 1527 should be (res_apairs, res_cpairs) */ 1528 1529 /* GC: assumes lss is rooted */ 1530 TValue map_for_each_transpose(klisp_State *K, TValue lss, 1531 int32_t app_apairs, int32_t app_cpairs, 1532 int32_t res_apairs, int32_t res_cpairs) 1533 { 1534 TValue tlist = kcons(K, KNIL, KNIL); 1535 krooted_vars_push(K, &tlist); 1536 TValue lp = tlist; 1537 TValue lap = lp; 1538 1539 TValue cars = KNIL; /* put something for GC */ 1540 TValue tail = lss; 1541 1542 /* GC: both cars & tail vary in each loop, to protect them we need 1543 the vars stack */ 1544 krooted_vars_push(K, &cars); 1545 krooted_vars_push(K, &tail); 1546 1547 /* Loop over list of lists, creating a list of cars and 1548 a list of cdrs, accumulate the list of cars and loop 1549 with the list of cdrs as the new list of lists (lss) */ 1550 while(res_apairs != 0 || res_cpairs != 0) { 1551 int32_t pairs; 1552 1553 if (res_apairs != 0) { 1554 pairs = res_apairs; 1555 } else { 1556 pairs = res_cpairs; 1557 /* remember last acyclic pair to encycle! later */ 1558 lap = lp; 1559 } 1560 1561 while(pairs--) { 1562 /* accumulate cars and replace tail with cdrs */ 1563 cars = map_for_each_get_cars_cdrs(K, &tail, app_apairs, app_cpairs); 1564 TValue np = kcons(K, cars, KNIL); 1565 kset_cdr(lp, np); 1566 lp = np; 1567 } 1568 1569 if (res_apairs != 0) { 1570 res_apairs = 0; 1571 } else { 1572 res_cpairs = 0; 1573 /* encycle! the list of list of cars */ 1574 TValue fcp = kcdr(lap); 1575 TValue lcp = lp; 1576 kset_cdr(lcp, fcp); 1577 } 1578 } 1579 1580 krooted_vars_pop(K); 1581 krooted_vars_pop(K); 1582 krooted_vars_pop(K); 1583 return kcdr(tlist); 1584 } 1585 1586 /* Continuations that are used in more than one file */ 1587 1588 /* Helper for $sequence, $vau, $lambda, ... */ 1589 /* the remaining list can't be null, that case is managed before */ 1590 void do_seq(klisp_State *K) 1591 { 1592 TValue *xparams = K->next_xparams; 1593 TValue obj = K->next_value; 1594 klisp_assert(ttisnil(K->next_env)); 1595 1596 UNUSED(obj); 1597 1598 /* 1599 ** xparams[0]: remaining list 1600 ** xparams[1]: dynamic environment 1601 */ 1602 TValue ls = xparams[0]; 1603 TValue first = kcar(ls); 1604 TValue tail = kcdr(ls); 1605 TValue denv = xparams[1]; 1606 1607 if (ttispair(tail)) { 1608 TValue new_cont = kmake_continuation(K, kget_cc(K), do_seq, 2, tail, 1609 denv); 1610 kset_cc(K, new_cont); 1611 #if KTRACK_SI 1612 /* put the source info of the list including the element 1613 that we are about to evaluate */ 1614 kset_source_info(K, new_cont, ktry_get_si(K, ls)); 1615 #endif 1616 } 1617 ktail_eval(K, first, denv); 1618 } 1619 1620 /* this is used for inner & outer continuations, it just 1621 passes the value. xparams is not actually empty, it contains 1622 the entry/exit guards, but they are used only in 1623 continuation->applicative (that is during abnormal passes) */ 1624 void do_pass_value(klisp_State *K) 1625 { 1626 TValue *xparams = K->next_xparams; 1627 TValue obj = K->next_value; 1628 klisp_assert(ttisnil(K->next_env)); 1629 UNUSED(xparams); 1630 kapply_cc(K, obj); 1631 } 1632 1633 /* 1634 ** Continuation that ignores the value received and instead returns 1635 ** a previously computed value. 1636 */ 1637 void do_return_value(klisp_State *K) 1638 { 1639 TValue *xparams = K->next_xparams; 1640 TValue obj = K->next_value; 1641 klisp_assert(ttisnil(K->next_env)); 1642 /* 1643 ** xparams[0]: saved_obj 1644 */ 1645 UNUSED(obj); 1646 TValue ret_obj = xparams[0]; 1647 kapply_cc(K, ret_obj); 1648 } 1649 1650 /* binder returned */ 1651 void do_bind(klisp_State *K) 1652 { 1653 TValue *xparams = K->next_xparams; 1654 TValue ptree = K->next_value; 1655 TValue denv = K->next_env; 1656 klisp_assert(ttisenvironment(K->next_env)); 1657 /* 1658 ** xparams[0]: dynamic key 1659 */ 1660 bind_2tp(K, ptree, "any", anytype, obj, 1661 "combiner", ttiscombiner, comb); 1662 UNUSED(denv); /* the combiner is called in an empty environment */ 1663 TValue key = xparams[0]; 1664 /* GC: root intermediate objs */ 1665 TValue new_flag = KTRUE; 1666 TValue new_value = obj; 1667 TValue old_flag = kcar(key); 1668 TValue old_value = kcdr(key); 1669 /* set the var to the new object */ 1670 kset_car(key, new_flag); 1671 kset_cdr(key, new_value); 1672 /* Old value must be protected from GC. It is no longer 1673 reachable through key and not yet reachable through 1674 continuation xparams. Boolean flag needn't be rooted, 1675 because is not heap-allocated. */ 1676 krooted_tvs_push(K, old_value); 1677 /* create a continuation to set the var to the correct value/flag on both 1678 normal return and abnormal passes */ 1679 TValue new_cont = make_bind_continuation(K, key, old_flag, old_value, 1680 new_flag, new_value); 1681 krooted_tvs_pop(K); 1682 kset_cc(K, new_cont); /* implicit rooting */ 1683 TValue env = kmake_empty_environment(K); 1684 krooted_tvs_push(K, env); 1685 TValue expr = kcons(K, comb, KNIL); 1686 krooted_tvs_pop(K); 1687 ktail_eval(K, expr, env) 1688 } 1689 1690 /* accesor returned */ 1691 void do_access(klisp_State *K) 1692 { 1693 TValue *xparams = K->next_xparams; 1694 TValue ptree = K->next_value; 1695 TValue denv = K->next_env; 1696 klisp_assert(ttisenvironment(K->next_env)); 1697 /* 1698 ** xparams[0]: dynamic key 1699 */ 1700 check_0p(K, ptree); 1701 UNUSED(denv); 1702 TValue key = xparams[0]; 1703 1704 if (kis_true(kcar(key))) { 1705 kapply_cc(K, kcdr(key)); 1706 } else { 1707 klispE_throw_simple(K, "variable is unbound"); 1708 return; 1709 } 1710 } 1711 1712 /* continuation to set the key to the old value on normal return */ 1713 void do_unbind(klisp_State *K) 1714 { 1715 TValue *xparams = K->next_xparams; 1716 TValue obj = K->next_value; 1717 klisp_assert(ttisnil(K->next_env)); 1718 /* 1719 ** xparams[0]: dynamic key 1720 ** xparams[1]: old flag 1721 ** xparams[2]: old value 1722 */ 1723 1724 TValue key = xparams[0]; 1725 TValue old_flag = xparams[1]; 1726 TValue old_value = xparams[2]; 1727 1728 kset_car(key, old_flag); 1729 kset_cdr(key, old_value); 1730 /* pass along the value returned to this continuation */ 1731 kapply_cc(K, obj); 1732 } 1733 1734 /* operative for setting the key to the new/old flag/value */ 1735 void do_set_pass(klisp_State *K) 1736 { 1737 TValue *xparams = K->next_xparams; 1738 TValue ptree = K->next_value; 1739 TValue denv = K->next_env; 1740 klisp_assert(ttisenvironment(K->next_env)); 1741 /* 1742 ** xparams[0]: dynamic key 1743 ** xparams[1]: flag 1744 ** xparams[2]: value 1745 */ 1746 TValue key = xparams[0]; 1747 TValue flag = xparams[1]; 1748 TValue value = xparams[2]; 1749 UNUSED(denv); 1750 1751 kset_car(key, flag); 1752 kset_cdr(key, value); 1753 1754 /* pass to next interceptor/ final destination */ 1755 /* ptree is as for interceptors: (obj divert) */ 1756 TValue obj = kcar(ptree); 1757 kapply_cc(K, obj); 1758 } 1759 1760 /* /Continuations that are used in more than one file */ 1761 1762 /* dynamic keys */ 1763 /* create continuation to set the key on both normal return and 1764 abnormal passes */ 1765 /* TODO: reuse the code for guards in kgcontinuations.c */ 1766 1767 /* GC: this assumes that key, old_value and new_value are rooted */ 1768 TValue make_bind_continuation(klisp_State *K, TValue key, 1769 TValue old_flag, TValue old_value, 1770 TValue new_flag, TValue new_value) 1771 { 1772 TValue unbind_cont = kmake_continuation(K, kget_cc(K), 1773 do_unbind, 3, key, old_flag, 1774 old_value); 1775 krooted_tvs_push(K, unbind_cont); 1776 /* create the guards to guarantee that the values remain consistent on 1777 abnormal passes (in both directions) */ 1778 TValue exit_int = kmake_operative(K, do_set_pass, 1779 3, key, old_flag, old_value); 1780 krooted_tvs_push(K, exit_int); 1781 TValue exit_guard = kcons(K, G(K)->root_cont, exit_int); 1782 krooted_tvs_pop(K); /* already rooted in guard */ 1783 krooted_tvs_push(K, exit_guard); 1784 TValue exit_guards = kcons(K, exit_guard, KNIL); 1785 krooted_tvs_pop(K); /* already rooted in guards */ 1786 krooted_tvs_push(K, exit_guards); 1787 1788 TValue entry_int = kmake_operative(K, do_set_pass, 1789 3, key, new_flag, new_value); 1790 krooted_tvs_push(K, entry_int); 1791 TValue entry_guard = kcons(K, G(K)->root_cont, entry_int); 1792 krooted_tvs_pop(K); /* already rooted in guard */ 1793 krooted_tvs_push(K, entry_guard); 1794 TValue entry_guards = kcons(K, entry_guard, KNIL); 1795 krooted_tvs_pop(K); /* already rooted in guards */ 1796 krooted_tvs_push(K, entry_guards); 1797 1798 1799 /* NOTE: in the stack now we have the unbind cont & two guard lists */ 1800 /* this is needed for interception code */ 1801 TValue env = kmake_empty_environment(K); 1802 krooted_tvs_push(K, env); 1803 TValue outer_cont = kmake_continuation(K, unbind_cont, 1804 do_pass_value, 2, entry_guards, env); 1805 kset_outer_cont(outer_cont); 1806 krooted_tvs_push(K, outer_cont); 1807 TValue inner_cont = kmake_continuation(K, outer_cont, 1808 do_pass_value, 2, exit_guards, env); 1809 kset_inner_cont(inner_cont); 1810 1811 /* unbind_cont & 2 guard_lists */ 1812 krooted_tvs_pop(K); krooted_tvs_pop(K); krooted_tvs_pop(K); 1813 /* env & outer_cont */ 1814 krooted_tvs_pop(K); krooted_tvs_pop(K); 1815 1816 return inner_cont; 1817 } 1818 1819 /* Helpers for guard-continuation (& guard-dynamic-extent) */ 1820 1821 #define singly_wrapped(obj_) (ttisapplicative(obj_) && \ 1822 ttisoperative(kunwrap(obj_))) 1823 1824 /* this unmarks root before throwing any error */ 1825 /* TODO: this isn't very clean, refactor */ 1826 1827 /* GC: assumes obj & root are rooted */ 1828 static inline TValue check_copy_single_entry(klisp_State *K, char *name, 1829 TValue obj, TValue root) 1830 { 1831 if (!ttispair(obj) || !ttispair(kcdr(obj)) || 1832 !ttisnil(kcddr(obj))) { 1833 unmark_list(K, root); 1834 klispE_throw_simple(K, "Bad entry (expected list of length 2)"); 1835 return KINERT; 1836 } 1837 TValue cont = kcar(obj); 1838 TValue app = kcadr(obj); 1839 1840 if (!ttiscontinuation(cont)) { 1841 unmark_list(K, root); 1842 klispE_throw_simple(K, "Bad type on first element (expected " 1843 "continuation)"); 1844 return KINERT; 1845 } else if (!singly_wrapped(app)) { 1846 unmark_list(K, root); 1847 klispE_throw_simple(K, "Bad type on second element (expected " 1848 "singly wrapped applicative)"); 1849 return KINERT; 1850 } 1851 1852 /* save the operative directly, don't waste space/time 1853 with a list, use just a pair */ 1854 return kcons(K, cont, kunwrap(app)); 1855 } 1856 1857 /* the guards are probably generated on the spot so we don't check 1858 for immutability and copy it anyways */ 1859 /* GC: Assumes obj is rooted */ 1860 TValue check_copy_guards(klisp_State *K, char *name, TValue obj) 1861 { 1862 if (ttisnil(obj)) { 1863 return obj; 1864 } else { 1865 TValue copy = kcons(K, KNIL, KNIL); 1866 krooted_vars_push(K, ©); 1867 TValue last_pair = copy; 1868 TValue tail = obj; 1869 1870 while(ttispair(tail) && !kis_marked(tail)) { 1871 /* this will clear the marks and throw an error if the structure 1872 is incorrect */ 1873 TValue entry = check_copy_single_entry(K, name, kcar(tail), obj); 1874 krooted_tvs_push(K, entry); 1875 TValue new_pair = kcons(K, entry, KNIL); 1876 krooted_tvs_pop(K); 1877 kmark(tail); 1878 kset_cdr(last_pair, new_pair); 1879 last_pair = new_pair; 1880 tail = kcdr(tail); 1881 } 1882 1883 /* dont close the cycle (if there is one) */ 1884 unmark_list(K, obj); 1885 if (!ttispair(tail) && !ttisnil(tail)) { 1886 klispE_throw_simple(K, "expected list"); 1887 return KINERT; 1888 } 1889 krooted_vars_pop(K); 1890 return kcdr(copy); 1891 } 1892 } 1893 1894 void guard_dynamic_extent(klisp_State *K) 1895 { 1896 TValue *xparams = K->next_xparams; 1897 TValue ptree = K->next_value; 1898 TValue denv = K->next_env; 1899 klisp_assert(ttisenvironment(K->next_env)); 1900 UNUSED(xparams); 1901 1902 bind_3tp(K, ptree, "any", anytype, entry_guards, 1903 "combiner", ttiscombiner, comb, 1904 "any", anytype, exit_guards); 1905 1906 entry_guards = check_copy_guards(K, "guard-dynamic-extent: entry guards", 1907 entry_guards); 1908 krooted_tvs_push(K, entry_guards); 1909 exit_guards = check_copy_guards(K, "guard-dynamic-extent: exit guards", 1910 exit_guards); 1911 krooted_tvs_push(K, exit_guards); 1912 /* GC: root continuations */ 1913 /* The current continuation is guarded */ 1914 TValue outer_cont = kmake_continuation(K, kget_cc(K), do_pass_value, 1915 2, entry_guards, denv); 1916 kset_outer_cont(outer_cont); 1917 kset_cc(K, outer_cont); /* this implicitly roots outer_cont */ 1918 1919 TValue inner_cont = kmake_continuation(K, outer_cont, do_pass_value, 2, 1920 exit_guards, denv); 1921 kset_inner_cont(inner_cont); 1922 1923 /* call combiner with no operands in the dynamic extent of inner, 1924 with the dynamic env of this call */ 1925 kset_cc(K, inner_cont); /* this implicitly roots inner_cont */ 1926 TValue expr = kcons(K, comb, KNIL); 1927 1928 krooted_tvs_pop(K); 1929 krooted_tvs_pop(K); 1930 1931 ktail_eval(K, expr, denv); 1932 } 1933 1934 1935 void do_int_mark_error(klisp_State *K) 1936 { 1937 TValue *xparams = K->next_xparams; 1938 TValue ptree = K->next_value; 1939 TValue denv = K->next_env; 1940 klisp_assert(ttisenvironment(K->next_env)); 1941 /* 1942 ** xparams[0]: errorp pointer 1943 */ 1944 UNUSED(denv); 1945 bool *errorp = (bool *) pvalue(xparams[0]); 1946 *errorp = true; 1947 /* ptree is (object divert) */ 1948 TValue error_obj = kcar(ptree); 1949 /* pass the error along after setting the flag */ 1950 kapply_cc(K, error_obj); 1951 } 1952 1953 void do_int_mark_root(klisp_State *K) 1954 { 1955 TValue *xparams = K->next_xparams; 1956 TValue obj = K->next_value; 1957 klisp_assert(ttisnil(K->next_env)); 1958 /* 1959 ** xparams[0]: rootp pointer 1960 */ 1961 UNUSED(obj); /* ignore obj */ 1962 bool *rootp = (bool *) pvalue(xparams[0]); 1963 *rootp = false; /* mark that we didn't explicitly call the root cont */ 1964 /* pass #INERT to the root continuation */ 1965 kapply_cc(K, KINERT); 1966 }