Boron 2.1.0
datatypes.c
1/*
2 Copyright 2009-2024 Karl Robillard
3
4 This file is part of the Urlan datatype system.
5
6 Urlan is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Urlan is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with Urlan. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20
149
217
218
219#include "urlan_atoms.h"
220
221
222//#define ANY3(c,t1,t2,t3) ((1<<ur_type(c)) & ((1<<t1) | (1<<t2) | (1<<t3)))
223
224#define DT(dt) (ut->types[ dt ])
225#define SERIES_DT(dt) ((const USeriesType*) (ut->types[ dt ]))
226#define bitIsSet(mem,n) (mem[(n)>>3] & 1<<((n)&7))
227
228#define block_destroy ur_arrFree
229#define string_destroy ur_arrFree
230#define context_markBuf block_markBuf
231
232void block_markBuf( UThread* ut, UBuffer* buf );
233
234
235typedef struct
236{
237 UIndex small;
238 UIndex large;
239 char secondLarger;
240}
241USizeOrder;
242
243
244void ur_sizeOrder( USizeOrder* ord, UIndex a, UIndex b )
245{
246 if( a >= b )
247 {
248 ord->small = b;
249 ord->large = a;
250 ord->secondLarger = 0;
251 }
252 else
253 {
254 ord->small = a;
255 ord->large = b;
256 ord->secondLarger = 1;
257 }
258}
259
260
261//----------------------------------------------------------------------------
262// UT_UNSET
263
264
265int unset_make( UThread* ut, const UCell* from, UCell* res )
266{
267 (void) ut;
268 (void) from;
269 ur_setId(res, UT_UNSET);
270 return UR_OK;
271}
272
273void unset_copy( UThread* ut, const UCell* from, UCell* res )
274{
275 (void) ut;
276 *res = *from;
277}
278
279int unset_compare( UThread* ut, const UCell* a, const UCell* b, int test )
280{
281 (void) ut;
282 (void) a;
283 (void) b;
284 (void) test;
285 return 0;
286}
287
288static const char* operatorNames[] =
289{
290 "add", "sub", "mul", "div", "mod", "and", "or", "xor"
291};
292
293int unset_operate( UThread* ut, const UCell* a, const UCell* b, UCell* res,
294 int op )
295{
296 (void) res;
297 return ur_error( ut, UR_ERR_SCRIPT, "%s operator is unset for types %s %s",
298 operatorNames[ op & 7 ],
299 ur_atomCStr(ut, ur_type(a)),
300 ur_atomCStr(ut, ur_type(b)) );
301}
302
303const UCell* unset_select( UThread* ut, const UCell* cell, const UCell* sel,
304 UCell* tmp )
305{
306 (void) cell;
307 (void) sel;
308 (void) tmp;
309 ur_error( ut, UR_ERR_SCRIPT, "Select method is unset for type %s",
310 ur_atomCStr(ut, ur_type(cell)) );
311 return 0;
312}
313
314void unset_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
315{
316 (void) depth;
317 ur_strAppendChar( str, '~' );
318 ur_strAppendCStr( str, ur_atomCStr(ut, ur_type(cell)) );
319 ur_strAppendChar( str, '~' );
320}
321
322void unset_mark( UThread* ut, UCell* cell )
323{
324 (void) ut;
325 (void) cell;
326}
327
328void unset_destroy( UBuffer* buf )
329{
330 (void) buf;
331}
332
333void unset_toShared( UCell* cell )
334{
335 (void) cell;
336}
337
338void unset_bind( UThread* ut, UCell* cell, const UBindTarget* bt )
339{
340 (void) ut;
341 (void) cell;
342 (void) bt;
343}
344
345
346#define unset_recycle 0
347#define unset_markBuf 0
348
349
350UDatatype dt_unset =
351{
352 "unset!",
353 unset_make, unset_make, unset_copy,
354 unset_compare, unset_operate, unset_select,
355 unset_toString, unset_toString,
356 unset_recycle, unset_mark, unset_destroy,
357 unset_markBuf, unset_toShared, unset_bind
358};
359
360
361//----------------------------------------------------------------------------
362// UT_DATATYPE
363
367
376int ur_isDatatype( const UCell* cell, const UCell* datatype )
377{
378 uint32_t dt = ur_type(cell);
379 if( dt < 32 )
380 return datatype->datatype.mask0 & (1 << dt);
381 else
382 return datatype->datatype.mask1 & (1 << (dt - 32));
383}
384
385
389void ur_makeDatatype( UCell* cell, int type )
390{
391 ur_setId(cell, UT_DATATYPE);
392 ur_datatype(cell) = type;
393 if( type < 32 )
394 {
395 cell->datatype.mask0 = 1 << type;
396 cell->datatype.mask1 = cell->datatype.mask2 = 0;
397 }
398 else if( type < 64 )
399 {
400 cell->datatype.mask1 = 1 << (type - 32);
401 cell->datatype.mask0 = cell->datatype.mask2 = 0;
402 }
403 else
404 {
405 cell->datatype.mask1 =
406 cell->datatype.mask0 = cell->datatype.mask2 = 0xffffffff;
407 }
408}
409
410
414void ur_datatypeAddType( UCell* cell, int type )
415{
416 uint32_t* mp;
417 uint32_t mask;
418
419 if( type < 32 )
420 {
421 mp = &cell->datatype.mask0;
422 mask = 1 << type;
423 }
424 else if( type < 64 )
425 {
426 mp = &cell->datatype.mask1;
427 mask = 1 << (type - 32);
428 }
429 else
430 {
431 mp = &cell->datatype.mask2;
432 mask = 1 << (type - 64);
433 }
434
435 if( ! (mask & *mp) )
436 {
437 *mp |= mask;
438 cell->datatype.n = UT_TYPEMASK;
439 }
440}
441
442
443#if 0
444/*
445 If cell is any word and it has a datatype name then that type is returned.
446 Otherwise the datatype of the cell is returned.
447*/
448static int _wordType( UThread* ut, const UCell* cell )
449{
450 int type = ur_type(cell);
451 if( ur_isWordType(type) && (ur_atom(cell) < ur_datatypeCount(ut)) )
452 type = ur_atom(cell);
453 return type;
454}
455#endif
456
457
458int datatype_make( UThread* ut, const UCell* from, UCell* res )
459{
460 (void) ut;
461 ur_makeDatatype( res, ur_type(from) );
462 return UR_OK;
463}
464
465
466int datatype_compare( UThread* ut, const UCell* a, const UCell* b, int test )
467{
468 (void) ut;
469 switch( test )
470 {
471 case UR_COMPARE_SAME:
472 if( ur_datatype(a) == ur_datatype(b) )
473 {
474 if( ur_datatype(a) != UT_TYPEMASK )
475 return 1;
476 return ((a->datatype.mask0 == b->datatype.mask0) &&
477 (a->datatype.mask1 == b->datatype.mask1));
478 }
479 break;
480
481 case UR_COMPARE_EQUAL:
482 case UR_COMPARE_EQUAL_CASE:
483 if( ur_type(a) == ur_type(b) )
484 {
485 return ((a->datatype.mask0 & b->datatype.mask0) ||
486 (a->datatype.mask1 & b->datatype.mask1));
487 }
488 break;
489
490 case UR_COMPARE_ORDER:
491 case UR_COMPARE_ORDER_CASE:
492 if( ur_type(a) == ur_type(b) )
493 {
494 if( ur_datatype(a) > ur_datatype(b) )
495 return 1;
496 if( ur_datatype(a) < ur_datatype(b) )
497 return -1;
498 // Order of two multi-types is undefined.
499 }
500 break;
501 }
502 return 0;
503}
504
505
506void datatype_toString(UThread* ut, const UCell* cell, UBuffer* str, int depth)
507{
508 int dt = ur_datatype(cell);
509 (void) depth;
510 if( dt < UT_MAX )
511 {
512 ur_strAppendCStr( str, ur_atomCStr( ut, dt ) );
513 }
514 else
515 {
516 uint32_t mask;
517 uint32_t dtBits;
518
519 dt = 0;
520 dtBits = cell->datatype.mask0;
521loop:
522 for( mask = 1; dtBits; ++dt, mask <<= 1 )
523 {
524 if( mask & dtBits )
525 {
526 dtBits &= ~mask;
527 ur_strAppendCStr( str, ur_atomCStr( ut, dt ) );
528 ur_strAppendChar( str, '/' );
529 }
530 }
531 if( dt <= 32 )
532 {
533 if( (dtBits = cell->datatype.mask1) )
534 {
535 dt = 32;
536 goto loop;
537 }
538 }
539 --str->used; // Remove extra '/'.
540 }
541}
542
543
544UDatatype dt_datatype =
545{
546 "datatype!",
547 datatype_make, datatype_make, unset_copy,
548 datatype_compare, unset_operate, unset_select,
549 datatype_toString, datatype_toString,
550 unset_recycle, unset_mark, unset_destroy,
551 unset_markBuf, unset_toShared, unset_bind
552};
553
554
555//----------------------------------------------------------------------------
556// UT_NONE
557
558
559int none_make( UThread* ut, const UCell* from, UCell* res )
560{
561 (void) ut;
562 (void) from;
563 ur_setId(res, UT_NONE);
564 return UR_OK;
565}
566
567
568int none_compare( UThread* ut, const UCell* a, const UCell* b, int test )
569{
570 (void) ut;
571 switch( test )
572 {
573 case UR_COMPARE_SAME:
574 case UR_COMPARE_EQUAL:
575 case UR_COMPARE_EQUAL_CASE:
576 return ur_type(a) == ur_type(b);
577 }
578 return 0;
579}
580
581
582void none_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
583{
584 (void) ut;
585 (void) cell;
586 (void) depth;
587 ur_strAppendCStr( str, "none" );
588}
589
590
591UDatatype dt_none =
592{
593 "none!",
594 none_make, none_make, unset_copy,
595 none_compare, unset_operate, unset_select,
596 none_toString, none_toString,
597 unset_recycle, unset_mark, unset_destroy,
598 unset_markBuf, unset_toShared, unset_bind
599};
600
601
602//----------------------------------------------------------------------------
603// UT_LOGIC
604
605
606int logic_make( UThread* ut, const UCell* from, UCell* res )
607{
608 (void) ut;
609 ur_setId(res, UT_LOGIC);
610 switch( ur_type(from) )
611 {
612 case UT_NONE:
613 //ur_logic(res) = 0;
614 break;
615 case UT_LOGIC:
616 ur_logic(res) = ur_logic(from);
617 break;
618 case UT_CHAR:
619 case UT_INT:
620 ur_logic(res) = ur_int(from) ? 1 : 0;
621 break;
622 case UT_DOUBLE:
623 ur_logic(res) = ur_double(from) ? 1 : 0;
624 break;
625 default:
626 ur_logic(res) = 1;
627 break;
628 }
629 return UR_OK;
630}
631
632
633int logic_compare( UThread* ut, const UCell* a, const UCell* b, int test )
634{
635 (void) ut;
636 switch( test )
637 {
638 case UR_COMPARE_SAME:
639 return ur_logic(a) == ur_logic(b);
640
641 case UR_COMPARE_EQUAL:
642 case UR_COMPARE_EQUAL_CASE:
643 if( ur_type(a) == ur_type(b) )
644 return ur_logic(a) == ur_logic(b);
645 break;
646 }
647 return 0;
648}
649
650
651void logic_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
652{
653 (void) ut;
654 (void) depth;
655 ur_strAppendCStr( str, ur_logic(cell) ? "true" : "false" );
656}
657
658
659int logic_operate( UThread* ut, const UCell* a, const UCell* b, UCell* res,
660 int op )
661{
662 int la = ur_is(a, UT_LOGIC) ? ur_logic(a) : 0;
663 int lb = ur_is(b, UT_LOGIC) ? ur_logic(b) : 0;
664
665 ur_setId(res, UT_LOGIC);
666 switch( op )
667 {
668 case UR_OP_AND:
669 ur_logic(res) = la & lb;
670 break;
671 case UR_OP_OR:
672 ur_logic(res) = la | lb;
673 break;
674 case UR_OP_XOR:
675 ur_logic(res) = la ^ lb;
676 break;
677 default:
678 return unset_operate( ut, a, b, res, op );
679 }
680 return UR_OK;
681}
682
683
684UDatatype dt_logic =
685{
686 "logic!",
687 logic_make, logic_make, unset_copy,
688 logic_compare, logic_operate, unset_select,
689 logic_toString, logic_toString,
690 unset_recycle, unset_mark, unset_destroy,
691 unset_markBuf, unset_toShared, unset_bind,
692};
693
694
695//----------------------------------------------------------------------------
696// UT_CHAR
697
698
699int char_make( UThread* ut, const UCell* from, UCell* res )
700{
701 if( ur_is(from, UT_INT) || ur_is(from, UT_CHAR) )
702 {
703 ur_setId(res, UT_CHAR);
704 ur_int(res) = ur_int(from);
705 return UR_OK;
706 }
707 else if( ur_is(from, UT_STRING) )
708 {
709 USeriesIter si;
710 ur_seriesSlice( ut, &si, from );
711 SERIES_DT( UT_STRING )->pick( si.buf, si.it, res );
712 return UR_OK;
713 }
714 return ur_error( ut, UR_ERR_TYPE,
715 "make char! expected char!/int!/string!" );
716}
717
718
719extern int copyUcs2ToUtf8( uint8_t* dest, const uint16_t* src, int srcLen );
720extern char _hexDigits[];
721
722void char_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
723{
724 char tmp[5];
725 char* cstr;
726 uint16_t n = ur_int(cell);
727 (void) ut;
728 (void) depth;
729
730 if( n > 127 )
731 {
732 if( str->form == UR_ENC_UCS2 )
733 {
734 uint16_t* cp;
735 ur_arrReserve( str, str->used + 3 );
736 cp = str->ptr.u16 + str->used;
737 *cp++ = '\'';
738 *cp++ = n;
739 *cp = '\'';
740 str->used += 3;
741 }
742 else
743 {
744 uint8_t* cp;
745 ur_arrReserve( str, str->used + 9 );
746 cp = str->ptr.b + str->used;
747 *cp++ = '\'';
748 if( str->form == UR_ENC_UTF8 )
749 {
750 cp += copyUcs2ToUtf8( cp, &n, 1 );
751 }
752 else
753 {
754 *cp++ = '^';
755 *cp++ = '(';
756 if( n & 0xff00 )
757 {
758 *cp++ = _hexDigits[ ((n >> 12) & 0xf) ];
759 *cp++ = _hexDigits[ ((n >> 8) & 0xf) ];
760 }
761 *cp++ = _hexDigits[ ((n >> 4) & 0xf) ];
762 *cp++ = _hexDigits[ (n & 0xf) ];
763 *cp++ = ')';
764 }
765 *cp++ = '\'';
766 str->used = cp - str->ptr.b;
767 }
768 return;
769 }
770
771 if( n < 16 )
772 {
773 if( n == '\n' )
774 cstr = "'^/'";
775 else if( n == '\t' )
776 cstr = "'^-'";
777 else
778 {
779 cstr = tmp;
780 *cstr++ = '\'';
781 *cstr++ = '^';
782 n += ((n < 11) ? '0' : ('A' - 10));
783 goto close_esc;
784 }
785 }
786 else
787 {
788 cstr = tmp;
789 *cstr++ = '\'';
790 if( n == '^' || n == '\'' )
791 *cstr++ = '^';
792close_esc:
793 *cstr++ = n;
794 *cstr++ = '\'';
795 *cstr = '\0';
796 cstr = tmp;
797 }
798 ur_strAppendCStr( str, cstr );
799}
800
801
802void char_toText( UThread* ut, const UCell* cell, UBuffer* str, int depth )
803{
804 (void) ut;
805 (void) depth;
806 ur_strAppendChar( str, ur_int(cell) );
807}
808
809
810int int_compare( UThread*, const UCell* a, const UCell* b, int test );
811int int_operate( UThread*, const UCell* a, const UCell* b, UCell* res, int op );
812
813UDatatype dt_char =
814{
815 "char!",
816 char_make, char_make, unset_copy,
817 int_compare, int_operate, unset_select,
818 char_toString, char_toText,
819 unset_recycle, unset_mark, unset_destroy,
820 unset_markBuf, unset_toShared, unset_bind
821};
822
823
824//----------------------------------------------------------------------------
825// UT_INT
826
827
828extern int64_t str_toInt64( const uint8_t*, const uint8_t*, const uint8_t** );
829extern int64_t str_hexToInt64(const uint8_t*,const uint8_t*,const uint8_t**);
830
831#define MAKE_NO_UCS2(tn) \
832 ur_error(ut,UR_ERR_INTERNAL,"make %s does not handle UCS2 strings",tn)
833
834int int_make( UThread* ut, const UCell* from, UCell* res )
835{
836 ur_setId(res, UT_INT);
837 switch( ur_type(from) )
838 {
839 case UT_NONE:
840 ur_int(res) = 0;
841 break;
842 case UT_LOGIC:
843 ur_int(res) = ur_logic(from);
844 break;
845 case UT_CHAR:
846 case UT_INT:
847 ur_int(res) = ur_int(from);
848 break;
849 case UT_DOUBLE:
850 case UT_TIME:
851 case UT_DATE:
852 ur_int(res) = ur_double(from);
853 break;
854 case UT_BINARY:
855 case UT_STRING:
856 {
857 USeriesIter si;
858 ur_seriesSlice( ut, &si, from );
859 if( ur_strIsUcs2(si.buf) && ur_is(from, UT_STRING) )
860 {
861 return MAKE_NO_UCS2( "int!" );
862 }
863 else
864 {
865 const uint8_t* cp = si.buf->ptr.b + si.it;
866 const uint8_t* end = si.buf->ptr.b + si.end;
867 if( (si.end - si.it) > 2 && (cp[0] == '0') && (cp[1] == 'x') )
868 {
869 ur_int(res) = str_hexToInt64( cp + 2, end, 0 );
870 ur_setFlags(res, UR_FLAG_INT_HEX);
871 }
872 else
873 ur_int(res) = str_toInt64( cp, end, 0 );
874 }
875 }
876 break;
877 default:
878 return ur_error( ut, UR_ERR_TYPE,
879 "make int! expected number or none!/logic!/char!/string!" );
880 }
881 return UR_OK;
882}
883
884
885#define MASK_CHAR_INT ((1 << UT_CHAR) | (1 << UT_INT))
886#define ur_isIntType(T) ((1 << T) & MASK_CHAR_INT)
887
888int int_compare( UThread* ut, const UCell* a, const UCell* b, int test )
889{
890 (void) ut;
891
892 if( test == UR_COMPARE_SAME )
893 return ur_int(a) == ur_int(b);
894
895 if( ur_isIntType( ur_type(a) ) && ur_isIntType( ur_type(b) ) )
896 {
897 switch( test )
898 {
899 case UR_COMPARE_EQUAL:
900 case UR_COMPARE_EQUAL_CASE:
901 return ur_int(a) == ur_int(b);
902
903 case UR_COMPARE_ORDER:
904 case UR_COMPARE_ORDER_CASE:
905 if( ur_int(a) > ur_int(b) )
906 return 1;
907 if( ur_int(a) < ur_int(b) )
908 return -1;
909 break;
910 }
911 }
912 return 0;
913}
914
915
916int int_operate( UThread* ut, const UCell* a, const UCell* b, UCell* res,
917 int op )
918{
919 if( ur_isIntType( ur_type(a) ) && ur_isIntType( ur_type(b) ) )
920 {
921 ur_setId(res, ur_type(a));
922 switch( op )
923 {
924 case UR_OP_ADD:
925 ur_int(res) = ur_int(a) + ur_int(b);
926 break;
927 case UR_OP_SUB:
928 ur_int(res) = ur_int(a) - ur_int(b);
929 break;
930 case UR_OP_MUL:
931 ur_int(res) = ur_int(a) * ur_int(b);
932 break;
933 case UR_OP_DIV:
934 if( ur_int(b) == 0 )
935 goto div_by_zero;
936 ur_int(res) = ur_int(a) / ur_int(b);
937 break;
938 case UR_OP_MOD:
939 if( ur_int(b) == 0 )
940 goto div_by_zero;
941 ur_int(res) = ur_int(a) % ur_int(b);
942 break;
943 case UR_OP_AND:
944 ur_int(res) = ur_int(a) & ur_int(b);
945 break;
946 case UR_OP_OR:
947 ur_int(res) = ur_int(a) | ur_int(b);
948 break;
949 case UR_OP_XOR:
950 ur_int(res) = ur_int(a) ^ ur_int(b);
951 break;
952 default:
953 return unset_operate( ut, a, b, res, op );
954 }
955 return UR_OK;
956 }
957 else if( ur_is(a, UT_LOGIC) || ur_is(b, UT_LOGIC) )
958 {
959 int va = ur_is(a, UT_LOGIC) ? ur_logic(a) : ur_int(a);
960 int vb = ur_is(b, UT_LOGIC) ? ur_logic(b) : ur_int(b);
961
962 ur_setId(res, ur_type(a));
963 switch( op )
964 {
965 case UR_OP_AND:
966 ur_int(res) = va & vb;
967 break;
968 case UR_OP_OR:
969 ur_int(res) = va | vb;
970 break;
971 case UR_OP_XOR:
972 ur_int(res) = va ^ vb;
973 break;
974 default:
975 return unset_operate( ut, a, b, res, op );
976 }
977 return UR_OK;
978 }
979 return ur_error( ut, UR_ERR_TYPE,
980 "int! operator exepected logic!/char!/int!" );
981
982div_by_zero:
983
984 return ur_error( ut, UR_ERR_SCRIPT, "int! divide by zero" );
985}
986
987
988void int_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
989{
990 (void) ut;
991 (void) depth;
992 if( ur_flags(cell, UR_FLAG_INT_HEX) )
993 {
994 int64_t n = ur_int(cell);
995 ur_strAppendCStr( str, "0x" );
996 ur_strAppendHex( str, n, ((uint64_t) n) >> 32 );
997 }
998 else
999 ur_strAppendInt64( str, ur_int(cell) );
1000}
1001
1002
1003UDatatype dt_int =
1004{
1005 "int!",
1006 int_make, int_make, unset_copy,
1007 int_compare, int_operate, unset_select,
1008 int_toString, int_toString,
1009 unset_recycle, unset_mark, unset_destroy,
1010 unset_markBuf, unset_toShared, unset_bind
1011};
1012
1013
1014//----------------------------------------------------------------------------
1015// UT_DOUBLE
1016
1017
1018extern double str_toDouble( const uint8_t*, const uint8_t*, const uint8_t** );
1019
1020int decimal_make( UThread* ut, const UCell* from, UCell* res )
1021{
1022 ur_setId(res, UT_DOUBLE);
1023 switch( ur_type(from) )
1024 {
1025 case UT_NONE:
1026 ur_double(res) = 0.0;
1027 break;
1028 case UT_LOGIC:
1029 ur_double(res) = (double) ur_logic(from);
1030 break;
1031 case UT_CHAR:
1032 case UT_INT:
1033 ur_double(res) = (double) ur_int(from);
1034 break;
1035 case UT_DOUBLE:
1036 case UT_TIME:
1037 case UT_DATE:
1038 ur_double(res) = ur_double(from);
1039 break;
1040 case UT_STRING:
1041 {
1042 USeriesIter si;
1043 ur_seriesSlice( ut, &si, from );
1044 if( ur_strIsUcs2(si.buf) )
1045 return MAKE_NO_UCS2( "double!" );
1046 else
1047 ur_double(res) = str_toDouble( si.buf->ptr.b + si.it,
1048 si.buf->ptr.b + si.end, 0 );
1049 }
1050 break;
1051 default:
1052 return ur_error( ut, UR_ERR_TYPE,
1053 "make double! expected number or none!/logic!/char!/string!" );
1054 }
1055 return UR_OK;
1056}
1057
1058
1059#define MASK_DECIMAL ((1 << UT_DOUBLE) | (1 << UT_TIME) | (1 << UT_DATE))
1060#define ur_isDecimalType(T) ((1 << T) & MASK_DECIMAL)
1061
1062#define FLOAT_EPSILON (0.00000005960464477539062 * 2.0)
1063
1064// Compare doubles which may have been floats (e.g. vec3! elements).
1065static int float_equal( double a, double b )
1066{
1067 return a >= (b - FLOAT_EPSILON) && a <= (b + FLOAT_EPSILON);
1068}
1069
1070
1071int decimal_compare( UThread* ut, const UCell* a, const UCell* b, int test )
1072{
1073 (void) ut;
1074
1075 switch( test )
1076 {
1077 case UR_COMPARE_SAME:
1078 return ur_double(a) == ur_double(b);
1079
1080 case UR_COMPARE_EQUAL:
1081 case UR_COMPARE_EQUAL_CASE:
1082 if( ur_isDecimalType( ur_type(a) ) )
1083 {
1084 if( ur_isDecimalType( ur_type(b) ) )
1085 return float_equal( ur_double(a), ur_double(b) );
1086 else if( ur_isIntType( ur_type(b) ) )
1087 return float_equal( ur_double(a), ur_int(b) );
1088 }
1089 else
1090 {
1091 if( ur_isIntType( ur_type(a) ) )
1092 return float_equal( (double) ur_int(a), ur_double(b) );
1093 }
1094 break;
1095
1096 case UR_COMPARE_ORDER:
1097 case UR_COMPARE_ORDER_CASE:
1098 if( ur_isDecimalType( ur_type(a) ) )
1099 {
1100 if( ur_isDecimalType( ur_type(b) ) )
1101 {
1102 if( ur_double(a) > ur_double(b) )
1103 return 1;
1104 if( ur_double(a) < ur_double(b) )
1105 return -1;
1106 }
1107 else if( ur_isIntType( ur_type(b) ) )
1108 {
1109 if( ur_double(a) > ur_int(b) )
1110 return 1;
1111 if( ur_double(a) < ur_int(b) )
1112 return -1;
1113 }
1114 }
1115 else
1116 {
1117 if( ur_isIntType( ur_type(a) ) )
1118 {
1119 if( ((double) ur_int(a)) > ur_double(b) )
1120 return 1;
1121 if( ((double) ur_int(a)) < ur_double(b) )
1122 return -1;
1123 }
1124 }
1125 break;
1126 }
1127 return 0;
1128}
1129
1130
1131int decimal_operate( UThread* ut, const UCell* a, const UCell* b, UCell* res,
1132 int op )
1133{
1134 double da;
1135 double db;
1136 int t;
1137
1138 t = ur_type(a);
1139 if( ur_isDecimalType( t ) )
1140 da = ur_double(a);
1141 else if( ur_isIntType( t ) )
1142 da = ur_int(a);
1143 else
1144 goto bad_type;
1145
1146 if( ur_isDecimalType( ur_type(b) ) )
1147 {
1148 if( t < UT_DOUBLE )
1149 t = ur_type(b);
1150 db = ur_double(b);
1151 }
1152 else if( ur_isIntType( ur_type(b) ) )
1153 db = ur_int(b);
1154 else
1155 goto bad_type;
1156
1157 ur_setId(res, t);
1158 switch( op )
1159 {
1160 case UR_OP_ADD:
1161 ur_double(res) = da + db;
1162 break;
1163 case UR_OP_SUB:
1164 ur_double(res) = da - db;
1165 break;
1166 case UR_OP_MUL:
1167 ur_double(res) = da * db;
1168 break;
1169 case UR_OP_DIV:
1170 if( db == 0.0 )
1171 goto div_by_zero;
1172 ur_double(res) = da / db;
1173 break;
1174 case UR_OP_MOD:
1175 if( db == 0.0 )
1176 goto div_by_zero;
1177 ur_double(res) = fmod(da, db);
1178 break;
1179 case UR_OP_AND:
1180 case UR_OP_OR:
1181 case UR_OP_XOR:
1182 ur_double(res) = 0.0;
1183 break;
1184 default:
1185 return unset_operate( ut, a, b, res, op );
1186 }
1187 return UR_OK;
1188
1189bad_type:
1190
1191 return ur_error( ut, UR_ERR_TYPE,
1192 "double! operator exepected char!/int!/double!/time!/date!" );
1193
1194div_by_zero:
1195
1196 return ur_error( ut, UR_ERR_SCRIPT, "double! divide by zero" );
1197}
1198
1199
1200void decimal_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
1201{
1202 (void) ut;
1203 (void) depth;
1204 ur_strAppendDouble( str, ur_double(cell) );
1205}
1206
1207
1208UDatatype dt_double =
1209{
1210 "double!",
1211 decimal_make, decimal_make, unset_copy,
1212 decimal_compare, decimal_operate, unset_select,
1213 decimal_toString, decimal_toString,
1214 unset_recycle, unset_mark, unset_destroy,
1215 unset_markBuf, unset_toShared, unset_bind
1216};
1217
1218
1219//----------------------------------------------------------------------------
1220// UT_TIME
1221
1222
1223double str_toTime( const uint8_t*, const uint8_t*, const uint8_t** );
1224
1225int time_make( UThread* ut, const UCell* from, UCell* res )
1226{
1227 switch( ur_type(from) )
1228 {
1229 case UT_INT:
1230 ur_setId(res, UT_TIME);
1231 ur_double(res) = (double) ur_int(from);
1232 break;
1233 case UT_DOUBLE:
1234 case UT_TIME:
1235 case UT_DATE:
1236 ur_setId(res, UT_TIME);
1237 ur_double(res) = ur_double(from);
1238 break;
1239 case UT_STRING:
1240 {
1241 USeriesIter si;
1242 ur_seriesSlice( ut, &si, from );
1243 if( ur_strIsUcs2(si.buf) )
1244 {
1245 return MAKE_NO_UCS2( "time!" );
1246 }
1247 else
1248 {
1249 const uint8_t* cp = si.buf->ptr.b;
1250 ur_setId(res, UT_TIME);
1251 ur_double(res) = str_toTime( cp + si.it, cp + si.end, 0 );
1252 }
1253 }
1254 break;
1255 default:
1256 return ur_error( ut, UR_ERR_TYPE,
1257 "make time! expected int!/double!/time!/date!/string!" );
1258 }
1259 return UR_OK;
1260}
1261
1262
1263int time_compare( UThread* ut, const UCell* a, const UCell* b, int test )
1264{
1265 (void) ut;
1266
1267 switch( test )
1268 {
1269 case UR_COMPARE_SAME:
1270 return ur_double(a) == ur_double(b);
1271
1272 case UR_COMPARE_EQUAL:
1273 case UR_COMPARE_EQUAL_CASE:
1274 if( ur_type(a) == ur_type(b) )
1275 return float_equal( ur_double(a), ur_double(b) );
1276 break;
1277
1278 case UR_COMPARE_ORDER:
1279 case UR_COMPARE_ORDER_CASE:
1280 if( ur_type(a) == ur_type(b) )
1281 {
1282 if( ur_double(a) > ur_double(b) )
1283 return 1;
1284 if( ur_double(a) < ur_double(b) )
1285 return -1;
1286 }
1287 break;
1288 }
1289 return 0;
1290}
1291
1292
1293extern int fpconv_ftoa( double, char* );
1294
1295void time_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
1296{
1297 int seg;
1298 double n = ur_double(cell);
1299 (void) ut;
1300 (void) depth;
1301
1302
1303 if( n < 0.0 )
1304 {
1305 n = -n;
1306 ur_strAppendChar( str, '-' );
1307 }
1308
1309 // Hours
1310 seg = (int) (n / 3600.0);
1311 if( seg )
1312 n -= seg * 3600.0;
1313 ur_strAppendInt( str, seg );
1314 ur_strAppendChar( str, ':' );
1315
1316 // Minutes
1317 seg = (int) (n / 60.0);
1318 if( seg )
1319 n -= seg * 60.0;
1320 if( seg < 10 )
1321 ur_strAppendChar( str, '0' );
1322 ur_strAppendInt( str, seg );
1323 ur_strAppendChar( str, ':' );
1324
1325 // Seconds
1326 if( n < 10.0 )
1327 ur_strAppendChar( str, '0' );
1328
1329#if 1
1330 {
1331 // Limit significant digits and round as ur_strAppendFloat() does but
1332 // without losing precision through float cast.
1333 char buf[26];
1334 int len = fpconv_ftoa( n, buf );
1335 buf[ len ] = '\0';
1336 ur_strAppendCStr( str, buf );
1337 }
1338#else
1339 ur_strAppendDouble( str, n );
1340#endif
1341}
1342
1343
1344UDatatype dt_time =
1345{
1346 "time!",
1347 time_make, time_make, unset_copy,
1348 time_compare, decimal_operate, unset_select,
1349 time_toString, time_toString,
1350 unset_recycle, unset_mark, unset_destroy,
1351 unset_markBuf, unset_toShared, unset_bind
1352};
1353
1354
1355//----------------------------------------------------------------------------
1356// UT_DATE
1357
1358
1359extern void date_toString( UThread*, const UCell*, UBuffer*, int );
1360extern double ur_stringToDate(const uint8_t*,const uint8_t*,const uint8_t**);
1361
1362
1363int date_make( UThread* ut, const UCell* from, UCell* res )
1364{
1365 switch( ur_type(from) )
1366 {
1367 case UT_TIME:
1368 case UT_DATE:
1369 ur_setId(res, UT_DATE);
1370 ur_double(res) = ur_double(from);
1371 break;
1372 case UT_STRING:
1373 {
1374 USeriesIter si;
1375 ur_seriesSlice( ut, &si, from );
1376 if( ur_strIsUcs2(si.buf) )
1377 {
1378 return MAKE_NO_UCS2( "date!" );
1379 }
1380 else
1381 {
1382 const uint8_t* cp = si.buf->ptr.b;
1383 ur_setId(res, UT_DATE);
1384 ur_double(res) = ur_stringToDate(cp + si.it, cp + si.end, 0);
1385 }
1386 }
1387 break;
1388 default:
1389 return ur_error( ut, UR_ERR_TYPE,
1390 "make date! expected time!/date!/string!" );
1391 }
1392 return UR_OK;
1393}
1394
1395
1396int date_operate( UThread* ut, const UCell* a, const UCell* b, UCell* res,
1397 int op )
1398{
1399 UCell tmp;
1400
1401 if( ur_is(a, UT_INT) )
1402 {
1403 ur_int(&tmp) = ur_int(a);
1404 a = &tmp;
1405 goto set_days;
1406 }
1407 else if( ur_is(b, UT_INT) )
1408 {
1409 ur_int(&tmp) = ur_int(b);
1410 b = &tmp;
1411set_days:
1412 ur_setId(&tmp, UT_INT);
1413 ur_int(&tmp) *= 86400;
1414 }
1415 return decimal_operate( ut, a, b, res, op );
1416}
1417
1418
1419UDatatype dt_date =
1420{
1421 "date!",
1422 date_make, date_make, unset_copy,
1423 time_compare, date_operate, unset_select,
1424 date_toString, date_toString,
1425 unset_recycle, unset_mark, unset_destroy,
1426 unset_markBuf, unset_toShared, unset_bind
1427};
1428
1429
1430//----------------------------------------------------------------------------
1431// UT_VEC3
1432
1433
1434static void vec3_setf( UCell* res, float n )
1435{
1436 float* f = res->vec3.xyz;
1437 f[0] = f[1] = f[2] = n;
1438}
1439
1440
1441extern int vector_pickFloatV( const UBuffer*, UIndex n, float* fv, int count );
1442
1443int vec3_make( UThread* ut, const UCell* from, UCell* res )
1444{
1445 ur_setId(res, UT_VEC3);
1446 switch( ur_type(from) )
1447 {
1448 case UT_NONE:
1449 vec3_setf( res, 0.0f );
1450 break;
1451 case UT_LOGIC:
1452 vec3_setf( res, (float) ur_logic(from) );
1453 break;
1454 case UT_INT:
1455 vec3_setf( res, (float) ur_int(from) );
1456 break;
1457 case UT_DOUBLE:
1458 vec3_setf( res, (float) ur_double(from) );
1459 break;
1460 case UT_COORD:
1461 res->vec3.xyz[0] = (float) from->coord.n[0];
1462 res->vec3.xyz[1] = (float) from->coord.n[1];
1463 res->vec3.xyz[2] = (from->coord.len > 2) ?
1464 (float) from->coord.n[2] : 0.0;
1465 break;
1466 case UT_VEC3:
1467 memCpy( res->vec3.xyz, from->vec3.xyz, 3 * sizeof(float) );
1468 break;
1469 case UT_BLOCK:
1470 {
1471 UBlockIt bi;
1472 const UCell* cell;
1473 float num;
1474 int len = 0;
1475
1476 ur_blockIt( ut, &bi, from );
1477 ur_foreach( bi )
1478 {
1479 if( ur_is(bi.it, UT_WORD) )
1480 {
1481 cell = ur_wordCell( ut, bi.it );
1482 if( ! cell )
1483 return UR_THROW;
1484 }
1485#if 0
1486 else if( ur_is(bi.it, UT_PATH) )
1487 {
1488 if( ! ur_pathCell( ut, bi.it, res ) )
1489 return UR_THROW;
1490 }
1491#endif
1492 else
1493 {
1494 cell = bi.it;
1495 }
1496
1497 if( ur_is(cell, UT_INT) )
1498 num = (float) ur_int(cell);
1499 else if( ur_is(cell, UT_DOUBLE) )
1500 num = (float) ur_double(cell);
1501 else
1502 break;
1503
1504 res->vec3.xyz[ len ] = num;
1505 if( ++len == 3 )
1506 return UR_OK;
1507 }
1508 while( len < 3 )
1509 res->vec3.xyz[ len++ ] = 0.0f;
1510 }
1511 break;
1512 case UT_VECTOR:
1513 {
1514 int len;
1515 len = vector_pickFloatV( ur_bufferSer(from), from->series.it,
1516 res->vec3.xyz, 3 );
1517 while( len < 3 )
1518 res->vec3.xyz[ len++ ] = 0.0f;
1519 }
1520 break;
1521 default:
1522 return ur_error( ut, UR_ERR_TYPE,
1523 "make vec3! expected none!/logic!/int!/double!/block!" );
1524 }
1525 return UR_OK;
1526}
1527
1528
1529void vec3_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
1530{
1531 (void) ut;
1532 for( depth = 0; depth < 3; ++depth )
1533 {
1534 if( depth )
1535 ur_strAppendChar( str, ',' );
1536 ur_strAppendFloat( str, cell->vec3.xyz[ depth ] );
1537 }
1538}
1539
1540
1541/* index is zero-based */
1542void vec3_pick( const UCell* cell, int index, UCell* res )
1543{
1544 if( (index < 0) || (index >= 3) )
1545 {
1546 ur_setId(res, UT_NONE);
1547 }
1548 else
1549 {
1550 ur_setId(res, UT_DOUBLE);
1551 ur_double(res) = cell->vec3.xyz[ index ];
1552 }
1553}
1554
1555
1556/* index is zero-based */
1557int vec3_poke( UThread* ut, UCell* cell, int index, const UCell* src )
1558{
1559 float num;
1560
1561 if( (index < 0) || (index >= 3) )
1562 return ur_error( ut, UR_ERR_SCRIPT, "poke vec3! index out of range" );
1563
1564 if( ur_is(src, UT_DOUBLE) )
1565 num = (float) ur_double(src);
1566 else if( ur_is(src, UT_INT) )
1567 num = (float) ur_int(src);
1568 else
1569 return ur_error( ut, UR_ERR_TYPE, "poke vec3! expected int!/double!" );
1570
1571 cell->vec3.xyz[ index ] = num;
1572 return UR_OK;
1573}
1574
1575
1576int vec3_compare( UThread* ut, const UCell* a, const UCell* b, int test )
1577{
1578 (void) ut;
1579 switch( test )
1580 {
1581 case UR_COMPARE_EQUAL:
1582 case UR_COMPARE_EQUAL_CASE:
1583 if( ur_type(a) != ur_type(b) )
1584 break;
1585 // Fall through...
1586
1587 case UR_COMPARE_SAME:
1588 {
1589 const float* pa = a->vec3.xyz;
1590 const float* pb = b->vec3.xyz;
1591 if( (pa[0] != pb[0]) || (pa[1] != pb[1]) || (pa[2] != pb[2]) )
1592 return 0;
1593 return 1;
1594 }
1595 break;
1596
1597 case UR_COMPARE_ORDER:
1598 case UR_COMPARE_ORDER_CASE:
1599 if( ur_type(a) == ur_type(b) )
1600 {
1601 const float* pa = a->vec3.xyz;
1602 const float* aend = pa + 3;
1603 const float* pb = b->vec3.xyz;
1604 while( pa != aend )
1605 {
1606 if( *pa > *pb )
1607 return 1;
1608 if( *pa < *pb )
1609 return -1;
1610 ++pa;
1611 ++pb;
1612 }
1613 }
1614 break;
1615 }
1616 return 0;
1617}
1618
1619
1620static const float* _load3f( const UCell* cell, float* tmp )
1621{
1622 switch( ur_type(cell) )
1623 {
1624 case UT_INT:
1625 tmp[0] = tmp[1] = tmp[2] = (float) ur_int(cell);
1626 break;
1627
1628 case UT_DOUBLE:
1629 tmp[0] = tmp[1] = tmp[2] = (float) ur_double(cell);
1630 break;
1631
1632 case UT_COORD:
1633 tmp[0] = (float) cell->coord.n[0];
1634 tmp[1] = (float) cell->coord.n[1];
1635 tmp[2] = (cell->coord.len > 2) ? (float) cell->coord.n[2] : 0.0f;
1636 break;
1637
1638 case UT_VEC3:
1639 return cell->vec3.xyz;
1640
1641 default:
1642 return 0;
1643 }
1644 return tmp;
1645}
1646
1647
1648#define OPER_V3(OP) \
1649 res->vec3.xyz[0] = va[0] OP vb[0]; \
1650 res->vec3.xyz[1] = va[1] OP vb[1]; \
1651 res->vec3.xyz[2] = va[2] OP vb[2]
1652
1653int vec3_operate( UThread* ut, const UCell* a, const UCell* b, UCell* res,
1654 int op )
1655{
1656 float tmp[ 3 ];
1657 const float* va;
1658 const float* vb;
1659
1660 va = _load3f( a, tmp );
1661 if( ! va )
1662 goto bad_type;
1663 vb = _load3f( b, tmp );
1664 if( ! vb )
1665 goto bad_type;
1666
1667 ur_setId(res, UT_VEC3);
1668 switch( op )
1669 {
1670 case UR_OP_ADD:
1671 OPER_V3( + );
1672 break;
1673 case UR_OP_SUB:
1674 OPER_V3( - );
1675 break;
1676 case UR_OP_MUL:
1677 OPER_V3( * );
1678 break;
1679 case UR_OP_DIV:
1680 OPER_V3( / );
1681 break;
1682 default:
1683 return unset_operate( ut, a, b, res, op );
1684 }
1685 return UR_OK;
1686
1687bad_type:
1688
1689 return ur_error( ut, UR_ERR_TYPE,
1690 "vec3! operator exepected int!/double!/coord!/vec3!" );
1691}
1692
1693
1694static
1695const UCell* vec3_select( UThread* ut, const UCell* cell, const UCell* sel,
1696 UCell* tmp )
1697{
1698 if( ur_is(sel, UT_INT) )
1699 {
1700 vec3_pick( cell, ur_int(sel) - 1, tmp );
1701 return tmp;
1702 }
1703 ur_error( ut, UR_ERR_SCRIPT, "vec3 select expected int!" );
1704 return 0;
1705}
1706
1707
1708UDatatype dt_vec3 =
1709{
1710 "vec3!",
1711 vec3_make, vec3_make, unset_copy,
1712 vec3_compare, vec3_operate, vec3_select,
1713 vec3_toString, vec3_toString,
1714 unset_recycle, unset_mark, unset_destroy,
1715 unset_markBuf, unset_toShared, unset_bind
1716};
1717
1718
1719//----------------------------------------------------------------------------
1720// UT_WORD
1721
1722
1723extern uint8_t charset_word[32];
1724
1725// Return UR_INVALID_ATOM if string is invalid.
1726static UAtom word_intern( UThread* ut, const char* str, const char* end )
1727{
1728 const char* it = str;
1729 int ch;
1730 while( it != end )
1731 {
1732 ch = *it++;
1733 if( bitIsSet(charset_word, ch) )
1734 continue;
1735 ur_error( ut, UR_ERR_SCRIPT, "make word! found invalid chars" );
1736 return UR_INVALID_ATOM;
1737 }
1738 return ur_internAtom( ut, str, end );
1739}
1740
1741
1742int word_makeType( UThread* ut, const UCell* from, UCell* res, int ntype )
1743{
1744 UAtom atom;
1745 int type = ur_type(from);
1746
1747 if( ur_isWordType( type ) )
1748 {
1749 *res = *from;
1750 ur_type(res) = ntype;
1751 return UR_OK;
1752 }
1753 else if( type == UT_STRING )
1754 {
1755 USeriesIter si;
1756
1757 ur_seriesSlice( ut, &si, from );
1758 if( si.buf->form == UR_ENC_LATIN1 )
1759 {
1760 atom = word_intern( ut, si.buf->ptr.c + si.it,
1761 si.buf->ptr.c + si.end );
1762 }
1763 else
1764 {
1765 UBuffer tmp;
1766 ur_strInit( &tmp, UR_ENC_LATIN1, 0 );
1767 ur_strAppend( &tmp, si.buf, si.it, si.end );
1768 atom = word_intern( ut, tmp.ptr.c, tmp.ptr.c + tmp.used );
1769 ur_strFree( &tmp );
1770 }
1771 if( atom == UR_INVALID_ATOM )
1772 return UR_THROW;
1773set_atom:
1774 ur_setId(res, ntype);
1775 ur_setWordUnbound(res, atom);
1776 return UR_OK;
1777 }
1778 else if( type == UT_DATATYPE )
1779 {
1780 atom = ur_datatype(from);
1781 if( atom < UT_MAX )
1782 goto set_atom;
1783 }
1784 return ur_error( ut, UR_ERR_TYPE, "make word! expected word!/string!" );
1785}
1786
1787
1788int word_make( UThread* ut, const UCell* from, UCell* res )
1789{
1790 return word_makeType( ut, from, res, UT_WORD );
1791}
1792
1793
1794/*
1795 Returns atom (if cell is any word), datatype atom (if cell is a simple
1796 datatype), or -1.
1797*/
1798static int word_atomOrType( const UCell* cell )
1799{
1800 int type = ur_type(cell);
1801 if( ur_isWordType(type) )
1802 return ur_atom(cell);
1803 if( type == UT_DATATYPE )
1804 {
1805 type = ur_datatype(cell);
1806 if( type < UT_MAX )
1807 return type;
1808 }
1809 return -1;
1810}
1811
1812
1813int compare_ic_uint8_t( const uint8_t*, const uint8_t*,
1814 const uint8_t*, const uint8_t* );
1815
1816int word_compare( UThread* ut, const UCell* a, const UCell* b, int test )
1817{
1818 switch( test )
1819 {
1820 case UR_COMPARE_SAME:
1821 return ((ur_atom(a) == ur_atom(b)) &&
1822 (ur_binding(a) == ur_binding(b)) &&
1823 (a->word.ctx == b->word.ctx));
1824
1825 case UR_COMPARE_EQUAL:
1826 case UR_COMPARE_EQUAL_CASE:
1827 {
1828 int atomA = word_atomOrType( a );
1829 if( (atomA > -1) && (atomA == word_atomOrType(b)) )
1830 return 1;
1831 }
1832 break;
1833
1834 case UR_COMPARE_ORDER:
1835 case UR_COMPARE_ORDER_CASE:
1836 if( ur_type(a) == ur_type(b) )
1837 {
1838#define ATOM_LEN(str) strLen((const char*) str)
1839 const uint8_t* strA = (const uint8_t*) ur_wordCStr(a);
1840 const uint8_t* strB = (const uint8_t*) ur_wordCStr(b);
1841 int (*func)(const uint8_t*, const uint8_t*,
1842 const uint8_t*, const uint8_t* );
1843 func = (test == UR_COMPARE_ORDER) ? compare_ic_uint8_t
1844 : compare_uint8_t;
1845 return func( strA, strA + ATOM_LEN(strA),
1846 strB, strB + ATOM_LEN(strB) );
1847 }
1848 break;
1849 }
1850 return 0;
1851}
1852
1853
1854void word_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
1855{
1856 (void) depth;
1857 ur_strAppendCStr( str, ur_wordCStr( cell ) );
1858}
1859
1860
1861void word_mark( UThread* ut, UCell* cell )
1862{
1863 if( ur_binding(cell) == UR_BIND_THREAD )
1864 {
1865 UIndex n = cell->word.ctx;
1866 if( ur_markBuffer( ut, n ) )
1867 context_markBuf( ut, ur_buffer(n) );
1868 }
1869}
1870
1871
1872void word_toShared( UCell* cell )
1873{
1874 if( ur_binding(cell) == UR_BIND_THREAD )
1875 {
1876 ur_setBinding( cell, UR_BIND_ENV );
1877 cell->word.ctx = -cell->word.ctx;
1878 }
1879#if 1
1880 // FIXME: The core library should have no knowledge of other binding types.
1881 else if( ur_binding(cell) >= UR_BIND_USER ) // UR_BIND_FUNC, UR_BIND_OPTION
1882 cell->word.ctx = -cell->word.ctx;
1883#endif
1884}
1885
1886
1887UDatatype dt_word =
1888{
1889 "word!",
1890 word_make, word_make, unset_copy,
1891 word_compare, unset_operate, unset_select,
1892 word_toString, word_toString,
1893 unset_recycle, word_mark, unset_destroy,
1894 unset_markBuf, word_toShared, unset_bind
1895};
1896
1897
1898//----------------------------------------------------------------------------
1899// UT_LITWORD
1900
1901
1902int litword_make( UThread* ut, const UCell* from, UCell* res )
1903{
1904 return word_makeType( ut, from, res, UT_LITWORD );
1905}
1906
1907
1908void litword_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
1909{
1910 (void) depth;
1911 ur_strAppendChar( str, '\'' );
1912 ur_strAppendCStr( str, ur_wordCStr( cell ) );
1913}
1914
1915
1916UDatatype dt_litword =
1917{
1918 "lit-word!",
1919 litword_make, litword_make, unset_copy,
1920 word_compare, unset_operate, unset_select,
1921 litword_toString, word_toString,
1922 unset_recycle, word_mark, unset_destroy,
1923 unset_markBuf, word_toShared, unset_bind
1924};
1925
1926
1927//----------------------------------------------------------------------------
1928// UT_SETWORD
1929
1930
1931int setword_make( UThread* ut, const UCell* from, UCell* res )
1932{
1933 return word_makeType( ut, from, res, UT_SETWORD );
1934}
1935
1936
1937void setword_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
1938{
1939 (void) depth;
1940 ur_strAppendCStr( str, ur_wordCStr( cell ) );
1941 ur_strAppendChar( str, ':' );
1942}
1943
1944
1945UDatatype dt_setword =
1946{
1947 "set-word!",
1948 setword_make, setword_make, unset_copy,
1949 word_compare, unset_operate, unset_select,
1950 setword_toString, word_toString,
1951 unset_recycle, word_mark, unset_destroy,
1952 unset_markBuf, word_toShared, unset_bind
1953};
1954
1955
1956//----------------------------------------------------------------------------
1957// UT_GETWORD
1958
1959
1960int getword_make( UThread* ut, const UCell* from, UCell* res )
1961{
1962 return word_makeType( ut, from, res, UT_GETWORD );
1963}
1964
1965
1966void getword_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
1967{
1968 (void) depth;
1969 ur_strAppendChar( str, ':' );
1970 ur_strAppendCStr( str, ur_wordCStr( cell ) );
1971}
1972
1973
1974UDatatype dt_getword =
1975{
1976 "get-word!",
1977 getword_make, getword_make, unset_copy,
1978 word_compare, unset_operate, unset_select,
1979 getword_toString, word_toString,
1980 unset_recycle, word_mark, unset_destroy,
1981 unset_markBuf, word_toShared, unset_bind
1982};
1983
1984
1985//----------------------------------------------------------------------------
1986// UT_OPTION
1987
1988
1989void option_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
1990{
1991 (void) depth;
1992 ur_strAppendChar( str, '/' );
1993 ur_strAppendCStr( str, ur_wordCStr( cell ) );
1994}
1995
1996
1997UDatatype dt_option =
1998{
1999 "option!",
2000 unset_make, unset_make, unset_copy,
2001 word_compare, unset_operate, unset_select,
2002 option_toString, option_toString,
2003 unset_recycle, word_mark, unset_destroy,
2004 unset_markBuf, word_toShared, unset_bind
2005};
2006
2007
2008//----------------------------------------------------------------------------
2009// UT_BINARY
2010
2011
2012void binary_copy( UThread* ut, const UCell* from, UCell* res )
2013{
2014 UBinaryIter bi;
2015 UIndex n;
2016 int len;
2017
2018 ur_binSlice( ut, &bi, from );
2019 len = bi.end - bi.it;
2020 n = ur_makeBinary( ut, len ); // Invalidates bi.buf.
2021 if( len )
2022 ur_binAppendData( ur_buffer(n), bi.it, len );
2023
2024 // Handle binary! & bitset!
2025 ur_initSeries( res, ur_type(from), n );
2026}
2027
2028
2029int binary_make( UThread* ut, const UCell* from, UCell* res )
2030{
2031 int type = ur_type(from);
2032 if( type == UT_INT )
2033 {
2034 ur_makeBinaryCell( ut, ur_int(from), res );
2035 return UR_OK;
2036 }
2037 else if( type == UT_BINARY )
2038 {
2039 binary_copy( ut, from, res );
2040 return UR_OK;
2041 }
2042 else if( ur_isStringType(type) || (type == UT_VECTOR) )
2043 {
2044 USeriesIter si;
2045 UBuffer* bin;
2046
2047 bin = ur_makeBinaryCell( ut, 0, res );
2048 ur_seriesSlice( ut, &si, from );
2049 ur_binAppendArray( bin, &si );
2050 return UR_OK;
2051 }
2052 return ur_error( ut, UR_ERR_TYPE,
2053 "make binary! expected int!/binary!/string!/file!" );
2054}
2055
2056
2057int binary_compare( UThread* ut, const UCell* a, const UCell* b, int test )
2058{
2059 switch( test )
2060 {
2061 case UR_COMPARE_SAME:
2062 return ((a->series.buf == b->series.buf) &&
2063 (a->series.it == b->series.it) &&
2064 (a->series.end == b->series.end));
2065
2066 case UR_COMPARE_EQUAL:
2067 case UR_COMPARE_EQUAL_CASE:
2068 if( ! ur_is(a, UT_BINARY) || ! ur_is(b, UT_BINARY) )
2069 break;
2070 if( (a->series.buf == b->series.buf) &&
2071 (a->series.it == b->series.it) &&
2072 (a->series.end == b->series.end) )
2073 return 1;
2074 {
2075 USeriesIter ai;
2076 USeriesIter bi;
2077
2078 ur_seriesSlice( ut, &ai, a );
2079 ur_seriesSlice( ut, &bi, b );
2080
2081 if( (ai.end - ai.it) == (bi.end - bi.it) )
2082 {
2083 const uint8_t* pos;
2084 const uint8_t* end = bi.buf->ptr.b + bi.end;
2085 pos = match_pattern_8( ai.buf->ptr.b + ai.it,
2086 ai.buf->ptr.b + ai.end,
2087 bi.buf->ptr.b + bi.it, end );
2088 return pos == end;
2089 }
2090 }
2091 break;
2092
2093 case UR_COMPARE_ORDER:
2094 case UR_COMPARE_ORDER_CASE:
2095 if( ur_is(a, UT_BINARY) && ur_is(b, UT_BINARY) )
2096 {
2097 USeriesIter ai;
2098 USeriesIter bi;
2099
2100 ur_seriesSlice( ut, &ai, a );
2101 ur_seriesSlice( ut, &bi, b );
2102
2103 return compare_uint8_t( ai.buf->ptr.b + ai.it,
2104 ai.buf->ptr.b + ai.end,
2105 bi.buf->ptr.b + bi.it,
2106 bi.buf->ptr.b + bi.end );
2107 }
2108 break;
2109 }
2110 return 0;
2111}
2112
2113
2114static const char* binaryEncStart[ UR_BENC_COUNT ] = { "#{", "2#{", "64#{" };
2115
2116void binary_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
2117{
2118 UBinaryIter bi;
2119 (void) depth;
2120
2121 ur_binSlice( ut, &bi, cell );
2122 ur_strAppendCStr( str, binaryEncStart[ bi.buf->form ] );
2123 ur_strAppendBinary( str, bi.it, bi.end, bi.buf->form );
2124 ur_strAppendChar( str, '}' );
2125}
2126
2127
2128void binary_mark( UThread* ut, UCell* cell )
2129{
2130 UIndex n = cell->series.buf;
2131 if( n > UR_INVALID_BUF ) // Also acts as (! ur_isShared(n))
2132 ur_markBuffer( ut, n );
2133}
2134
2135
2136void binary_toShared( UCell* cell )
2137{
2138 UIndex n = cell->series.buf;
2139 if( n > UR_INVALID_BUF )
2140 cell->series.buf = -n;
2141}
2142
2143
2144void binary_pick( const UBuffer* buf, UIndex n, UCell* res )
2145{
2146 if( n > -1 && n < buf->used )
2147 {
2148 ur_setId(res, UT_INT);
2149 ur_int(res) = buf->ptr.b[ n ];
2150 }
2151 else
2152 ur_setId(res, UT_NONE);
2153}
2154
2155
2156void binary_poke( UBuffer* buf, UIndex n, const UCell* val )
2157{
2158 if( n > -1 && n < buf->used )
2159 {
2160 if( ur_is(val, UT_CHAR) || ur_is(val, UT_INT) )
2161 buf->ptr.b[ n ] = ur_int(val);
2162 }
2163}
2164
2165
2166static int _errorStaticBinary( UThread* ut )
2167{
2168 return ur_error(ut, UR_ERR_SCRIPT, "Cannot modify static binary!");
2169}
2170
2171
2172int binary_append( UThread* ut, UBuffer* buf, const UCell* val )
2173{
2174 int vt;
2175
2176 if (buf->flags & UR_STATIC)
2177 return _errorStaticBinary(ut);
2178
2179 vt = ur_type(val);
2180 if( (vt == UT_BINARY) || ur_isStringType(vt) )
2181 {
2182 USeriesIter si;
2183 int len;
2184
2185 ur_seriesSlice( ut, &si, val );
2186 len = si.end - si.it;
2187 if( len )
2188 {
2189 if( (vt != UT_BINARY) && ur_strIsUcs2(si.buf) )
2190 {
2191 len *= 2;
2192 si.it *= 2;
2193 }
2194 ur_binAppendData( buf, si.buf->ptr.b + si.it, len );
2195 }
2196 return UR_OK;
2197 }
2198 else if( (vt == UT_CHAR) || (vt == UT_INT) )
2199 {
2200 ur_binReserve( buf, buf->used + 1 );
2201 buf->ptr.b[ buf->used++ ] = ur_int(val);
2202 return UR_OK;
2203 }
2204 else if( vt == UT_BLOCK )
2205 {
2206 UBlockIt bi;
2207 ur_blockIt( ut, &bi, val );
2208 ur_foreach( bi )
2209 {
2210 if( ! binary_append( ut, buf, bi.it ) )
2211 return UR_THROW;
2212 }
2213 return UR_OK;
2214 }
2215 return ur_error( ut, UR_ERR_TYPE,
2216 "append binary! expected char!/int!/binary!/string!/block!" );
2217}
2218
2219
2220int binary_insert( UThread* ut, UBuffer* buf, UIndex index,
2221 const UCell* val, UIndex part )
2222{
2223 int vt;
2224
2225 if (buf->flags & UR_STATIC)
2226 return _errorStaticBinary(ut);
2227
2228 vt = ur_type(val);
2229 if( (vt == UT_BINARY) || ur_isStringType(vt) )
2230 {
2231 USeriesIter si;
2232 int len;
2233
2234 ur_seriesSlice( ut, &si, val );
2235 len = si.end - si.it;
2236 if( len > part )
2237 len = part;
2238 if( len )
2239 {
2240 if( (vt != UT_BINARY) && ur_strIsUcs2(si.buf) )
2241 {
2242 len *= 2;
2243 si.it *= 2;
2244 }
2245
2246 ur_binExpand( buf, index, len );
2247 if( si.buf == buf )
2248 ur_seriesSlice( ut, &si, val ); // Re-aquire si.buf->ptr.
2249
2250 memCpy( buf->ptr.b + index, si.buf->ptr.b + si.it, len );
2251 }
2252 return UR_OK;
2253 }
2254 else if( (vt == UT_CHAR) || (vt == UT_INT) )
2255 {
2256 ur_binExpand( buf, index, 1 );
2257 buf->ptr.b[ index ] = ur_int(val);
2258 return UR_OK;
2259 }
2260 return ur_error( ut, UR_ERR_TYPE,
2261 "insert binary! expected char!/int!/binary!/string!" );
2262}
2263
2264
2265int binary_change( UThread* ut, USeriesIterM* si, const UCell* val,
2266 UIndex part )
2267{
2268 UBuffer* buf = si->buf;
2269 int type;
2270
2271 if (buf->flags & UR_STATIC)
2272 return _errorStaticBinary(ut);
2273
2274 type = ur_type(val);
2275 if( type == UT_CHAR || type == UT_INT )
2276 {
2277 if( si->it == buf->used )
2278 ur_binReserve( buf, ++buf->used );
2279 buf->ptr.b[ si->it++ ] = ur_int(val);
2280 if( part > 1 )
2281 ur_binErase( buf, si->it, part - 1 );
2282 return UR_OK;
2283 }
2284 else if( type == UT_BINARY )
2285 {
2286 UBinaryIter ri;
2287 UIndex newUsed;
2288 int rlen;
2289
2290 ur_binSlice( ut, &ri, val );
2291 rlen = ri.end - ri.it;
2292 if( rlen > 0 )
2293 {
2294 if( part > 0 )
2295 {
2296 if( part > rlen )
2297 {
2298 ur_binErase( buf, si->it, part - rlen );
2299 newUsed = (buf->used < rlen) ? rlen : buf->used;
2300 }
2301 else
2302 {
2303 if( part < rlen )
2304 ur_binExpand( buf, si->it, rlen - part );
2305 newUsed = buf->used;
2306 }
2307 }
2308 else
2309 {
2310 newUsed = si->it + rlen;
2311 if( newUsed < buf->used )
2312 newUsed = buf->used;
2313 }
2314
2315 // TODO: Handle overwritting self when buf is val.
2316
2317 buf->used = si->it;
2318 ur_binAppendData( buf, ri.it, rlen );
2319 si->it = buf->used;
2320 buf->used = newUsed;
2321 }
2322 return UR_OK;
2323 }
2324 return ur_error( ut, UR_ERR_TYPE,
2325 "change binary! expected char!/int!/binary!" );
2326}
2327
2328
2329void binary_remove( UThread* ut, USeriesIterM* si, UIndex part )
2330{
2331 (void) ut;
2332 ur_binErase( si->buf, si->it, (part > 0) ? part : 1 );
2333}
2334
2335
2336void binary_reverse( const USeriesIterM* si )
2337{
2338 uint8_t* it = si->buf->ptr.b;
2339 reverse_uint8_t( it + si->it, it + si->end );
2340}
2341
2342
2343int binary_find( UThread* ut, const USeriesIter* si, const UCell* val, int opt )
2344{
2345 const UBuffer* buf = si->buf;
2346 const uint8_t* it = buf->ptr.b;
2347 const uint8_t* ba = it + si->it;
2348 const uint8_t* bb = it + si->end;
2349 int vt = ur_type(val);
2350
2351 if( (vt == UT_CHAR) || (vt == UT_INT) )
2352 {
2353 if( opt & UR_FIND_LAST )
2354 it = find_last_uint8_t( ba, bb, ur_int(val) );
2355 else
2356 it = find_uint8_t( ba, bb, ur_int(val) );
2357check_find:
2358 if( it )
2359 return it - buf->ptr.b;
2360 }
2361 else if( ur_isStringType( vt ) || (vt == UT_BINARY) )
2362 {
2363 USeriesIter siV;
2364 const uint8_t* itV;
2365
2366 ur_seriesSlice( ut, &siV, val );
2367
2368 if( (vt != UT_BINARY) && ur_strIsUcs2(siV.buf) )
2369 return -1; // TODO: Handle ucs2.
2370
2371 // TODO: Implement UR_FIND_LAST.
2372 itV = siV.buf->ptr.b;
2373 it = find_pattern_8( ba, bb, itV + siV.it, itV + siV.end );
2374 goto check_find;
2375 }
2376 else if( vt == UT_BITSET )
2377 {
2378 const UBuffer* bbuf = ur_bufferSer(val);
2379 if( opt & UR_FIND_LAST )
2380 it = find_last_charset_uint8_t( ba, bb, bbuf->ptr.b, bbuf->used );
2381 else
2382 it = find_charset_uint8_t( ba, bb, bbuf->ptr.b, bbuf->used );
2383 goto check_find;
2384 }
2385 return -1;
2386}
2387
2388
2389int binary_operate( UThread* ut, const UCell* a, const UCell* b, UCell* res,
2390 int op )
2391{
2392 if( ur_type(a) == ur_type(b) )
2393 {
2394 switch( op )
2395 {
2396 /*
2397 case UR_OP_ADD:
2398 case UR_OP_SUB:
2399 case UR_OP_MUL:
2400 case UR_OP_DIV:
2401 case UR_OP_MOD:
2402 */
2403
2404 case UR_OP_AND:
2405 case UR_OP_OR:
2406 case UR_OP_XOR:
2407 {
2408 UBinaryIter biA;
2409 UBinaryIter biB;
2410 UBuffer* bin;
2411 uint8_t* bp;
2412 USizeOrder ord;
2413
2414 bin = ur_makeBinaryCell( ut, 0, res );
2415 ur_type(res) = ur_type(a);
2416
2417 ur_binSlice( ut, &biA, a );
2418 ur_binSlice( ut, &biB, b );
2419 ur_sizeOrder( &ord, biA.end - biA.it, biB.end - biB.it );
2420
2421 if( ord.large )
2422 {
2423 ur_binExpand( bin, 0, ord.large );
2424 bp = bin->ptr.b;
2425 ord.large -= ord.small; // Large is now remainder.
2426 switch( op )
2427 {
2428 case UR_OP_AND:
2429 while( ord.small-- )
2430 *bp++ = *biA.it++ & *biB.it++;
2431 memSet( bp, 0, ord.large );
2432 break;
2433
2434 case UR_OP_OR:
2435 while( ord.small-- )
2436 *bp++ = *biA.it++ | *biB.it++;
2437 goto copy_remain;
2438
2439 case UR_OP_XOR:
2440 while( ord.small-- )
2441 *bp++ = *biA.it++ ^ *biB.it++;
2442copy_remain:
2443 memCpy( bp, ord.secondLarger ? biB.it : biA.it,
2444 ord.large );
2445 break;
2446 }
2447 }
2448 }
2449 return UR_OK;
2450 }
2451 }
2452 return unset_operate( ut, a, b, res, op );
2453}
2454
2455
2456const UCell* binary_select( UThread* ut, const UCell* cell, const UCell* sel,
2457 UCell* tmp )
2458{
2459 if( ur_is(sel, UT_INT) )
2460 {
2461 const UBuffer* buf = ur_bufferSer(cell);
2462 binary_pick( buf, cell->series.it + ur_int(sel) - 1, tmp );
2463 return tmp;
2464 }
2465 ur_error( ut, UR_ERR_SCRIPT, "binary select expected int!" );
2466 return 0;
2467}
2468
2469
2470USeriesType dt_binary =
2471{
2472 {
2473 "binary!",
2474 binary_make, binary_make, binary_copy,
2475 binary_compare, binary_operate, binary_select,
2476 binary_toString, binary_toString,
2477 unset_recycle, binary_mark, ur_binFree,
2478 unset_markBuf, binary_toShared, unset_bind
2479 },
2480 binary_pick, binary_poke, binary_append,
2481 binary_insert, binary_change, binary_remove,
2482 binary_reverse, binary_find
2483};
2484
2485
2486//----------------------------------------------------------------------------
2487// UT_BITSET
2488
2489
2490UBuffer* ur_makeBitsetCell( UThread* ut, int bitCount, UCell* res )
2491{
2492 UBuffer* buf;
2493 int bytes = (bitCount + 7) / 8;
2494
2495 buf = ur_makeBinaryCell( ut, bytes, res );
2496 buf->type = UT_BITSET;
2497 ur_type(res) = UT_BITSET;
2498
2499 buf->used = bytes;
2500 memSet( buf->ptr.b, 0, buf->used );
2501
2502 return buf;
2503}
2504
2505
2506#define setBit(mem,n) (mem[(n)>>3] |= 1<<((n)&7))
2507#define clrBit(mem,n) (mem[(n)>>3] &= ~(1<<((n)&7)))
2508
2509int bitset_make( UThread* ut, const UCell* from, UCell* res )
2510{
2511 if( ur_is(from, UT_INT) )
2512 {
2513 ur_makeBitsetCell( ut, ur_int(from), res );
2514 return UR_OK;
2515 }
2516 else if( ur_is(from, UT_CHAR) )
2517 {
2518 int n = ur_int(from);
2519 UBuffer* buf = ur_makeBitsetCell( ut, n + 1, res );
2520 setBit( buf->ptr.b, n );
2521 return UR_OK;
2522 }
2523 else if( ur_is(from, UT_BINARY) )
2524 {
2525 binary_copy( ut, from, res );
2526 ur_buffer( res->series.buf )->type = UT_BITSET;
2527 ur_type(res) = UT_BITSET;
2528 return UR_OK;
2529 }
2530 else if( ur_is(from, UT_STRING) )
2531 {
2532 uint8_t* bits;
2533 UBinaryIter si;
2534 int n;
2535
2536 bits = ur_makeBitsetCell( ut, 256, res )->ptr.b;
2537
2538 ur_binSlice( ut, &si, from );
2539 if( si.buf->form != UR_ENC_LATIN1 )
2540 {
2541 return ur_error( ut, UR_ERR_INTERNAL,
2542 "FIXME: make bitset! only handles Latin-1 strings" );
2543 }
2544
2545 ur_foreach( si )
2546 {
2547 n = *si.it;
2548 setBit( bits, n );
2549 }
2550 return UR_OK;
2551 }
2552 return ur_error( ut, UR_ERR_TYPE,
2553 "make bitset! expected int!/char!/binary!/string!" );
2554}
2555
2556
2557int bitset_compare( UThread* ut, const UCell* a, const UCell* b, int test )
2558{
2559 switch( test )
2560 {
2561 case UR_COMPARE_SAME:
2562 return a->series.buf == b->series.buf;
2563
2564 case UR_COMPARE_EQUAL:
2565 case UR_COMPARE_EQUAL_CASE:
2566 if( ! ur_is(a, UT_BITSET) || ! ur_is(b, UT_BITSET) )
2567 break;
2568 if( a->series.buf == b->series.buf )
2569 return 1;
2570 {
2571 USizeOrder ord;
2572 const UBuffer* ba = ur_bufferSer(a);
2573 const UBuffer* bb = ur_bufferSer(b);
2574
2575 ur_sizeOrder( &ord, ba->used, bb->used );
2576 if( ord.small )
2577 {
2578 const uint8_t* pos;
2579 const uint8_t* end = bb->ptr.b + ord.small;
2580 pos = match_pattern_8( ba->ptr.b, ba->ptr.b + ord.small,
2581 bb->ptr.b, end );
2582 if( pos != end )
2583 return 0;
2584
2585 pos = ord.secondLarger ? bb->ptr.b : ba->ptr.b;
2586 end = pos + ord.large;
2587 pos += ord.small;
2588 while( pos != end )
2589 {
2590 if( *pos++ )
2591 return 0;
2592 }
2593 }
2594 }
2595 return 1;
2596
2597 case UR_COMPARE_ORDER:
2598 case UR_COMPARE_ORDER_CASE:
2599 break;
2600 }
2601 return 0;
2602}
2603
2604
2605void bitset_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
2606{
2607 const UBuffer* buf = ur_bufferSer(cell);
2608 (void) depth;
2609
2610 // Using "make bitset!" requires evaluation to re-load.
2611 // Maybe bitset! should have it's own syntax?
2612
2613 ur_strAppendCStr( str, "make bitset! #{" );
2614 ur_strAppendBinary( str, buf->ptr.b, buf->ptr.b + buf->used, UR_BENC_16 );
2615 ur_strAppendChar( str, '}' );
2616}
2617
2618
2619void bitset_pick( const UBuffer* buf, UIndex n, UCell* res )
2620{
2621 if( n > -1 && n < (buf->used * 8) )
2622 {
2623 ur_setId(res, UT_LOGIC);
2624 if( bitIsSet( buf->ptr.b, n ) )
2625 ur_logic(res) = 1;
2626 }
2627 else
2628 ur_setId(res, UT_NONE);
2629}
2630
2631
2632void bitset_poke( UBuffer* buf, UIndex n, const UCell* val )
2633{
2634 if( n > -1 && n < (buf->used * 8) )
2635 {
2636 if( ur_true(val) )
2637 {
2638 if( ur_is(val, UT_INT) )
2639 {
2640 if( ur_int(val) == 0 )
2641 goto clear;
2642 }
2643 else if( ur_is(val, UT_DOUBLE) )
2644 {
2645 if( ur_double(val) == 0.0 )
2646 goto clear;
2647 }
2648 setBit( buf->ptr.b, n );
2649 }
2650 else
2651 {
2652clear:
2653 clrBit( buf->ptr.b, n );
2654 }
2655 }
2656}
2657
2658
2659void bitset_reverse( const USeriesIterM* si )
2660{
2661 (void) si;
2662}
2663
2664
2665int bitset_find( UThread* ut, const USeriesIter* si, const UCell* val, int opt )
2666{
2667 const UBuffer* buf = si->buf;
2668 int vt = ur_type(val);
2669 int n;
2670 (void) opt;
2671
2672 if( (vt == UT_CHAR) || (vt == UT_INT) )
2673 {
2674 n = ur_int(val);
2675 if( ((n >> 3) < buf->used) && bitIsSet( buf->ptr.b, n ) )
2676 return n;
2677 }
2678 else if( vt == UT_BLOCK ) // Succeeds if all bits are found.
2679 {
2680 UBlockIt bi;
2681 n = -1;
2682 ur_blockIt( ut, &bi, val );
2683 ur_foreach( bi )
2684 {
2685 if( ur_is(bi.it, UT_CHAR) || ur_is(bi.it, UT_INT) )
2686 {
2687 n = ur_int(bi.it);
2688 if( ((n >> 3) >= buf->used) || ! bitIsSet( buf->ptr.b, n ) )
2689 return -1;
2690 }
2691 }
2692 return n;
2693 }
2694 return -1;
2695}
2696
2697
2698USeriesType dt_bitset =
2699{
2700 {
2701 "bitset!",
2702 bitset_make, bitset_make, binary_copy,
2703 bitset_compare, binary_operate, unset_select,
2704 bitset_toString, bitset_toString,
2705 unset_recycle, binary_mark, ur_binFree,
2706 unset_markBuf, binary_toShared, unset_bind
2707 },
2708 bitset_pick, bitset_poke, binary_append,
2709 binary_insert, binary_change, binary_remove,
2710 bitset_reverse, bitset_find
2711};
2712
2713
2714//----------------------------------------------------------------------------
2715// UT_STRING
2716
2717
2718void string_copy( UThread* ut, const UCell* from, UCell* res )
2719{
2720 USeriesIter si;
2721 UBuffer* buf;
2722 int len;
2723
2724 ur_seriesSlice( ut, &si, from );
2725 len = si.end - si.it;
2726 // Make invalidates si.buf.
2727 buf = ur_makeStringCell( ut, si.buf->form, len, res );
2728 if( len )
2729 ur_strAppend( buf, ur_bufferSer(from), si.it, si.end );
2730}
2731
2732
2733int string_convert( UThread* ut, const UCell* from, UCell* res )
2734{
2735 int type = ur_type(from);
2736 if( ur_isStringType(type) )
2737 {
2738 string_copy( ut, from, res );
2739 }
2740 else if( type == UT_BINARY )
2741 {
2742 UBinaryIter bi;
2743 UIndex n;
2744
2745 ur_binSlice( ut, &bi, from );
2746 n = ur_makeStringUtf8( ut, bi.it, bi.end );
2747
2748 ur_initSeries( res, UT_STRING, n );
2749 }
2750 else
2751 {
2752 DT( type )->toString( ut, from,
2753 ur_makeStringCell(ut, UR_ENC_LATIN1, 0, res), 0 );
2754 }
2755 return UR_OK;
2756}
2757
2758
2759int string_make( UThread* ut, const UCell* from, UCell* res )
2760{
2761 if( ur_is(from, UT_INT) )
2762 {
2763 ur_makeStringCell( ut, UR_ENC_LATIN1, ur_int(from), res );
2764 return UR_OK;
2765 }
2766 else if( ur_is(from, UT_WORD) )
2767 {
2768 UAtom atom = ur_atom(from);
2769 int enc = atom - UR_ATOM_LATIN1;
2770 if (enc < UR_ENC_LATIN1 || enc > UR_ENC_UCS2)
2771 return ur_error(ut, UR_ERR_SCRIPT, "Invalid string! encoding %s",
2772 ur_atomCStr(ut, atom));
2773 ur_makeStringCell(ut, enc, 0, res);
2774 return UR_OK;
2775 }
2776 return string_convert( ut, from, res );
2777}
2778
2779
2780#define COMPARE_IC(T) \
2781int compare_ic_ ## T( const T* it, const T* end, \
2782 const T* itB, const T* endB ) { \
2783 int ca, cb; \
2784 int lenA = end - it; \
2785 int lenB = endB - itB; \
2786 while( it < end && itB < endB ) { \
2787 ca = ur_charLowercase( *it++ ); \
2788 cb = ur_charLowercase( *itB++ ); \
2789 if( ca > cb ) \
2790 return 1; \
2791 if( ca < cb ) \
2792 return -1; \
2793 } \
2794 if( lenA > lenB ) \
2795 return 1; \
2796 if( lenA < lenB ) \
2797 return -1; \
2798 return 0; \
2799}
2800
2801COMPARE_IC(uint8_t)
2802COMPARE_IC(uint16_t)
2803
2804
2805int string_compare( UThread* ut, const UCell* a, const UCell* b, int test )
2806{
2807 switch( test )
2808 {
2809 case UR_COMPARE_SAME:
2810 return ((a->series.buf == b->series.buf) &&
2811 (a->series.it == b->series.it) &&
2812 (a->series.end == b->series.end));
2813
2814 case UR_COMPARE_EQUAL:
2815 case UR_COMPARE_EQUAL_CASE:
2816 if( ! ur_isStringType(ur_type(a)) || ! ur_isStringType(ur_type(b)) )
2817 break;
2818 if( (a->series.buf == b->series.buf) &&
2819 (a->series.it == b->series.it) &&
2820 (a->series.end == b->series.end) )
2821 return 1;
2822 {
2823 USeriesIter ai;
2824 USeriesIter bi;
2825 int len;
2826
2827 ur_seriesSlice( ut, &ai, a );
2828 ur_seriesSlice( ut, &bi, b );
2829 len = ai.end - ai.it;
2830
2831 if( (bi.end - bi.it) == len )
2832 {
2833 if( (len == 0) ||
2834 (ur_strMatch( &ai, &bi, (test == UR_COMPARE_EQUAL_CASE) )
2835 == len ) )
2836 return 1;
2837 }
2838 }
2839 break;
2840
2841 case UR_COMPARE_ORDER:
2842 case UR_COMPARE_ORDER_CASE:
2843 if( ! ur_isStringType(ur_type(a)) || ! ur_isStringType(ur_type(b)) )
2844 break;
2845 {
2846 USeriesIter ai;
2847 USeriesIter bi;
2848
2849 ur_seriesSlice( ut, &ai, a );
2850 ur_seriesSlice( ut, &bi, b );
2851
2852 if( ai.buf->elemSize != bi.buf->elemSize )
2853 return 0; // TODO: Handle all different encodings.
2854
2855 if( ur_strIsUcs2(ai.buf) )
2856 {
2857 int (*func)(const uint16_t*, const uint16_t*,
2858 const uint16_t*, const uint16_t* );
2859 func = (test == UR_COMPARE_ORDER) ? compare_ic_uint16_t
2860 : compare_uint16_t;
2861 return func( ai.buf->ptr.u16 + ai.it,
2862 ai.buf->ptr.u16 + ai.end,
2863 bi.buf->ptr.u16 + bi.it,
2864 bi.buf->ptr.u16 + bi.end );
2865 }
2866 else
2867 {
2868 int (*func)(const uint8_t*, const uint8_t*,
2869 const uint8_t*, const uint8_t* );
2870 func = (test == UR_COMPARE_ORDER) ? compare_ic_uint8_t
2871 : compare_uint8_t;
2872 return func( ai.buf->ptr.b + ai.it,
2873 ai.buf->ptr.b + ai.end,
2874 bi.buf->ptr.b + bi.it,
2875 bi.buf->ptr.b + bi.end );
2876 }
2877 }
2878 }
2879 return 0;
2880}
2881
2882
2883// Newline (\n) or double quote (").
2884// 0x04
2885static uint8_t _strLongChars[5] = { 0x00, 0x00, 0x00, 0x00, 0x04 };
2886
2887static uint8_t _strEscapeChars[16] = {
2888 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2889 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x28
2890};
2891
2892
2893static inline int nibbleToChar( int n )
2894{
2895 return (n < 10) ? n + '0' : n + 'A' - 10;
2896}
2897
2898void string_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
2899{
2900 const int longLen = 40;
2901 int len;
2902 int quote;
2903 UIndex escPos;
2904 USeriesIter si;
2905
2906 ur_seriesSlice( ut, &si, cell );
2907 len = si.end - si.it;
2908
2909 if( len < 1 )
2910 {
2911 ur_strAppendCStr( str, "\"\"" );
2912 return;
2913 }
2914
2915 if( (len > longLen) ||
2916 (ur_strFindChars( si.buf, si.it, si.end,
2917 _strLongChars, sizeof(_strLongChars) ) > -1) )
2918 {
2919 ur_strAppendChar( str, '{' );
2920 quote = '}';
2921 }
2922 else
2923 {
2924 ur_strAppendChar( str, '"' );
2925 quote = '"';
2926 }
2927
2928 while( 1 )
2929 {
2930 escPos = ur_strFindChars( si.buf, si.it, si.end,
2931 _strEscapeChars, sizeof(_strEscapeChars) );
2932 if( escPos < 0 )
2933 {
2934 ur_strAppend( str, si.buf, si.it, si.end );
2935 break;
2936 }
2937
2938 if( escPos != si.it )
2939 ur_strAppend( str, si.buf, si.it, escPos );
2940 si.it = escPos + 1;
2941
2942 depth = ur_strIsUcs2(si.buf) ? si.buf->ptr.u16[ escPos ]
2943 : si.buf->ptr.b[ escPos ];
2944 switch( depth )
2945 {
2946 case '\t':
2947 ur_strAppendCStr( str, "^-" );
2948 break;
2949
2950 case '\n':
2951 if( quote == '"' )
2952 ur_strAppendCStr( str, "^/" );
2953 else
2954 ur_strAppendChar( str, '\n' );
2955 break;
2956
2957 case '^':
2958 ur_strAppendCStr( str, "^^" );
2959 break;
2960
2961 case '{':
2962 if( quote == '"' )
2963 ur_strAppendChar( str, '{' );
2964 else
2965 ur_strAppendCStr( str, "^{" );
2966 break;
2967
2968 case '}':
2969 if( quote == '"' )
2970 ur_strAppendChar( str, '}' );
2971 else
2972 ur_strAppendCStr( str, "^}" );
2973 break;
2974
2975 default:
2976 ur_strAppendChar( str, '^' );
2977 ur_strAppendChar( str, nibbleToChar( depth ) );
2978 break;
2979 }
2980 }
2981
2982 ur_strAppendChar( str, quote );
2983}
2984
2985
2986void string_toText( UThread* ut, const UCell* cell, UBuffer* str, int depth )
2987{
2988 const UBuffer* ss = ur_bufferSer(cell);
2989 (void) depth;
2990 ur_strAppend( str, ss, cell->series.it,
2991 (cell->series.end > -1) ? cell->series.end : ss->used );
2992}
2993
2994
2995void string_pick( const UBuffer* buf, UIndex n, UCell* res )
2996{
2997 if( n > -1 && n < buf->used )
2998 {
2999 ur_setId(res, UT_CHAR);
3000 ur_int(res) = ur_strIsUcs2(buf) ? buf->ptr.u16[ n ]
3001 : buf->ptr.b[ n ];
3002 }
3003 else
3004 ur_setId(res, UT_NONE);
3005}
3006
3007
3008void string_poke( UBuffer* buf, UIndex n, const UCell* val )
3009{
3010 if( n > -1 && n < buf->used )
3011 {
3012 if( ur_is(val, UT_CHAR) || ur_is(val, UT_INT) )
3013 {
3014 if( ur_strIsUcs2(buf) )
3015 buf->ptr.u16[ n ] = ur_int(val);
3016 else
3017 buf->ptr.b[ n ] = ur_int(val);
3018 }
3019 }
3020}
3021
3022
3023static int _errorStaticString( UThread* ut )
3024{
3025 return ur_error(ut, UR_ERR_SCRIPT, "Cannot modify static string!");
3026}
3027
3028
3029int string_append( UThread* ut, UBuffer* buf, const UCell* val )
3030{
3031 int type;
3032
3033 if (buf->flags & UR_STATIC)
3034 return _errorStaticString(ut);
3035
3036 type = ur_type(val);
3037 if( ur_isStringType(type) )
3038 {
3039 USeriesIter si;
3040 ur_seriesSlice( ut, &si, val );
3041 ur_strAppend( buf, si.buf, si.it, si.end );
3042 }
3043 else if( type == UT_CHAR )
3044 {
3045 ur_strAppendChar( buf, ur_int(val) );
3046 }
3047 else if( type == UT_BLOCK )
3048 {
3049 UBlockIt bi;
3050 const UDatatype** dt = ut->types;
3051 ur_blockIt( ut, &bi, val );
3052 ur_foreach( bi )
3053 {
3054 dt[ ur_type(bi.it) ]->toText( ut, bi.it, buf, 0 );
3055 //ur_toText( ut, bi.it, str );
3056 }
3057 }
3058 else
3059 {
3060 DT( type )->toText( ut, val, buf, 0 );
3061 }
3062 return UR_OK;
3063}
3064
3065
3066int string_insert( UThread* ut, UBuffer* buf, UIndex index,
3067 const UCell* val, UIndex part )
3068{
3069 int type;
3070
3071 if (buf->flags & UR_STATIC)
3072 return _errorStaticString(ut);
3073
3074 type = ur_type(val);
3075 if( ur_isStringType(type) )
3076 {
3077 USeriesIter si;
3078 UIndex saveUsed;
3079 int len;
3080
3081 ur_seriesSlice( ut, &si, val );
3082 len = si.end - si.it;
3083 if( len > part )
3084 len = part;
3085 if( len )
3086 {
3087 ur_arrExpand( buf, index, len );
3088
3089 saveUsed = buf->used;
3090 buf->used = index;
3091 ur_strAppend( buf, si.buf, si.it, si.it + len );
3092 buf->used = saveUsed;
3093 }
3094 return UR_OK;
3095 }
3096 else if( type == UT_CHAR )
3097 {
3098 ur_arrExpand( buf, index, 1 );
3099 if( ur_strIsUcs2(buf) )
3100 buf->ptr.u16[ index ] = ur_int(val);
3101 else
3102 buf->ptr.c[ index ] = ur_int(val);
3103 return UR_OK;
3104 }
3105 return ur_error( ut, UR_ERR_TYPE, "insert string! expected char!/string!" );
3106}
3107
3108
3109/*
3110 \param si String to change.
3111 \param ri Replacement string.
3112 \param part Replace this many characters, regardless of the length of ri.
3113
3114 \return si->it is placed at end of change and si->buf.used may be modified.
3115*/
3116static void ur_strChange( USeriesIterM* si, USeriesIter* ri, UIndex part )
3117{
3118 UBuffer* buf;
3119 UIndex newUsed;
3120 int rlen = ri->end - ri->it;
3121
3122 if( rlen > 0 )
3123 {
3124 buf = si->buf;
3125 if( part > 0 )
3126 {
3127 if( part > rlen )
3128 {
3129 ur_arrErase( buf, si->it, part - rlen );
3130 newUsed = (buf->used < rlen) ? rlen : buf->used;
3131 }
3132 else
3133 {
3134 if( part < rlen )
3135 ur_arrExpand( buf, si->it, rlen - part );
3136 newUsed = buf->used;
3137 }
3138 }
3139 else
3140 {
3141 newUsed = si->it + rlen;
3142 if( newUsed < buf->used )
3143 newUsed = buf->used;
3144 }
3145
3146 // TODO: Handle overwritting self when buf is ri->buf.
3147
3148 buf->used = si->it;
3149 ur_strAppend( buf, ri->buf, ri->it, ri->end );
3150 si->it = buf->used;
3151 buf->used = newUsed;
3152 }
3153}
3154
3155
3156int string_change( UThread* ut, USeriesIterM* si, const UCell* val,
3157 UIndex part )
3158{
3159 USeriesIter siV;
3160 UBuffer* buf = si->buf;
3161 int type;
3162
3163 if (buf->flags & UR_STATIC)
3164 return _errorStaticString(ut);
3165
3166 type = ur_type(val);
3167 if( type == UT_CHAR )
3168 {
3169 if( si->it == buf->used )
3170 ur_arrReserve( buf, ++buf->used );
3171
3172 if( ur_strIsUcs2(buf) )
3173 buf->ptr.u16[ si->it ] = ur_int(val);
3174 else
3175 buf->ptr.b[ si->it ] = ur_int(val);
3176 ++si->it;
3177
3178 if( part > 1 )
3179 ur_arrErase( buf, si->it, part - 1 );
3180 }
3181 else if( ur_isStringType(type) )
3182 {
3183 ur_seriesSlice( ut, &siV, val );
3184 ur_strChange( si, &siV, part );
3185 }
3186 else
3187 {
3188 UBuffer tmp;
3189
3190 ur_strInit( &tmp, UR_ENC_LATIN1, 0 );
3191 DT( type )->toString( ut, val, &tmp, 0 );
3192
3193 siV.buf = &tmp;
3194 siV.it = 0;
3195 siV.end = tmp.used;
3196
3197 ur_strChange( si, &siV, part );
3198 ur_strFree( &tmp );
3199 }
3200 return UR_OK;
3201}
3202
3203
3204void string_remove( UThread* ut, USeriesIterM* si, UIndex part )
3205{
3206 (void) ut;
3207 ur_arrErase( si->buf, si->it, (part > 0) ? part : 1 );
3208}
3209
3210
3211void string_reverse( const USeriesIterM* si )
3212{
3213 const UBuffer* buf = si->buf;
3214 assert( buf->form != UR_ENC_UTF8 );
3215 if( ur_strIsUcs2(buf) )
3216 reverse_uint16_t( buf->ptr.u16 + si->it, buf->ptr.u16 + si->end );
3217 else
3218 reverse_uint8_t( buf->ptr.b + si->it, buf->ptr.b + si->end );
3219}
3220
3221
3222int string_find( UThread* ut, const USeriesIter* si, const UCell* val, int opt )
3223{
3224 const UBuffer* buf = si->buf;
3225
3226 switch( ur_type(val) )
3227 {
3228 case UT_CHAR:
3229 return ur_strFindChar( buf, si->it, si->end, ur_int(val), opt );
3230
3231 case UT_BINARY:
3232 case UT_STRING:
3233 case UT_FILE:
3234 {
3235 USeriesIter pi;
3236 UIndex (*find)(const USeriesIter*, const USeriesIter*, int)
3237 = (opt & UR_FIND_LAST) ? ur_strFindRev : ur_strFind;
3238 ur_seriesSlice( ut, &pi, val );
3239 return find( si, &pi, opt & UR_FIND_CASE );
3240 }
3241
3242 case UT_BITSET:
3243 {
3244 UIndex (*find)(const UBuffer*, UIndex, UIndex, const uint8_t*, int)
3245 = (opt & UR_FIND_LAST) ? ur_strFindCharsRev : ur_strFindChars;
3246 const UBuffer* bbuf = ur_bufferSer(val);
3247 return find( buf, si->it, si->end, bbuf->ptr.b, bbuf->used );
3248 }
3249 }
3250 return -1;
3251}
3252
3253
3254const UCell* string_select( UThread* ut, const UCell* cell, const UCell* sel,
3255 UCell* tmp )
3256{
3257 if( ur_is(sel, UT_INT) )
3258 {
3259 const UBuffer* buf = ur_bufferSer(cell);
3260 string_pick( buf, cell->series.it + ur_int(sel) - 1, tmp );
3261 return tmp;
3262 }
3263 ur_error( ut, UR_ERR_SCRIPT, "string select expected int!" );
3264 return 0;
3265}
3266
3267
3268USeriesType dt_string =
3269{
3270 {
3271 "string!",
3272 string_make, string_convert, string_copy,
3273 string_compare, unset_operate, string_select,
3274 string_toString, string_toText,
3275 unset_recycle, binary_mark, string_destroy,
3276 unset_markBuf, binary_toShared, unset_bind
3277 },
3278 string_pick, string_poke, string_append,
3279 string_insert, string_change, string_remove,
3280 string_reverse, string_find
3281};
3282
3283
3284//----------------------------------------------------------------------------
3285// UT_FILE
3286
3287
3288int file_make( UThread* ut, const UCell* from, UCell* res )
3289{
3290 int ok = string_make( ut, from, res );
3291 if( ok )
3292 ur_type(res) = UT_FILE;
3293 return ok;
3294}
3295
3296
3297int file_convert( UThread* ut, const UCell* from, UCell* res )
3298{
3299 int ok = string_convert( ut, from, res );
3300 if( ok )
3301 ur_type(res) = UT_FILE;
3302 return ok;
3303}
3304
3305
3306void file_copy( UThread* ut, const UCell* from, UCell* res )
3307{
3308 string_copy( ut, from, res );
3309 ur_type(res) = UT_FILE;
3310}
3311
3312
3313// "()[]; "
3314static uint8_t _fileQuoteChars[12] =
3315{
3316 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x08,
3317 0x00, 0x00, 0x00, 0x28
3318};
3319
3320void file_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
3321{
3322 USeriesIter si;
3323 (void) depth;
3324
3325 ur_seriesSlice( ut, &si, cell );
3326
3327 if( ur_strFindChars( si.buf, si.it, si.end, _fileQuoteChars,
3328 sizeof(_fileQuoteChars) ) > -1 )
3329 {
3330 ur_strAppendCStr( str, "%\"" );
3331 ur_strAppend( str, si.buf, si.it, si.end );
3332 ur_strAppendChar( str, '"' );
3333 }
3334 else
3335 {
3336 ur_strAppendChar( str, '%' );
3337 ur_strAppend( str, si.buf, si.it, si.end );
3338 }
3339}
3340
3341
3342USeriesType dt_file =
3343{
3344 {
3345 "file!",
3346 file_make, file_convert, file_copy,
3347 string_compare, unset_operate, string_select,
3348 file_toString, string_toText,
3349 unset_recycle, binary_mark, string_destroy,
3350 unset_markBuf, binary_toShared, unset_bind
3351 },
3352 string_pick, string_poke, string_append,
3353 string_insert, string_change, string_remove,
3354 string_reverse, string_find
3355};
3356
3357
3358//----------------------------------------------------------------------------
3359// UT_BLOCK
3360
3361
3362void block_copy( UThread* ut, const UCell* from, UCell* res )
3363{
3364 UBlockIt bi;
3365 UBuffer* buf;
3366 int len;
3367
3368 ur_blockIt( ut, &bi, from );
3369 len = bi.end - bi.it;
3370 // Make invalidates bi.buf.
3371 buf = ur_makeBlockCell( ut, ur_type(from), len, res );
3372 if( len )
3373 ur_blkAppendCells( buf, bi.it, len );
3374}
3375
3376
3377extern int ur_pathSelectCells(const UCell* selC, UCell* dest);
3378
3379int block_make( UThread* ut, const UCell* from, UCell* res )
3380{
3381 int type = ur_type(from);
3382 if( type == UT_INT )
3383 {
3384 ur_makeBlockCell( ut, UT_BLOCK, ur_int(from), res );
3385 return UR_OK;
3386 }
3387 else if( type == UT_STRING )
3388 {
3389 USeriesIter si;
3390 ur_makeBlockCell( ut, UT_BLOCK, 0, res ); // gc!
3391 ur_seriesSlice( ut, &si, from );
3392 if( si.it == si.end )
3393 {
3394 return UR_OK;
3395 }
3396 else if( (si.buf->elemSize == 1) )
3397 {
3398 return ur_tokenizeB( ut, res->series.buf, si.buf->form,
3399 si.buf->ptr.b + si.it,
3400 si.buf->ptr.b + si.end );
3401 }
3402 else
3403 {
3404 UBuffer tmp;
3405 UStatus ok;
3406 ur_strInit( &tmp, UR_ENC_UTF8, 0 );
3407 ur_strAppend( &tmp, si.buf, si.it, si.end );
3408 ok = ur_tokenizeB( ut, res->series.buf, UR_ENC_UTF8,
3409 tmp.ptr.b, tmp.ptr.b + tmp.used );
3410 ur_strFree( &tmp );
3411 return ok;
3412 }
3413 }
3414 else if( ur_isBlockType(type) )
3415 {
3416as_block:
3417 block_copy( ut, from, res );
3418 ur_type(res) = UT_BLOCK;
3419 return UR_OK;
3420 }
3421 else if( ur_isPathType(type) )
3422 {
3423 if( from->word.selType )
3424 {
3425 UBuffer* blk = ur_makeBlockCell( ut, UT_BLOCK, 3, res ); // gc!
3426 blk->used = ur_pathSelectCells(from, blk->ptr.cell);
3427 return UR_OK;
3428 }
3429 goto as_block;
3430 }
3431 return ur_error( ut, UR_ERR_TYPE,
3432 "make block! expected int!/string!/block!/path!" );
3433}
3434
3435
3436int block_convert( UThread* ut, const UCell* from, UCell* res )
3437{
3438 int type = ur_type(from);
3439
3440 if( type == UT_STRING || ur_isPathType(type) )
3441 {
3442 return block_make( ut, from, res );
3443 }
3444 else if( ur_isBlockType( type ) )
3445 {
3446 block_copy( ut, from, res );
3447 ur_type(res) = UT_BLOCK;
3448 }
3449 else
3450 {
3451 UBuffer* blk = ur_makeBlockCell( ut, UT_BLOCK, 1, res );
3452 ur_blkPush( blk, from );
3453 }
3454 return UR_OK;
3455}
3456
3457
3458int block_compare( UThread* ut, const UCell* a, const UCell* b, int test )
3459{
3460 switch( test )
3461 {
3462 case UR_COMPARE_SAME:
3463 return ((a->series.buf == b->series.buf) &&
3464 (a->series.it == b->series.it) &&
3465 (a->series.end == b->series.end));
3466
3467 case UR_COMPARE_EQUAL:
3468 case UR_COMPARE_EQUAL_CASE:
3469 if( ur_type(a) != ur_type(b) )
3470 break;
3471 if( (a->series.buf == b->series.buf) &&
3472 (a->series.it == b->series.it) &&
3473 (a->series.end == b->series.end) )
3474 return 1;
3475 {
3476 UBlockIt ai;
3477 UBlockIt bi;
3478 const UDatatype** dt;
3479 int t;
3480
3481 ur_blockIt( ut, &ai, a );
3482 ur_blockIt( ut, &bi, b );
3483
3484 if( (ai.end - ai.it) == (bi.end - bi.it) )
3485 {
3486 dt = ut->types;
3487 ur_foreach( ai )
3488 {
3489 t = ur_type(ai.it);
3490 if( t < ur_type(bi.it) )
3491 t = ur_type(bi.it);
3492 if( ! dt[ t ]->compare( ut, ai.it, bi.it, test ) )
3493 return 0;
3494 ++bi.it;
3495 }
3496 return 1;
3497 }
3498 }
3499 break;
3500
3501 case UR_COMPARE_ORDER:
3502 case UR_COMPARE_ORDER_CASE:
3503 break;
3504 }
3505 return 0;
3506}
3507
3508
3509#define BLOCK_OP_INT(OP) \
3510 ur_foreach(bi) { \
3511 if( ur_isIntType(ur_type(bi.it)) ) \
3512 n = n OP ur_int(bi.it); \
3513 else if( ur_isDecimalType(ur_type(bi.it)) ) \
3514 n = n OP (int) ur_double(bi.it); \
3515 }
3516
3517#define BLOCK_OP_DEC(OP) \
3518 ur_foreach(bi) { \
3519 if( ur_isDecimalType(ur_type(bi.it)) ) \
3520 n = n OP ur_double(bi.it); \
3521 else if( ur_isIntType(ur_type(bi.it)) ) \
3522 n = n OP (double) ur_int(bi.it); \
3523 }
3524
3525int block_operate( UThread* ut, const UCell* a, const UCell* b, UCell* res,
3526 int op )
3527{
3528 UBlockIt bi;
3529
3530 if( ur_isIntType( ur_type(a) ) )
3531 {
3532 int n = ur_int(a);
3533 ur_blockIt( ut, &bi, b );
3534 switch( op )
3535 {
3536 case UR_OP_ADD:
3537 BLOCK_OP_INT( + )
3538 break;
3539 case UR_OP_SUB:
3540 BLOCK_OP_INT( - )
3541 break;
3542 case UR_OP_MUL:
3543 BLOCK_OP_INT( * )
3544 break;
3545 case UR_OP_AND:
3546 BLOCK_OP_INT( & )
3547 break;
3548 case UR_OP_OR:
3549 BLOCK_OP_INT( | )
3550 break;
3551 case UR_OP_XOR:
3552 BLOCK_OP_INT( ^ )
3553 break;
3554 default:
3555 return unset_operate( ut, a, b, res, op );
3556 }
3557 ur_setId(res, ur_type(a));
3558 ur_int(res) = n;
3559 return UR_OK;
3560 }
3561 else if( ur_isDecimalType( ur_type(a) ) )
3562 {
3563 double n = ur_double(a);
3564 ur_blockIt( ut, &bi, b );
3565 switch( op )
3566 {
3567 case UR_OP_ADD:
3568 BLOCK_OP_DEC( + )
3569 break;
3570 case UR_OP_SUB:
3571 BLOCK_OP_DEC( - )
3572 break;
3573 case UR_OP_MUL:
3574 BLOCK_OP_DEC( * )
3575 break;
3576 default:
3577 return unset_operate( ut, a, b, res, op );
3578 }
3579 ur_setId(res, ur_type(a));
3580 ur_double(res) = n;
3581 return UR_OK;
3582 }
3583 return ur_error( ut, UR_ERR_TYPE,
3584 "block! operator exepected char!/int!/double!" );
3585}
3586
3587
3588static int _blockRecursion( UThread* ut, UIndex blkN )
3589{
3590 UBuffer* bs = &ut->blocksSeen;
3591 if (find_uint32_t(bs->ptr.u32, bs->ptr.u32 + bs->used, (uint32_t) blkN))
3592 return 1;
3593 ur_arrAppendInt32(bs, blkN);
3594 return 0;
3595}
3596
3597
3598/*
3599 If depth is -1 then the outermost pair of braces will be omitted.
3600*/
3601void block_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
3602{
3603 UBlockIt bi;
3604 const UCell* start;
3605 int brace = 0;
3606
3607 if (_blockRecursion(ut, cell->series.buf))
3608 {
3609 ur_strAppendCStr(str, "[...]");
3610 return;
3611 }
3612
3613 if( depth > -1 )
3614 {
3615 switch( ur_type(cell) )
3616 {
3617 case UT_BLOCK:
3618 ur_strAppendChar( str, '[' );
3619 brace = ']';
3620 break;
3621 case UT_PAREN:
3622 ur_strAppendChar( str, '(' );
3623 brace = ')';
3624 break;
3625#ifdef UR_CONFIG_MACROS
3626 case UT_MACRO:
3627 ur_strAppendCStr( str, "^(" );
3628 brace = ')';
3629 break;
3630#endif
3631 }
3632 }
3633
3634 ur_blockIt( ut, &bi, cell );
3635 start = bi.it;
3636
3637 ++depth;
3638 ur_foreach( bi )
3639 {
3640 if( bi.it->id.flags & UR_FLAG_SOL )
3641 {
3642 ur_strAppendChar( str, '\n' );
3643 ur_strAppendIndent( str, depth );
3644 }
3645 else if( bi.it != start )
3646 {
3647 ur_strAppendChar( str, ' ' );
3648 }
3649 ur_toStr( ut, bi.it, str, depth );
3650 }
3651 --depth;
3652
3653 ut->blocksSeen.used--;
3654
3655 if( (start != bi.end) && (start->id.flags & UR_FLAG_SOL) )
3656 {
3657 ur_strAppendChar( str, '\n' );
3658 if( brace )
3659 ur_strAppendIndent( str, depth );
3660 }
3661
3662 if( brace )
3663 ur_strAppendChar( str, brace );
3664}
3665
3666
3667void block_toText( UThread* ut, const UCell* cell, UBuffer* str, int depth )
3668{
3669 UBlockIt bi;
3670 const UCell* start;
3671 (void) depth;
3672
3673 if (_blockRecursion(ut, cell->series.buf))
3674 {
3675 ur_strAppendCStr(str, "[...]");
3676 return;
3677 }
3678
3679 ur_blockIt( ut, &bi, cell );
3680 start = bi.it;
3681
3682 ur_foreach( bi )
3683 {
3684 if( bi.it != start )
3685 ur_strAppendChar( str, ' ' );
3686 ur_toText( ut, bi.it, str );
3687 }
3688
3689 ut->blocksSeen.used--;
3690}
3691
3692
3693void block_markBuf( UThread* ut, UBuffer* buf )
3694{
3695 int t;
3696 UCell* it = buf->ptr.cell;
3697 UCell* end = it + buf->used;
3698 while( it != end )
3699 {
3700 t = ur_type(it);
3701 if( t >= UT_REFERENCE_BUF )
3702 {
3703 DT( t )->mark( ut, it );
3704 }
3705 ++it;
3706 }
3707}
3708
3709
3710void block_mark( UThread* ut, UCell* cell )
3711{
3712 UIndex n = cell->series.buf;
3713 if( n > UR_INVALID_BUF ) // Also acts as (! ur_isShared(n))
3714 {
3715 if( ur_markBuffer( ut, n ) )
3716 block_markBuf( ut, ur_buffer(n) );
3717 }
3718}
3719
3720
3721void block_toShared( UCell* cell )
3722{
3723 UIndex n = cell->series.buf;
3724 if( n > UR_INVALID_BUF )
3725 cell->series.buf = -n;
3726}
3727
3728
3729void block_pick( const UBuffer* buf, UIndex n, UCell* res )
3730{
3731 if( n > -1 && n < buf->used )
3732 *res = buf->ptr.cell[ n ];
3733 else
3734 ur_setId(res, UT_NONE);
3735}
3736
3737
3738void block_poke( UBuffer* buf, UIndex n, const UCell* val )
3739{
3740 if( n > -1 && n < buf->used )
3741 buf->ptr.cell[ n ] = *val;
3742}
3743
3744
3745int block_append( UThread* ut, UBuffer* buf, const UCell* val )
3746{
3747 if( ur_is(val, UT_BLOCK) || ur_is(val, UT_PAREN) )
3748 {
3749 UBlockIt bi;
3750 if( ur_blockIt( ut, &bi, val ) == buf )
3751 {
3752 // If appending to self then this makes sure the source
3753 // cells pointer does not change in ur_blkAppendCells().
3754 ur_arrReserve( buf, buf->used + (bi.end - bi.it) );
3755 ur_blockIt( ut, &bi, val );
3756 }
3757 ur_blkAppendCells( buf, bi.it, bi.end - bi.it );
3758 }
3759 else
3760 {
3761 ur_blkPush( buf, val );
3762 }
3763 return UR_OK;
3764}
3765
3766
3767int block_insert( UThread* ut, UBuffer* buf, UIndex index,
3768 const UCell* val, UIndex part )
3769{
3770 if( ur_is(val, UT_BLOCK) || ur_is(val, UT_PAREN) )
3771 {
3772 const UBuffer* blk;
3773 UBlockIt bi;
3774 int len;
3775
3776 blk = ur_blockIt( ut, &bi, val );
3777 len = bi.end - bi.it;
3778 if( len > part )
3779 len = part;
3780 if( len > 0 )
3781 {
3782 if( blk == buf )
3783 {
3784 // Inserting into self.
3785 UIndex it = bi.it - buf->ptr.cell;
3786 ur_arrExpand( buf, index, len );
3787 if( it != index )
3788 {
3789 memCpy( buf->ptr.cell + index, buf->ptr.cell + it,
3790 len * sizeof(UCell) );
3791 }
3792 }
3793 else
3794 {
3795 ur_blkInsert( buf, index, bi.it, len );
3796 }
3797 }
3798 }
3799 else
3800 {
3801 ur_blkInsert( buf, index, val, 1 );
3802 }
3803 return UR_OK;
3804}
3805
3806
3807int block_change( UThread* ut, USeriesIterM* si, const UCell* val,
3808 UIndex part )
3809{
3810 if( ur_isBlockType( ur_type(val) ) )
3811 {
3812 UBlockIt ri;
3813 UBuffer* buf;
3814 UIndex newUsed;
3815 int rlen;
3816
3817 ur_blockIt( ut, &ri, val );
3818 rlen = ri.end - ri.it;
3819 if( rlen > 0 )
3820 {
3821 buf = si->buf;
3822 if( part > 0 )
3823 {
3824 if( part > rlen )
3825 {
3826 ur_arrErase( buf, si->it, part - rlen );
3827 newUsed = (buf->used < rlen) ? rlen : buf->used;
3828 }
3829 else
3830 {
3831 if( part < rlen )
3832 ur_arrExpand( buf, si->it, rlen - part );
3833 newUsed = buf->used;
3834 }
3835 }
3836 else
3837 {
3838 newUsed = si->it + rlen;
3839 if( newUsed < buf->used )
3840 newUsed = buf->used;
3841 }
3842
3843 // TODO: Handle overwritting self when buf is val.
3844
3845 buf->used = si->it;
3846 ur_blkAppendCells( buf, ri.it, rlen );
3847 si->it = buf->used;
3848 buf->used = newUsed;
3849 }
3850 }
3851 else
3852 {
3853 UBuffer* buf = si->buf;
3854 if( si->it == buf->used )
3855 ur_arrReserve( buf, ++buf->used );
3856 buf->ptr.cell[ si->it++ ] = *val;
3857 if( part > 1 )
3858 ur_arrErase( buf, si->it, part - 1 );
3859 }
3860 return UR_OK;
3861}
3862
3863
3864void block_remove( UThread* ut, USeriesIterM* si, UIndex part )
3865{
3866 (void) ut;
3867 ur_arrErase( si->buf, si->it, (part > 0) ? part : 1 );
3868}
3869
3870
3871void block_reverse( const USeriesIterM* si )
3872{
3873 if( si->end > si->it )
3874 {
3875 UCell tmp;
3876 UCell* it = si->buf->ptr.cell + si->it;
3877 UCell* end = si->buf->ptr.cell + si->end;
3878
3879 while( it < --end )
3880 {
3881 tmp = *it;
3882 *it++ = *end;
3883 *end = tmp;
3884 }
3885 }
3886}
3887
3888
3889int block_find( UThread* ut, const USeriesIter* si, const UCell* val, int opt )
3890{
3891 UBlockIt bi;
3892 const UBuffer* buf = si->buf;
3893 int (*equal)(UThread*, const UCell*, const UCell*) =
3894 (opt & UR_FIND_CASE) ? ur_equalCase : ur_equal;
3895
3896 bi.it = buf->ptr.cell + si->it;
3897 bi.end = buf->ptr.cell + si->end;
3898
3899 if( opt & UR_FIND_LAST )
3900 {
3901 while( bi.it != bi.end )
3902 {
3903 --bi.end;
3904 if( equal( ut, val, bi.end ) )
3905 return bi.end - buf->ptr.cell;
3906 }
3907 }
3908 else
3909 {
3910 ur_foreach( bi )
3911 {
3912 if( equal( ut, val, bi.it ) )
3913 return bi.it - buf->ptr.cell;
3914 }
3915 }
3916 return -1;
3917}
3918
3919
3920const UCell* block_select( UThread* ut, const UCell* cell, const UCell* sel,
3921 UCell* tmp )
3922{
3923 const UBuffer* buf = ur_bufferSer(cell);
3924
3925 if( ur_is(sel, UT_INT) )
3926 {
3927 //block_pick( buf, cell->series.it + ur_int(sel) - 1, tmp );
3928 int n = cell->series.it + ur_int(sel) - 1;
3929 if( n > -1 && n < buf->used )
3930 return buf->ptr.cell + n;
3931none:
3932 ur_setId(tmp, UT_NONE);
3933 return tmp;
3934 }
3935 else if( ur_is(sel, UT_WORD) )
3936 {
3937 UBlockIt wi;
3938 UAtom atom = ur_atom(sel);
3939 ur_blockIt( ut, &wi, cell );
3940 ur_foreach( wi )
3941 {
3942 // Checking atom first would be faster (it will fail more often
3943 // and is a quicker check), but the atom field may not be
3944 // intialized memory so memory checkers will report an error.
3945 if( ur_isWordType( ur_type(wi.it) ) && (ur_atom(wi.it) == atom) )
3946 {
3947 if( ++wi.it == wi.end )
3948 goto none;
3949 return wi.it;
3950 }
3951 }
3952 goto none;
3953 }
3954 ur_error( ut, UR_ERR_SCRIPT, "block select expected int!/word!" );
3955 return 0;
3956}
3957
3958
3959USeriesType dt_block =
3960{
3961 {
3962 "block!",
3963 block_make, block_convert, block_copy,
3964 block_compare, block_operate, block_select,
3965 block_toString, block_toText,
3966 unset_recycle, block_mark, block_destroy,
3967 block_markBuf, block_toShared, unset_bind
3968 },
3969 block_pick, block_poke, block_append,
3970 block_insert, block_change, block_remove,
3971 block_reverse, block_find
3972};
3973
3974
3975//----------------------------------------------------------------------------
3976// UT_PAREN
3977
3978
3979int paren_make( UThread* ut, const UCell* from, UCell* res )
3980{
3981 int ok = block_make( ut, from, res );
3982 if( ok )
3983 ur_type(res) = UT_PAREN;
3984 return ok;
3985}
3986
3987
3988int paren_convert( UThread* ut, const UCell* from, UCell* res )
3989{
3990 int ok = block_convert( ut, from, res );
3991 if( ok )
3992 ur_type(res) = UT_PAREN;
3993 return ok;
3994}
3995
3996
3997USeriesType dt_paren =
3998{
3999 {
4000 "paren!",
4001 paren_make, paren_convert, block_copy,
4002 block_compare, unset_operate, block_select,
4003 block_toString, block_toString,
4004 unset_recycle, block_mark, block_destroy,
4005 block_markBuf, block_toShared, unset_bind
4006 },
4007 block_pick, block_poke, block_append,
4008 block_insert, block_change, block_remove,
4009 block_reverse, block_find
4010};
4011
4012
4013//----------------------------------------------------------------------------
4014// UT_PATH
4015
4016
4017void path_copy( UThread* ut, const UCell* from, UCell* res )
4018{
4019 if( from->word.selType )
4020 *res = *from;
4021 else
4022 block_copy( ut, from, res );
4023}
4024
4025
4026static int path_makeT( UThread* ut, const UCell* from, UCell* res, int ptype )
4027{
4028 int typeMask = 1 << ur_type(from);
4029 if( typeMask & ((1<<UT_BLOCK) | (1<<UT_PAREN)) )
4030 {
4031 UBlockIt bi;
4032 int len;
4033
4034 ur_blockIt( ut, &bi, from );
4035 len = bi.end - bi.it;
4036 if( len < 2 )
4037 return ur_error(ut, UR_ERR_SCRIPT, "make path! requires two nodes");
4038
4039 if( (1 << ur_type(bi.it)) & ((1<<UT_WORD) | (1<<UT_LITWORD)) )
4040 {
4041 ur_makePathCell( ut, bi.it, len, res );
4042 ur_type(res) = ptype;
4043 return UR_OK;
4044 }
4045 return ur_error( ut, UR_ERR_TYPE,
4046 "path! must start with word!/lit-word!" );
4047 }
4048 else if( typeMask & ((1<<UT_PATH) | (1<<UT_LITPATH) | (1<<UT_SETPATH)) )
4049 {
4050 path_copy( ut, from, res );
4051 ur_type(res) = ptype;
4052 return UR_OK;
4053 }
4054 return ur_error( ut, UR_ERR_TYPE, "make path! expected block!" );
4055}
4056
4057
4058int path_make( UThread* ut, const UCell* from, UCell* res )
4059{
4060 return path_makeT( ut, from, res, UT_PATH );
4061}
4062
4063
4064void path_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
4065{
4066 int stype;
4067
4068 if( ur_is(cell, UT_LITPATH) )
4069 ur_strAppendChar( str, '\'' );
4070
4071 if( (stype = cell->word.selType) )
4072 {
4073 const UAtom* sel = cell->word.sel;
4074
4075 ur_strAppendCStr( str, ur_atomCStr(ut, ur_atom(cell)) );
4076 do
4077 {
4078 ur_strAppendChar( str, '/' );
4079 if( (stype & 3) == UR_SELECT_ATOM )
4080 ur_strAppendCStr( str, ur_atomCStr(ut, *sel) );
4081 else
4082 ur_strAppendInt( str, *((int16_t*) sel) );
4083 ++sel;
4084 stype >>= 2;
4085 }
4086 while( stype );
4087 }
4088 else
4089 {
4090 UBlockIt bi;
4091 const UCell* start;
4092
4093 ur_blockIt( ut, &bi, cell );
4094 start = bi.it;
4095 ur_foreach( bi )
4096 {
4097 if( bi.it != start )
4098 ur_strAppendChar( str, '/' );
4099 ur_toStr( ut, bi.it, str, depth );
4100 }
4101 }
4102
4103 if( ur_is(cell, UT_SETPATH) )
4104 ur_strAppendChar( str, ':' );
4105}
4106
4107
4108int path_compare( UThread* ut, const UCell* a, const UCell* b, int test )
4109{
4110 const int pathMask = 1<<UT_PATH | 1<<UT_LITPATH | 1<<UT_SETPATH;
4111 int ta = ur_type(a);
4112 int tb = ur_type(b);
4113
4114 if( (1<<ta & pathMask) && (1<<tb & pathMask) )
4115 {
4116 if( a->word.selType && b->word.selType )
4117 {
4118 switch( test )
4119 {
4120 case UR_COMPARE_SAME:
4121 if( ta != tb )
4122 return 0;
4123 // Fall through...
4124
4125 case UR_COMPARE_EQUAL:
4126 case UR_COMPARE_EQUAL_CASE:
4127 if( a->word.selType == b->word.selType )
4128 return 1;
4129 break;
4130
4131 case UR_COMPARE_ORDER:
4132 case UR_COMPARE_ORDER_CASE:
4133 break;
4134 }
4135 }
4136 else if( ! (a->word.selType || b->word.selType) )
4137 {
4138 return block_compare( ut, a, b, test );
4139 }
4140 }
4141 return 0;
4142}
4143
4144
4145extern void path_pick( UThread*, const UCell* cell, int index, UCell* res );
4146
4147const UCell* path_select( UThread* ut, const UCell* cell, const UCell* sel,
4148 UCell* tmp )
4149{
4150 if( ! ur_is(sel, UT_INT) )
4151 {
4152 ur_error( ut, UR_ERR_SCRIPT, "path select expected int!" );
4153 return 0;
4154 }
4155 path_pick(ut, cell, ur_int(sel) - 1, tmp);
4156 return tmp;
4157}
4158
4159
4160void path_mark( UThread* ut, UCell* cell )
4161{
4162 if( cell->word.selType )
4163 word_mark( ut, cell );
4164 else
4165 block_mark( ut, cell );
4166}
4167
4168
4169void path_toShared( UCell* cell )
4170{
4171 if( cell->word.selType )
4172 word_toShared( cell );
4173 else
4174 block_toShared( cell );
4175}
4176
4177
4178UDatatype dt_path =
4179{
4180 "path!",
4181 path_make, path_make, path_copy,
4182 path_compare, unset_operate, path_select,
4183 path_toString, path_toString,
4184 unset_recycle, path_mark, block_destroy,
4185 block_markBuf, path_toShared, unset_bind
4186};
4187
4188
4189//----------------------------------------------------------------------------
4190// UT_LITPATH
4191
4192
4193int litpath_make( UThread* ut, const UCell* from, UCell* res )
4194{
4195 return path_makeT( ut, from, res, UT_LITPATH );
4196}
4197
4198
4199UDatatype dt_litpath =
4200{
4201 "lit-path!",
4202 litpath_make, litpath_make, path_copy,
4203 path_compare, unset_operate, path_select,
4204 path_toString, path_toString,
4205 unset_recycle, path_mark, block_destroy,
4206 block_markBuf, path_toShared, unset_bind
4207};
4208
4209
4210//----------------------------------------------------------------------------
4211// UT_SETPATH
4212
4213
4214int setpath_make( UThread* ut, const UCell* from, UCell* res )
4215{
4216 return path_makeT( ut, from, res, UT_SETPATH );
4217}
4218
4219
4220UDatatype dt_setpath =
4221{
4222 "set-path!",
4223 setpath_make, setpath_make, path_copy,
4224 path_compare, unset_operate, path_select,
4225 path_toString, path_toString,
4226 unset_recycle, path_mark, block_destroy,
4227 block_markBuf, path_toShared, unset_bind
4228};
4229
4230
4231//----------------------------------------------------------------------------
4232// UT_CONTEXT
4233
4234
4235int context_make( UThread* ut, const UCell* from, UCell* res )
4236{
4237 if( ur_is(from, UT_BLOCK) )
4238 {
4239 UBlockIterM bi;
4240 UBuffer* ctx;
4241
4242 ctx = ur_makeContextCell( ut, 0, res ); // gc!
4243
4244 if( ! ur_blkSliceM( ut, &bi, from ) )
4245 return UR_THROW;
4246
4247 ur_ctxSetWords( ctx, bi.it, bi.end );
4248 ur_ctxSort( ctx );
4249 ur_bind( ut, bi.buf, ctx, UR_BIND_SELF );
4250 return UR_OK;
4251 }
4252 else if( ur_is(from, UT_CONTEXT) )
4253 {
4254 ur_ctxClone( ut, ur_bufferSer(from), res );
4255 return UR_OK;
4256 }
4257 return ur_error( ut, UR_ERR_TYPE, "make context! expected block!/context!");
4258}
4259
4260
4261void context_copy( UThread* ut, const UCell* from, UCell* res )
4262{
4263 ur_ctxClone( ut, ur_bufferSer(from), res );
4264}
4265
4266
4267int context_compare( UThread* ut, const UCell* a, const UCell* b, int test )
4268{
4269 (void) ut;
4270 switch( test )
4271 {
4272 case UR_COMPARE_SAME:
4273 return (a->series.buf == b->series.buf);
4274
4275 case UR_COMPARE_EQUAL:
4276 case UR_COMPARE_EQUAL_CASE:
4277 if( ur_type(a) != ur_type(b) )
4278 break;
4279 if( a->series.buf == b->series.buf )
4280 return 1;
4281 // TODO: Compare words and values.
4282 break;
4283
4284 case UR_COMPARE_ORDER:
4285 case UR_COMPARE_ORDER_CASE:
4286 break;
4287 }
4288 return 0;
4289}
4290
4291
4292/*
4293 \ctx Pointer to a valid and sorted context.
4294 \ctxN The buffer of ctx (required for binding the words).
4295 \param res Set to a block of words in the context (bound to the context).
4296*/
4297void _contextWords( UThread* ut, const UBuffer* ctx, UIndex ctxN, UCell* res )
4298{
4299 UBlockIterM di;
4300 UAtom* ait;
4301 UAtom* atoms;
4302 int bindType;
4303 UIndex used = ctx->used;
4304
4305 di.buf = ur_makeBlockCell( ut, UT_BLOCK, used, res );
4306 di.it = di.buf->ptr.cell;
4307 di.end = di.it + used;
4308
4309 ctx = ur_bufferE(ctxN); // Re-aquire.
4310 atoms = ait = ((UAtom*) di.end) - used;
4311 ur_ctxWordAtoms( ctx, atoms );
4312
4313 if( ctxN == UR_INVALID_BUF )
4314 bindType = UR_BIND_UNBOUND;
4315 else
4316 bindType = ur_isShared(ctxN) ? UR_BIND_ENV : UR_BIND_THREAD;
4317
4318 ur_foreach( di )
4319 {
4320 ur_setId(di.it, UT_WORD);
4321 ur_setBinding( di.it, bindType );
4322 di.it->word.ctx = ctxN;
4323 di.it->word.index = ait - atoms;
4324 di.it->word.atom = *ait++;
4325 }
4326
4327 di.buf->used = used;
4328}
4329
4330
4331const UCell* context_select( UThread* ut, const UCell* cell, const UCell* sel,
4332 UCell* tmp )
4333{
4334 const UBuffer* ctx;
4335
4336 if( (ctx = ur_sortedContext( ut, cell )) )
4337 {
4338 if( ur_is(sel, UT_WORD) )
4339 {
4340 int i = ur_ctxLookup( ctx, ur_atom(sel) );
4341 if( i >= 0 )
4342 return ur_ctxCell(ctx, i);
4343 if( ur_atom(sel) == UR_ATOM_SELF )
4344 {
4345 *tmp = *cell;
4346 return tmp;
4347 }
4348 ur_error( ut, UR_ERR_SCRIPT, "context has no word '%s",
4349 ur_wordCStr(sel) );
4350 }
4351 else
4352 {
4353 ur_error( ut, UR_ERR_SCRIPT, "context select expected word!" );
4354 }
4355 }
4356 return NULL;
4357}
4358
4359
4360static void context_print( UThread* ut, const UBuffer* buf, UBuffer* str,
4361 int depth )
4362{
4363#define ASTACK_SIZE 8
4364 union {
4365 UAtom* heap;
4366 UAtom stack[ ASTACK_SIZE ];
4367 } atoms;
4368 UAtom* ait;
4369 int alloced;
4370 const UCell* it = buf->ptr.cell;
4371 const UCell* end = it + buf->used;
4372
4373 // Get word atoms in order.
4374 if( buf->used > ASTACK_SIZE )
4375 {
4376 alloced = 1;
4377 atoms.heap = ait = (UAtom*) memAlloc( sizeof(UAtom) * buf->used );
4378 ur_ctxWordAtoms( buf, atoms.heap );
4379 }
4380 else
4381 {
4382 alloced = 0;
4383 ur_ctxWordAtoms( buf, ait = atoms.stack );
4384 }
4385
4386 while( it != end )
4387 {
4388 ur_strAppendIndent( str, depth );
4389 ur_strAppendCStr( str, ur_atomCStr( ut, *ait++ ) );
4390 ur_strAppendCStr( str, ": " );
4391 DT( ur_type(it) )->toString( ut, it, str, depth );
4392 ur_strAppendChar( str, '\n' );
4393 ++it;
4394 }
4395
4396 if( alloced )
4397 memFree( atoms.heap );
4398}
4399
4400
4401#define ur_ctxRecursion(buf) (buf)->elemSize
4402
4403#define ur_printRecurseEnd(cell,ctxb) \
4404 if( ! ur_isShared(cell->context.buf) ) \
4405 ur_ctxRecursion((UBuffer*) ctxb) = 0
4406
4407static
4408const UBuffer* ur_printRecurse( UThread* ut, const UCell* cell, UBuffer* str )
4409{
4410 const UBuffer* buf = ur_bufferSer( cell );
4411
4412 // Recursion on shared buffers is not handled.
4413 if( ur_isShared(cell->series.buf) )
4414 return buf;
4415
4416 if( ur_ctxRecursion(buf) )
4417 {
4418 unset_toString( ut, cell, str, 0 );
4419 return 0;
4420 }
4421
4422 ur_ctxRecursion((UBuffer*) buf) = 1;
4423 return buf;
4424}
4425
4426
4427void context_toText( UThread* ut, const UCell* cell, UBuffer* str, int depth )
4428{
4429 const UBuffer* buf = ur_printRecurse( ut, cell, str );
4430 if( buf )
4431 {
4432 context_print( ut, buf, str, depth );
4433 ur_printRecurseEnd( cell, buf );
4434 }
4435}
4436
4437
4438/*
4439 If depth is -1 then the context word and braces will be omitted.
4440*/
4441void context_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
4442{
4443 if( depth < 0 )
4444 {
4445 context_toText( ut, cell, str, 0 );
4446 }
4447 else
4448 {
4449 const UBuffer* buf = ur_printRecurse( ut, cell, str );
4450 if( buf )
4451 {
4452 ur_strAppendCStr( str, "context [\n" );
4453 context_print( ut, buf, str, depth + 1 );
4454 ur_strAppendIndent( str, depth );
4455 ur_strAppendCStr( str, "]" );
4456 ur_printRecurseEnd( cell, buf );
4457 }
4458 }
4459}
4460
4461
4462void context_destroy( UBuffer* buf )
4463{
4464 ur_ctxFree( buf );
4465}
4466
4467
4468UDatatype dt_context =
4469{
4470 "context!",
4471 context_make, context_make, context_copy,
4472 context_compare, unset_operate, context_select,
4473 context_toString, context_toText,
4474 unset_recycle, block_mark, context_destroy,
4475 context_markBuf, block_toShared, unset_bind
4476};
4477
4478
4479//----------------------------------------------------------------------------
4480// UT_ERROR
4481
4482
4483int error_make( UThread* ut, const UCell* from, UCell* res )
4484{
4485 if( ur_is(from, UT_STRING) )
4486 {
4487 uint8_t type = UT_BLOCK;
4488
4489 ur_setId(res, UT_ERROR);
4490 res->error.exType = UR_ERR_SCRIPT;
4491 res->error.messageStr = from->series.buf;
4492 res->error.traceBlk = UR_INVALID_BUF;
4493
4494 ur_generate( ut, 1, &res->error.traceBlk, &type ); // gc!
4495 return UR_OK;
4496 }
4497 return ur_error( ut, UR_ERR_TYPE, "make error! expected string! message" );
4498}
4499
4500
4501int error_compare( UThread* ut, const UCell* a, const UCell* b, int test )
4502{
4503 (void) ut;
4504 switch( test )
4505 {
4506 case UR_COMPARE_EQUAL:
4507 case UR_COMPARE_EQUAL_CASE:
4508 if( ur_type(a) != ur_type(b) )
4509 break;
4510 // Fall through...
4511
4512 case UR_COMPARE_SAME:
4513 if( a->error.exType == b->error.exType &&
4514 a->error.messageStr == b->error.messageStr &&
4515 a->error.traceBlk == b->error.traceBlk )
4516 return 1;
4517 break;
4518
4519 case UR_COMPARE_ORDER:
4520 case UR_COMPARE_ORDER_CASE:
4521 if( ur_type(a) == ur_type(b) )
4522 {
4523 if( a->error.exType > b->error.exType )
4524 return 1;
4525 if( a->error.exType < b->error.exType )
4526 return -1;
4527 {
4528 UCell strA, strB;
4529
4530 ur_initSeries( &strA, UT_STRING, a->error.messageStr );
4531 ur_initSeries( &strB, UT_STRING, b->error.messageStr );
4532
4533 return string_compare( ut, &strA, &strB, test );
4534 }
4535 }
4536 break;
4537 }
4538 return 0;
4539}
4540
4541
4542static const char* errorTypeStr[] =
4543{
4544 "Datatype",
4545 "Script",
4546 "Syntax",
4547 "Access",
4548 "Internal"
4549};
4550
4551
4552static void _lineToString( UThread* ut, const UCell* bc, UBuffer* str )
4553{
4554 UBlockIter bi;
4555 const UCell* start;
4556 UIndex fstart;
4557
4558
4559 // Specialized version of ur_blkSlice() to get pointers even if
4560 // bi.it is at bi.end. Changing ur_blkSlice to do this would slow it
4561 // down with extra checks to validate that series.it < buf->used.
4562
4563 bi.buf = ur_bufferSer(bc);
4564 if( ! bi.buf->ptr.cell || ! bi.buf->used )
4565 return;
4566 {
4567 UIndex end = bi.buf->used;
4568 if( (bc->series.end > -1) && (bc->series.end < end) )
4569 end = bc->series.end;
4570 if( end < bc->series.it )
4571 end = bc->series.it;
4572 bi.it = bi.buf->ptr.cell + bc->series.it;
4573 bi.end = bi.buf->ptr.cell + end;
4574 }
4575 start = bi.it;
4576 if( bi.it == bi.end )
4577 --start;
4578
4579 // Set end to newline after bc->series.it.
4580 if( bi.it != bi.end )
4581 {
4582 ++bi.it;
4583 ur_foreach( bi )
4584 {
4585 if( ur_flags(bi.it, UR_FLAG_SOL) )
4586 break;
4587 }
4588 bi.end = bi.it;
4589 }
4590
4591 // Set start to newline at or before bc->series.it.
4592 while( start != bi.buf->ptr.cell )
4593 {
4594 if( ur_flags(start, UR_FLAG_SOL) )
4595 break;
4596 --start;
4597 }
4598 bi.it = start;
4599
4600 // Convert to string without any open/close braces.
4601 ur_foreach( bi )
4602 {
4603 if( bi.it != start )
4604 ur_strAppendChar( str, ' ' );
4605 fstart = str->used;
4606 ur_toStr( ut, bi.it, str, 0 );
4607 if( ur_is(bi.it, UT_BLOCK) || ur_is(bi.it, UT_PAREN) )
4608 {
4609 fstart = ur_strFindChar( str, fstart, str->used, '\n', 0 );
4610 if( fstart > -1 )
4611 str->used = fstart;
4612 }
4613 }
4614}
4615
4616
4617void error_toString( UThread* ut, const UCell* cell, UBuffer* str, int depth )
4618{
4619 uint16_t et = cell->error.exType;
4620 const UBuffer* msg;
4621 (void) depth;
4622
4623 if( et < UR_ERR_COUNT )
4624 {
4625 ur_strAppendCStr( str, errorTypeStr[ et ] );
4626 ur_strAppendCStr( str, " Error: " );
4627 }
4628 else
4629 {
4630 ur_strAppendCStr( str, "Error " );
4631 ur_strAppendInt( str, et );
4632 ur_strAppendCStr( str, ": " );
4633 }
4634
4635 msg = ur_buffer( cell->error.messageStr );
4636 ur_strAppend( str, msg, 0, msg->used );
4637
4638 if( cell->error.traceBlk > UR_INVALID_BUF )
4639 {
4640 UBlockIter bi;
4641
4642 bi.buf = ur_buffer( cell->error.traceBlk );
4643 bi.it = bi.buf->ptr.cell;
4644 bi.end = bi.it + bi.buf->used;
4645
4646 if( bi.buf->used )
4647 {
4648 ur_strAppendCStr( str, "\nTrace:" );
4649 ur_foreach( bi )
4650 {
4651 ur_strAppendCStr( str, "\n -> " );
4652 _lineToString( ut, bi.it, str );
4653 }
4654 }
4655 }
4656}
4657
4658
4659void error_mark( UThread* ut, UCell* cell )
4660{
4661 UIndex n;
4662
4663 ur_markBuffer( ut, cell->error.messageStr );
4664
4665 n = cell->error.traceBlk;
4666 if( n > UR_INVALID_BUF )
4667 {
4668 if( ur_markBuffer( ut, n ) )
4669 block_markBuf( ut, ur_buffer(n) );
4670 }
4671}
4672
4673
4674void error_toShared( UCell* cell )
4675{
4676 UIndex n;
4677 n = cell->error.messageStr;
4678 if( n > UR_INVALID_BUF )
4679 cell->error.messageStr = -n;
4680 n = cell->error.traceBlk;
4681 if( n > UR_INVALID_BUF )
4682 cell->error.traceBlk = -n;
4683}
4684
4685
4686UDatatype dt_error =
4687{
4688 "error!",
4689 error_make, error_make, unset_copy,
4690 error_compare, unset_operate, unset_select,
4691 error_toString, error_toString,
4692 unset_recycle, error_mark, unset_destroy,
4693 unset_markBuf, error_toShared, unset_bind
4694};
4695
4696
4697//EOF
void ur_binErase(UBuffer *, int start, int count)
Remove bytes from the binary.
Definition binary.c:171
void ur_binAppendData(UBuffer *, const uint8_t *data, int len)
Append data to binary buffer.
Definition binary.c:213
UBuffer * ur_makeBinaryCell(UThread *, int size, UCell *cell)
Generate a single binary and set cell to reference it.
Definition binary.c:74
void ur_binReserve(UBuffer *, int size)
Allocates enough memory to hold size bytes.
Definition binary.c:138
void ur_binFree(UBuffer *)
Free binary data.
Definition binary.c:120
void ur_binSlice(UThread *, UBinaryIter *, const UCell *cell)
Set UBinaryIter to binary slice.
Definition binary.c:423
void ur_binAppendArray(UBuffer *, const USeriesIter *si)
Append array slice to binary buffer.
Definition binary.c:227
void ur_binExpand(UBuffer *, int index, int count)
Create space in the binary for count bytes starting at index.
Definition binary.c:194
UIndex ur_makeBinary(UThread *, int size)
Generate and initialize a single binary buffer.
Definition binary.c:56
void ur_blkInsert(UBuffer *, UIndex it, const UCell *cells, int count)
Insert cells into block.
Definition block.c:143
void ur_blkPush(UBuffer *, const UCell *cell)
Copy cell to end of block.
Definition block.c:153
UStatus ur_blkSliceM(UThread *, UBlockIterM *, const UCell *cell)
Set UBlockIterM to block slice.
Definition block.c:224
void ur_blkAppendCells(UBuffer *, const UCell *cells, int count)
Append cells to block.
Definition block.c:125
UBuffer * ur_makeBlockCell(UThread *, int type, int size, UCell *cell)
Generate a single block and set cell to reference it.
Definition block.c:76
UBuffer * ur_ctxClone(UThread *, const UBuffer *src, UCell *cell)
Clone a new context and set cell to reference it.
Definition context.c:220
void ur_ctxFree(UBuffer *)
Free context data.
Definition context.c:316
int ur_ctxLookup(const UBuffer *, UAtom atom)
Find word in context by atom.
Definition context.c:579
#define ur_ctxCell(c, n)
Get pointer of UCell in context by index.
Definition urlan.h:668
void ur_ctxSetWords(UBuffer *, const UCell *it, const UCell *end)
Add the set-word! values in a series of cells to the words in a context.
Definition context.c:283
UBuffer * ur_makeContextCell(UThread *, int size, UCell *cell)
Generate a single context and set cell to reference it.
Definition context.c:111
UBuffer * ur_ctxSort(UBuffer *)
Sort the internal context search table so ur_ctxLookup() is faster.
Definition context.c:510
void ur_ctxWordAtoms(const UBuffer *, UAtom *atoms)
Get word atoms in order.
Definition context.c:334
void ur_bind(UThread *, UBuffer *blk, const UBuffer *ctx, int bindType)
Bind block to context.
Definition context.c:690
const UBuffer * ur_sortedContext(UThread *, const UCell *)
Get context and make sure it is fully sorted for minimal ur_ctxLookup() time.
Definition context.c:547
UBuffer * ur_makePathCell(UThread *, const UCell *nodes, int size, UCell *cell)
Initialize path cell and generate block if needed.
Definition path.c:65
int ur_pathSelectCells(const UCell *selC, UCell *dest)
Definition path.c:204
#define ur_strFree
A string is a simple array.
Definition urlan.h:629
UBuffer * ur_makeStringCell(UThread *, int enc, int size, UCell *cell)
Generate a single string and set cell to reference it.
Definition string.c:104
UIndex ur_strFindCharsRev(const UBuffer *, UIndex start, UIndex end, const uint8_t *charSet, int len)
Find the last character of a set in a string.
Definition string.c:1388
void ur_strAppendBinary(UBuffer *, const uint8_t *it, const uint8_t *end, enum UrlanBinaryEncoding enc)
Append binary data as text of the specified encoding.
Definition string.c:998
void ur_strAppendChar(UBuffer *, int)
Append a single UCS2 character to a string.
Definition string.c:611
UIndex ur_strFindChars(const UBuffer *, UIndex start, UIndex end, const uint8_t *charSet, int len)
Find the first character of a set in a string.
Definition string.c:1353
void ur_strAppendIndent(UBuffer *, int depth)
Append tabs to a string.
Definition string.c:851
UIndex ur_strFindRev(const USeriesIter *, const USeriesIter *, int matchCase)
Find last string in another string or binary series.
Definition string.c:1531
UIndex ur_makeStringUtf8(UThread *, const uint8_t *it, const uint8_t *end)
Generate and initialize a single string buffer from memory holding a UTF-8 string.
Definition string.c:415
void ur_strAppendHex(UBuffer *, uint32_t n, uint32_t hi)
Append a hexidecimal integer to a string.
Definition string.c:765
UIndex ur_strMatch(const USeriesIter *, const USeriesIter *, int matchCase)
Compare characters in two string or binary series.
Definition string.c:1584
void ur_strAppendInt(UBuffer *, int32_t)
Append an integer to a string.
Definition string.c:706
void ur_strInit(UBuffer *, int enc, int size)
Initialize buffer to type UT_STRING.
Definition string.c:430
UIndex ur_strFindChar(const UBuffer *, UIndex, UIndex, int ch, int opt)
Find the first instance of a character in a string.
Definition string.c:1292
void ur_strAppend(UBuffer *, const UBuffer *strB, UIndex itB, UIndex endB)
Append another string buffer to this string.
Definition string.c:899
void ur_strAppendDouble(UBuffer *, double)
Append a double to a string.
Definition string.c:787
UIndex ur_strFind(const USeriesIter *, const USeriesIter *, int matchCase)
Find string in another string or binary series.
Definition string.c:1451
void ur_strAppendFloat(UBuffer *, float)
Append a float to a string.
Definition string.c:813
void ur_strAppendInt64(UBuffer *, int64_t)
Append an 64-bit integer to a string.
Definition string.c:725
void ur_strAppendCStr(UBuffer *, const char *)
Append a null-terminated UTF-8 string to a string buffer.
Definition string.c:641
void ur_seriesSlice(const UThread *, USeriesIter *si, const UCell *cell)
Set USeriesIter to series slice.
Definition env.c:1338
#define ur_bufferSer(c)
Convenience macro for ur_bufferSeries().
Definition urlan.h:752
#define ur_setId(c, t)
Set type and initialize the other 24 bits of UCellId to zero.
Definition urlan.h:701
@ UT_TYPEMASK
Used in UCellDatatype to declare a multi-type datatype!.
Definition urlan.h:73
const char * ur_atomCStr(UThread *, UAtom atom)
Get name of atom.
Definition atoms.c:47
UIndex it
Start position.
Definition urlan.h:338
UStatus ur_error(UThread *, int errorType, const char *fmt,...)
Create error! exception.
Definition env.c:964
const UCell * ur_wordCell(UThread *, const UCell *cell)
Get word value for read-only operations.
Definition env.c:1132
UAtom ur_internAtom(UThread *, const char *it, const char *end)
Add a single atom to the shared environment.
Definition env.c:612
const UCell * end
End position.
Definition urlan.h:388
void ur_toText(UThread *, const UCell *cell, UBuffer *str)
Append textual representation of cell to a string.
Definition env.c:1118
UStatus ur_tokenizeB(UThread *, UIndex blkN, int inputEncoding, const uint8_t *start, const uint8_t *end)
Parse UTF-8 or Latin1 data into block.
Definition tokenize.c:654
UIndex end
End position.
Definition urlan.h:339
const UCell * it
Start position.
Definition urlan.h:387
@ UR_THROW
Returned to indicate an evaluation exception occured.
Definition urlan.h:117
@ UR_OK
Returned to indicate successful evaluation/operation.
Definition urlan.h:118
#define ur_foreach(bi)
Loop over all members of an iterator struct.
Definition urlan.h:760
UBuffer * ur_generate(UThread *, int count, UIndex *index, const uint8_t *)
Generate and initialize buffers of given types.
Definition env.c:771
int ur_true(const UCell *cell)
Check if a value is "true".
Definition env.c:1029
const UBuffer * ur_blockIt(const UThread *ut, UBlockIt *bi, const UCell *blkCell)
Set UBlockIt to the start and end of a block slice.
Definition env.c:1388
int ur_equal(UThread *, const UCell *a, const UCell *b)
Definition env.c:1053
const UBuffer * buf
Buffer pointer.
Definition urlan.h:337
int ur_datatypeCount(UThread *)
Get number of datatypes installed in the environment.
Definition env.c:580
#define ur_isShared(n)
True if buffer number refers to a buffer in the shared environment.
Definition urlan.h:726
#define ur_buffer(n)
Macro to get buffer known to be in thread dataStore.
Definition urlan.h:750
int ur_equalCase(UThread *, const UCell *a, const UCell *b)
Case-sensitive equality test.
Definition env.c:1066
#define ur_type(c)
Return UrlanDataType of cell.
Definition urlan.h:695
void ur_toStr(UThread *, const UCell *cell, UBuffer *str, int depth)
Append data representation of cell to a string.
Definition env.c:1107
#define ur_bufferE(n)
Convenience macro for ur_bufferEnv().
Definition urlan.h:751
Holds information for binding functions.
Definition urlan.h:402
Iterator for const UCell array.
Definition urlan.h:386
The UBuffer struct holds information about a resource, usually a chunk of memory.
Definition urlan.h:266
uint8_t * b
bytes
Definition urlan.h:277
uint8_t form
This can indicate a specific form of the data (such as a string encoding).
Definition urlan.h:269
char * c
chars
Definition urlan.h:276
uint32_t * u32
uint32_t
Definition urlan.h:282
UIndex used
This typically holds the number of elements in the buffer.
Definition urlan.h:271
uint16_t * u16
uint16_t
Definition urlan.h:279
uint8_t type
UrlanDataType identifier.
Definition urlan.h:267
uint8_t flags
Indicates special features of the buffer (UR_STATIC, UR_STRING_ENC_UP).
Definition urlan.h:270
UCell * cell
Array of cells.
Definition urlan.h:275
union UBuffer::@312146223224040072236377336057316010374162171270 ptr
This typically holds a pointer to a chunk of memory.
uint8_t elemSize
This typically holds the byte size of each element.
Definition urlan.h:268
int16_t n[UR_COORD_MAX]
Holds six, 16-bit integers.
Definition urlan.h:195
uint16_t len
Number of integers used in array n.
Definition urlan.h:194
uint8_t n
The UrlanDataType.
Definition urlan.h:167
uint32_t mask0
Low 32 bits of type mask.
Definition urlan.h:169
uint32_t mask1
Middle 32 bits of type mask.
Definition urlan.h:170
UIndex messageStr
Index of message string! buffer.
Definition urlan.h:240
uint16_t exType
The UrlanErrorType.
Definition urlan.h:239
UIndex traceBlk
Index of block! buffer where error occurred.
Definition urlan.h:241
uint8_t flags
Bit field for type-specific properties.
Definition urlan.h:157
UIndex end
Slice end index.
Definition urlan.h:230
UIndex buf
Buffer id.
Definition urlan.h:228
UIndex it
Iterator index.
Definition urlan.h:229
float xyz[3]
The three float values.
Definition urlan.h:203
uint16_t index
Normally the word index into a context.
Definition urlan.h:218
UAtom atom
The name of the word.
Definition urlan.h:219
UIndex ctx
Normally the buffer id of a context.
Definition urlan.h:217
The UDatatype struct holds methods for a specific class of data.
Definition urlan.h:439
void(* toText)(UThread *, const UCell *cell, UBuffer *str, int depth)
Convert cell to its string textual representation.
Definition urlan.h:450
Iterator for const series of any type.
Definition urlan.h:336
The USeriesType struct holds extra methods for series datatypes.
Definition urlan.h:469
The UThread struct stores the data specific to a thread of execution.
Definition urlan.h:309
const UDatatype ** types
Pointer to the datatypes.
Definition urlan.h:322
A cell holds a single value of a simple type or a reference (often to a UBuffer) for a complex type.
Definition urlan.h:248
UCellWord word
For word!, lit-word!, set-word!, get-word! types.
Definition urlan.h:251
UCellError error
For error! type.
Definition urlan.h:258
UCellVec3 vec3
For vec3! type.
Definition urlan.h:254
UCellCoord coord
For coord! type.
Definition urlan.h:253
UCellSeries series
For binary!, bitset!, string!, file!, block!, paren!, path! types.
Definition urlan.h:255
UCellId id
Basic type identification.
Definition urlan.h:249
UCellDatatype datatype
For datatype! type.
Definition urlan.h:250
#define UR_STATIC
This UBuffer::flags bit is set when the UBuffer::ptr points to memory outside of the Urlan datatype s...
Definition urlan.h:292
#define UR_FLAG_SOL
This UCellId::flags bit indicates that the cell starts a new line of code.
Definition urlan.h:82
void ur_arrAppendInt32(UBuffer *, int32_t)
Append int32_t to array.
Definition array.c:180
UStatus
Definition urlan.h:116
void ur_arrExpand(UBuffer *, int index, int count)
Create space in the array for count elements starting at index.
Definition array.c:161
void ur_makeDatatype(UCell *cell, int type)
Initialize cell to be a UT_DATATYPE value of the given type.
Definition datatypes.c:389
#define ur_datatype(c)
Access the UrlanDataType that a UCellDatatype represents.
Definition urlan.h:711
@ UR_ERR_SCRIPT
General script evaluation error.
Definition urlan.h:126
@ UR_ERR_INTERNAL
Fatal internal problem.
Definition urlan.h:129
@ UR_ERR_TYPE
Invalid argument/parameter datatype.
Definition urlan.h:125
void ur_datatypeAddType(UCell *cell, int type)
Add type to multi-type UT_DATATYPE cell.
Definition datatypes.c:414
int ur_isDatatype(const UCell *cell, const UCell *datatype)
Test if cell is of a certain datatype.
Definition datatypes.c:376
#define UR_FLAG_INT_HEX
This UCellId::flags bit indicates that an UR_INT value is printed as hexidecimal.
Definition urlan.h:80
int ur_markBuffer(UThread *, UIndex bufN)
Makes sure the buffer is marked as used.
Definition gc.c:326
@ UR_BIND_THREAD
Bound to buffer in thread dataStore.
Definition urlan.h:88
@ UR_BIND_USER
Start of user defined bindings.
Definition urlan.h:93
@ UR_BIND_UNBOUND
ur_setId() zeros binding so this is default.
Definition urlan.h:87
@ UR_BIND_ENV
Bound to buffer in shared env dataStore.
Definition urlan.h:89
@ UR_BIND_SELF
Evaluate to bound context rather than value.
Definition urlan.h:91
int32_t UIndex
This is an index into an array.
Definition urlan.h:150
void ur_arrErase(UBuffer *, int start, int count)
Remove elements from the array.
Definition array.c:137
void ur_arrReserve(UBuffer *, int count)
Allocates enough memory to hold count elements.
Definition array.c:98
This header provides fixed atoms which are always present.