root/trunk/thune/make.c

Revision 550, 47.9 kB (checked in by krobillard, 7 weeks ago)

Thune:

  • 8-bit string encoding is now Latin-1.
  • Now using WELL512a generator for random numbers.
  • Added hash-map datatype. List datatype can now be disabled in config.
  • Added project-point, remap.
  • Unique & fill now handle vector!.
  • File port 'read now retuns none when end of file reached.

Thune-GL:

  • Added draw-prog! & vertex-buffer! datatypes.
  • Display now accepts /fullscreen option.
  • Added particle-sim dialect.
Line 
1/*============================================================================
2    Thune Interpreter
3    Copyright (C) 2005-2007  Karl Robillard
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18===========================================================================*/
19
20
21#include <stdio.h>
22#include <assert.h>
23#include "urlan.h"
24#include "urlan_atoms.h"
25#include "os.h"
26#include "internal.h"
27#include "charset.h"
28#ifdef UR_CONFIG_LIST
29#include "list.h"
30#endif
31#ifdef UR_CONFIG_HASHMAP
32#include "hashmap.h"
33#endif
34
35
36//#define GC_STRESS_TEST  1
37
38
39extern int64_t ur_stringToInt( const char*, const char*, const char** );
40extern int64_t ur_hexToInt( const char*, const char*, const char** );
41extern double ur_stringToDec( const char*, const char*, const char** );
42
43extern UContext ur_thrGlobal;
44
45
46extern void ur_internDefault( UThread* ut, UCell* wc, UAtom atom,
47                              UCell* cbot, UCell* ctop );
48
49/*
50   wc->flags, wc->word wordBlk, valBlk, & index are set.
51*/
52static void ur_internGlobal( UThread* ut, UCell* wc, UAtom atom )
53{
54    UBlock* cblk = tBlockPtr( BLK_CTX_STACK );
55    ur_internDefault( ut, wc, atom, cblk->ptr.cells,
56                                    cblk->ptr.cells + cblk->used );
57}
58
59
60static UArray* _nextFree( UGCArray* gc )
61{
62    UArray* next;
63
64    next = ((UArray*) gc->arr.ptr.v) + gc->freeList;
65
66    assert( gc->freeList > -1 );
67    assert( next->avail == -1 );
68    assert( next->ptr.v == 0 );
69
70    gc->freeList = next->used;
71    gc->freeCount--;
72
73    return next;
74}
75
76
77/**
78  Size is the number of cells to reserve.  Used is set to 0.
79*/
80UIndex ur_makeBlockT( UThread* ut, int size, UBlock** blkPtr )
81{
82    UBlock* ptr;
83    UArray* ca = &ut->blocks.arr;
84
85#ifdef GC_STRESS_TEST
86    if( ut->flags & UR_THREAD_GC )
87        ur_recycle( ut );
88#endif
89
90    if( ut->blocks.freeCount )
91    {
92        ptr = (UBlock*) _nextFree( &ut->blocks );
93        goto init;
94    }
95
96#ifndef GC_STRESS_TEST
97    if( (ca->used == ca->avail) && (ut->flags & UR_THREAD_GC) )
98    {
99        ur_recycle( ut );
100        if( ut->blocks.freeCount )
101        {
102            ptr = (UBlock*) _nextFree( &ut->blocks );
103            goto init;
104        }
105    }
106#endif
107
108    UR_EXPAND_1( UBlock, ca, ptr );
109
110init:
111
112    ur_arrayInit( ptr, sizeof(UCell), size );
113    if( blkPtr )
114        *blkPtr = ptr;
115    return ur_blockN( ptr );
116}
117
118
119/**
120  Size is the number of bytes to reserve.  Used is set to 0.
121*/
122UIndex ur_makeBinaryT( UThread* ut, int size, UBinary** binPtr )
123{
124    UBinary* ptr;
125    UArray* ca = &ut->bin.arr;
126
127#ifdef GC_STRESS_TEST
128    if( ut->flags & UR_THREAD_GC )
129        ur_recycle( ut );
130#endif
131
132    if( ut->bin.freeCount )
133    {
134        ptr = (UBinary*) _nextFree( &ut->bin );
135        goto init;
136    }
137
138#ifndef GC_STRESS_TEST
139    if( (ca->used == ca->avail) && (ut->flags & UR_THREAD_GC) )
140    {
141        ur_recycle( ut );
142        if( ut->bin.freeCount )
143        {
144            ptr = (UBinary*) _nextFree( &ut->bin );
145            goto init;
146        }
147    }
148#endif
149
150    UR_EXPAND_1( UBinary, ca, ptr );
151
152init:
153
154    ur_arrayInit( ptr, sizeof(char), size );
155    if( binPtr )
156        *binPtr = ptr;
157    return ur_binN( ptr );
158}
159
160
161/*
162   Returns zero if cell can not be converted.
163*/
164UIndex ur_makeBinaryFrom( UThread* ut, const UCell* cell )
165{
166    uint8_t* cpA;
167    uint8_t* cpB;
168    UIndex binN = 0;
169
170    if( ur_binaryMem( ut, cell, &cpA, &cpB ) )
171    {
172        int size;
173        UBinary* bin;
174
175        size = cpB - cpA;
176        binN = ur_makeBinary( size, &bin );
177        if( size )
178        {
179#ifndef __BIG_ENDIAN__
180            if( ur_is(cell, UT_STRING) && (ur_encoding(cell) == UR_ENC_UCS2) )
181                memSwab( cpA, bin->ptr.b, size );
182            else
183#endif
184                memCpy( bin->ptr.b, cpA, size );
185
186            bin->used = size;
187        }
188    }
189
190    return binN;
191}
192
193
194const uint8_t* ur_readBinary( UBinary* bin, const uint8_t* it,
195                                            const uint8_t* end )
196{
197    int c;
198    int byte;
199    int hi;
200    uint8_t* out;
201
202    ur_arrayReserve( bin, 1, bin->used + (end - it) / 2 );
203    out = bin->ptr.b + bin->used;
204
205    byte = hi = 0;
206
207    while( it != end )
208    {
209        c = *it;
210        if( ur_bitIsSet( charset_hex, c ) )
211        {
212            if( (c >= '0') && (c <= '9') )
213                byte |= c - '0';
214            else if( (c >= 'a') && (c <= 'f') )
215                byte |= c - 'a' + 10;
216            else if( (c >= 'A') && (c <= 'F') )
217                byte |= c - 'A' + 10;
218
219            if( hi )
220            {
221                *out++ = byte;
222                byte = hi = 0;
223            }
224            else
225            {
226                byte <<= 4;
227                hi = 1;
228            }
229        }
230        else if( ! ur_bitIsSet( charset_white, c ) )
231        {
232            break;
233        }
234        ++it;
235    }
236
237    bin->used = out - bin->ptr.b;
238    return it;
239}
240
241
242/**
243  \param size  Number of bytes to allocate.  If non-zero, retp->ptr will
244               point to the new buffer.  If zero, retp->ptr will be zero.
245  \param retp  If non-zero, it will be set to the new resource.
246
247  Only the UResource dataType member is used by the system.  The rest of the
248  structure may be used as the caller sees fit.
249
250  If the size is non-zero, then the caller is responsible for calling
251  memFree() with the retp->ptr.  This is normally done in the datatype
252  gcDestroyResource method.
253*/
254UIndex ur_makeResourceT( UThread* ut, int dataType, int size,
255                         UResource** retp )
256{
257    UResource* buf;
258    UGCArray* gc = &ut->resources;
259    UArray* ca = &gc->arr;
260
261#ifdef GC_STRESS_TEST
262    if( ut->flags & UR_THREAD_GC )
263        ur_recycle( ut );
264#endif
265
266    if( ut->resources.freeCount )
267    {
268#ifndef GC_STRESS_TEST
269getFree:
270#endif
271        buf = ((UResource*) ca->ptr.v) + gc->freeList;
272
273        assert( gc->freeList > -1 );
274        assert( buf->dataType == UT_UNSET );
275
276        gc->freeList = buf->link;
277        gc->freeCount--;
278
279        goto init;
280    }
281
282#ifndef GC_STRESS_TEST
283    if( (ca->used == ca->avail) && (ut->flags & UR_THREAD_GC) )
284    {
285        ur_recycle( ut );
286        if( ut->resources.freeCount )
287            goto getFree;
288    }
289#endif
290
291    UR_EXPAND_1( UResource, ca, buf );
292
293init:
294
295    buf->dataType = dataType;
296    buf->ptr      = size ? memAlloc( size ) : 0;
297
298    if( retp )
299        *retp = buf;
300
301    return buf - ((UResource*) ca->ptr.v);
302}
303
304
305/**
306   Make context with wordCount reserved (used set to zero).
307*/
308void ur_makeContextT( UThread* ut, UContext* ctx, int wordCount )
309{
310    UBlock* ptrA;
311    UBlock* ptrB;
312    UArray* ca = &ut->blocks.arr;
313
314#ifdef GC_STRESS_TEST
315    if( ut->flags & UR_THREAD_GC )
316        ur_recycle( ut );
317#endif
318
319    if( ut->blocks.freeCount > 1 )
320    {
321        ptrA = (UBlock*) _nextFree( &ut->blocks );
322        ptrB = (UBlock*) _nextFree( &ut->blocks );
323        goto init;
324    }
325
326#ifndef GC_STRESS_TEST
327    if( (ca->used == ca->avail) && (ut->flags & UR_THREAD_GC) )
328    {
329        ur_recycle( ut );
330        if( ut->blocks.freeCount > 1 )
331        {
332            ptrA = (UBlock*) _nextFree( &ut->blocks );
333            ptrB = (UBlock*) _nextFree( &ut->blocks );
334            goto init;
335        }
336    }
337#endif
338
339    ur_arrayReserve( ca, sizeof(UBlock), ca->used + 2 );
340    ptrA = ((UBlock*) (ca->ptr.v)) + ca->used;
341    ptrB = ptrA + 1;
342    ca->used += 2;
343
344init:
345
346    ur_arrayInit( ptrA, sizeof(UCell), wordCount );
347    ur_arrayInit( ptrB, sizeof(UCell), wordCount );
348
349    ur_initType( ctx, UT_CONTEXT );
350    ctx->ctx.wordBlk     = ur_blockN( ptrA );
351    ctx->ctx.valBlk      = ur_blockN( ptrB );
352    ctx->ctx.protoValBlk = ctx->ctx.valBlk;
353}
354
355
356/*
357   Create context from initializer block.
358   protoCtx may be zero.
359   Caller must hold init and protoCtx (if non-zero) from GC.
360*/
361static void _makeContextProto( UThread* ut, UContext* res,
362                               const UCell* init, const UCell* protoCtx )
363{
364    if( init && ur_is(init, UT_BLOCK) )
365    {
366        int size = 0;
367        UBlock* blk;
368        UCell* it;
369        UCell* start;
370        UCell* end;
371
372        blk = ur_blockPtr( init->series.n );
373        UR_ITER_BLOCK( start, end, blk, init )
374
375        it = start;
376
377        if( protoCtx )
378        {
379            // Check if prototype must be extended with new words.
380
381            while( it != end )
382            {
383                if( ur_is(it, UT_SETWORD) )
384                {
385                    if( ur_lookup(protoCtx, ur_atom(it)) < 0 )
386                        ++size;
387                }
388                ++it;
389            }
390
391            if( size )
392            {
393                UIndex pwN;
394                UIndex pvN;
395                UCell* rend;
396                UBlock* rblk;
397
398                // Keep indices in case protoCtx == res
399                pwN = protoCtx->ctx.wordBlk;
400                pvN = protoCtx->ctx.valBlk;
401
402                blk  = ur_blockPtr( pvN );
403                size += blk->used;
404
405                ur_makeContext( res, size );
406
407                // Copy value block.
408
409                blk  = ur_blockPtr( pvN );      // re-acquire
410                rblk = ur_blockPtr( res->ctx.valBlk );
411                rblk->used = size;
412                ur_copyCells( blk->ptr.cells,
413                              blk->ptr.cells + blk->used,
414                              rblk->ptr.cells );
415#if 0
416                // Deep copy
417                it   = rblk->ptr.cells;
418                rend = rblk->ptr.cells + size;
419                while( it != rend )
420                {
421                    ur_clone( ut, it, UR_COPY_ALL, 2 );
422                    ++it;
423                }
424#endif
425
426                // Init new words to none.
427
428                it   = rblk->ptr.cells + blk->used;
429                rend = rblk->ptr.cells + size;
430                while( it != rend )
431                {
432                    ur_initType( it, UT_NONE );
433                    ++it;
434                }
435
436                // Copy word block.
437
438                blk  = ur_blockPtr( pwN );
439                rblk = ur_blockPtr( res->ctx.wordBlk );
440                rblk->used = blk->used;
441                ur_copyCells( blk->ptr.cells,
442                              blk->ptr.cells + blk->used,
443                              rblk->ptr.cells );
444            }
445            else
446            {
447                // No new words in init block; clone to share word block.
448
449                if( res != protoCtx )
450                {
451                    ur_copyCell( res, *protoCtx );
452                }
453                ur_clone( ut, res, size, 1 );
454                return;
455            }
456        }
457        else
458        {
459            while( it != end )
460            {
461                if( ur_is(it, UT_SETWORD) )
462                    ++size;
463                ++it;
464            }
465
466            ur_makeContext( res, size );
467        }
468
469        it = start;
470        while( it != end )
471        {
472            if( ur_is(it, UT_SETWORD) )
473                ur_internWord( res, it->word.atom );
474            ++it;
475        }
476    }
477}
478
479
480/*--------------------------------------------------------------------------*/
481
482
483#define ESCAPE_CHAR     '^'
484
485
486static int toHex( int n )
487{
488    if( (n >= '0') && (n <= '9') )
489        return n - '0';
490    if( (n >= 'a') && (n <= 'f') )
491        return n - 'a' + 10;
492    if( (n >= 'A') && (n <= 'F') )
493        return n - 'A' + 10;
494    return -1;
495}
496
497
498/*
499  Returns non-zero if identical up to end of either string.
500*/
501int memEqual( const char* a, const char* b, int len )
502{
503    const char* end = a + len;
504    while( a != end )
505    {
506        if( *a != *b )
507            return 0;
508        ++a;
509        ++b;
510    }
511    return 1;
512}
513
514
515/* Returns -1 if not special */
516static int _translateSpecialSeq( const char* cp, const char* end )
517{
518    int len;
519    len = end - cp;
520    if( len == 2 )
521    {
522        len = toHex( cp[0] );
523        if( len > -1 )
524        {
525            int d2 = toHex( cp[1] );
526            if( d2 > -1 )
527                return (len << 4) + d2;
528        }
529    }
530    else if( len == 3 )
531    {
532        if( memEqual( cp, "tab", 3 ) )
533            return '\t';
534        if( memEqual( cp, "esc", 3 ) )
535            return 27;
536    }
537    else if( len == 4 )
538    {
539        if( memEqual( cp, "line", 4 ) )
540            return '\n';
541        if( memEqual( cp, "page", 4 ) )
542            return '\f';
543        if( memEqual( cp, "back", 4 ) )
544            return '\b';
545        if( memEqual( cp, "bell", 4 ) )
546            return '\a';
547        if( memEqual( cp, "null", 4 ) )
548            return '\0';
549    }
550    return -1;
551}
552
553
554/**
555  Returns -1 if failed.
556*/
557int ur_escapedCharacter( const uint8_t** cp, const uint8_t* end )
558{
559    int val;
560    const uint8_t* it = *cp;
561
562    if( it == end )
563        return -1;
564
565    switch( *it )
566    {
567        case '0':
568        case '1':
569        case '2':
570        case '3':
571        case '4':
572        case '5':
573        case '6':
574        case '7':
575        case '8':
576        case '9':
577            val = *it - '0';
578            break;
579
580        case 'A':
581        case 'B':
582        case 'C':
583        case 'D':
584        case 'E':
585        case 'F':
586            val = *it - 'A' + 10;
587            break;
588
589        case 'a':
590        case 'b':
591        case 'c':
592        case 'd':
593        case 'e':
594        case 'f':
595            val = *it - 'a' + 10;
596            break;
597
598        case '/':
599            val = '\n';
600            break;
601
602        case '-':
603            val = '\t';
604            break;
605
606        case '(':
607        {
608            const uint8_t* pend;
609            pend = ++it;
610            while( pend != end )
611            {
612                if( *pend == ')' )
613                    break;
614                ++pend;
615            }
616            if( pend == end )
617                return -1;
618            val = _translateSpecialSeq( (char*) it, (char*) pend );
619            it = pend;
620        }
621            break;
622
623        default:
624            val = *it;
625            break;
626    }
627
628    *cp = ++it;
629    return val;
630}
631
632
633/*
634   Convert UTF-8 to UCS-2
635*/
636static void _makeString16( UBinary* str, const uint8_t* cp, int len )
637{
638    uint16_t  ch;
639    uint16_t* out;
640    const uint8_t* end;
641
642    ur_arrayReserve( str, 1, len * sizeof(uint16_t) );
643    out = str->ptr.u16;
644
645    end = cp + len;
646    while( cp != end )
647    {
648        ch = *cp++;
649
650        if( ch <= 0x7f )
651        {
652            *out++ = ch;
653        }
654        else if( ch >= 0xc2 && ch <= 0xdf )
655        {
656            if( cp != end )
657            {
658                *out++ = ((ch & 0x1f) << 6) | (*cp & 0x3f);
659                ++cp;
660            }
661        }
662        else if( ch >= 0xe0 && ch <= 0xef )
663        {
664            if( (end - cp) < 2 )
665                break;
666            *out++ = ((ch    & 0x0f) << 12) |
667                     ((cp[0] & 0x3f) <<  6) |
668                      (cp[1] & 0x3f);
669            cp += 2;
670        }
671        else if( ch >= 0xf0 && ch <= 0xf3 )
672        {
673            if( (end - cp) < 3 )
674                break;
675            *out++ = 0;     // Only handle UCS-2
676            cp += 3;
677        }
678    }
679
680    str->avail /= 2;
681    str->used = out - str->ptr.u16;
682}
683
684
685/**
686  \param res  Result cell.
687  \param text UTF-8 string.
688  \param len  Byte length of string.  If len is less than zero then the
689              length is automatically determined by looking for a NULL
690              terminator.
691
692  Special characters are translated.
693*/
694UString* ur_makeStringT( UThread* ut, UCell* res, const char* text, int len )
695{
696    UIndex strN;
697    UBinary* str;
698    const uint8_t* txt = (const uint8_t*) text;
699    const uint8_t* cp;
700    const uint8_t* end;
701    uint8_t* out;
702    unsigned int ch;
703
704    if( len == 0 )
705    {
706        strN = ur_makeBinary( 0, 0 );
707        goto init;
708    }
709
710    if( len < 0 )
711    {
712        cp = txt;
713        while( *cp )
714            ++cp;
715        len = cp - txt;
716    }
717
718    strN = ur_makeBinary( len + UR_CTERM_LEN, &str );
719
720    cp  = txt;
721    end = txt + len;
722    out = str->ptr.b;
723    while( cp != end )
724    {
725        if( *cp == ESCAPE_CHAR )
726        {
727            ++cp;
728            *out++ = ur_escapedCharacter( &cp, end );
729        }
730        else
731        {
732            ch = *cp++;
733            if( ch > 0x7f )
734            {
735                if( ch <= 0xdf )
736                {
737                    // If the UTF-8 value is in the Latin-1 range then
738                    // stay with an 8-bit string.
739                    ch = ((ch & 0x1f) << 6) | (*cp & 0x3f);
740                    if( ch < 256 )
741                    {
742                        ++cp;
743                        goto output_char;
744                    }
745                }
746                _makeString16( str, txt, len );
747                ur_initString( res, strN, 0 );
748                ur_setEncoding( res, UR_ENC_UCS2 );
749                return str;
750            }
751output_char:
752            *out++ = ch;
753        }
754    }
755
756    str->used = out - str->ptr.b;
757    str->ptr.b[ str->used ] = '\0';
758
759init:
760
761    ur_initString( res, strN, 0 );
762    return str;
763}
764
765
766/*--------------------------------------------------------------------------*/
767
768
769void _convertToDecimalVector( UArray* arr )
770{
771    int32_t* it  = arr->ptr.i;
772    int32_t* end = it + arr->used;
773
774    while( it != end )
775    {
776        *((float*) it) = (float) *it;
777        ++it;
778    }
779}
780
781
782UIndex ur_makeVectorT( UThread* ut, int size, UArray** ptr )
783{
784    UIndex binN;
785    UArray* bin;
786
787    binN = ur_makeBinary( size * sizeof(int32_t), &bin );
788    bin->avail /= sizeof(int32_t);
789
790    if( ptr )
791        *ptr = bin;
792
793    return binN;
794}
795
796
797#define BE32_TO_INT(bp)  (bp[0] << 24 | bp[1] << 16 | bp[2] << 8 | bp[3])
798#define LE32_TO_INT(bp)  (bp[3] << 24 | bp[2] << 16 | bp[1] << 8 | bp[0])
799
800static inline void binaryToVectorI( int32_t* it, int32_t* end,
801                                    const uint8_t* bp )
802{
803    while( it != end )
804    {
805        *it++ = BE32_TO_INT(bp);
806        bp += 4;
807    }
808}
809
810
811// Returns zero if make failed.
812UIndex ur_makeVectorCell( UThread* ut, const UCell* from, UCell* res )
813{
814    UArray* bin;
815    UIndex binN = 0;
816    int vtype = UT_INT;
817
818    if( ur_is(from, UT_BLOCK) )
819    {
820        UBlock* blk;
821        UCell* it;
822        UCell* end;
823
824        blk = ur_block( from );
825        UR_ITER_BLOCK( it, end, blk, from )
826
827        binN = ur_makeVector( end - it, &bin );
828
829        while( it != end )
830        {
831            if( ur_is(it, UT_INT) )
832            {
833                bin->ptr.i[ bin->used ] = ur_int(it);
834                ++bin->used;
835            }
836            else if( ur_is(it, UT_DECIMAL) )
837            {
838                goto decimal;
839            }
840            ++it;
841        }
842        goto init;
843
844decimal:
845
846        vtype = UT_DECIMAL;
847        _convertToDecimalVector( bin );
848
849        while( it != end )
850        {
851            if( ur_is(it, UT_DECIMAL) )
852            {
853                bin->ptr.f[ bin->used ] = (float) ur_decimal(it);
854                ++bin->used;
855            }
856            else if( ur_is(it, UT_INT) )
857            {
858                bin->ptr.f[ bin->used ] = (float) ur_int(it);
859                ++bin->used;
860            }
861            ++it;
862        }
863    }
864    else if( ur_is(from, UT_BINARY) )
865    {
866        uint8_t* cpA;
867        uint8_t* cpB;
868        UArray* vec;
869        int len;
870
871        ur_binaryMem( ut, from, &cpA, &cpB );
872        len = (cpB - cpA) / 4;
873        binN = ur_makeVector( len, &vec );
874        if( cpA )
875        {
876            vec->used = len;
877            binaryToVectorI( vec->ptr.i, vec->ptr.i + len, (uint8_t*) cpA );
878        }
879    }
880    else if( ur_is(from, UT_INT) )
881    {
882        binN = ur_makeVector( ur_int(from), 0 );
883    }
884
885    if( binN )
886    {
887init:
888        ur_initVector(res, vtype, binN, 0);
889        return binN;
890    }
891
892    return 0;
893}
894
895
896/*--------------------------------------------------------------------------*/
897
898
899#if 0
900typedef struct
901{
902    UAtom    name;
903    uint16_t index;
904    UAtom    ctype;
905}
906UStructField;
907
908
909/*
910   [field1 type1  field2 type2 ...] 
911*/
912UIndex ur_makeStructCell( const UCell* from, UCell* res )
913{
914    UArray* bin;
915    UIndex binN = 0;
916
917    if( ur_is(from, UT_BLOCK) )
918    {
919        UBlock* blk;
920        UCell* it;
921        UCell* end;
922        int count;
923        UAtom wrd;
924
925        blk = ur_block( from );
926        UR_ITER_BLOCK( it, end, blk, from )
927
928        wrd = 0;
929        count = 0;
930
931        while( it != end )
932        {
933            if( ur_is(it, UT_WORD) )
934            {
935                if( count & 1 )
936                {
937                    wrd = ur_atom(it);
938                }
939                else
940                {
941                    switch( ur_atom(it) )
942                    {
943                        case UT_CHAR:
944                            break;
945                        case UT_INT:
946                            break;
947                        case UT_INT64:
948                            break;
949                        case UT_DECIMAL:
950                            break;
951                        case UT_VECTOR:
952                            break;
953                    }
954                }
955                ++count;
956            }
957
958            ++it;
959        }
960
961        binN = ur_makeBinary( end - it, &bin );
962    }
963    //else if( ur_is(from, UT_STRUCT) ) { }
964
965    if( binN )
966    {
967        ur_initType(res, UT_STRUCT);
968        ur_setSeries(res, binN, 0);
969        return binN;
970    }
971
972    return 0;
973}
974#endif
975
976
977/*--------------------------------------------------------------------------*/
978
979
980static void _setBitsetBin( UThread* ut, uint8_t* bits, const UCell* from )
981{
982    uint8_t* it;
983    uint8_t* end;
984    UBinary* src = ur_bin(from);
985
986    UR_ITER_BIN( it, end, src, from )
987    while( it != end )
988    {
989        ur_setBit( bits, *it );
990        ++it;
991    }
992}
993
994
995static void _setBitsetStr( UThread* ut, uint8_t* bits, const UCell* from )
996{
997    char* it;
998    char* end;
999    UBinary* src = ur_bin(from);
1000
1001    UR_ITER_STR( it, end, src, from )
1002    while( it != end )
1003    {
1004        //if( *it < 256 )
1005        {
1006            ur_setBit( bits, *it );
1007        }
1008        ++it;
1009    }
1010}
1011
1012
1013UIndex ur_makeBitset( UThread* ut, const UCell* from )
1014{
1015    UIndex binN;
1016    UBinary* bin;
1017    uint8_t* bits;
1018    int len;
1019
1020
1021    switch( ur_type(from) )
1022    {
1023        case UT_INT:
1024            len = (ur_int(from) + 7) / 8;
1025            break;
1026
1027        case UT_BINARY:
1028            bin  = ur_bin(from);
1029            len  = bin->used;
1030            bits = bin->ptr.b;
1031
1032            binN = ur_makeBinary( bin->used, &bin );
1033            bin->used = len;
1034            memCpy( bin->ptr.b, bits, len );
1035            return binN;
1036
1037        default:
1038            len = 32;
1039            break;
1040    }
1041
1042    binN = ur_makeBinary( len, &bin );
1043    bin->used = len;
1044    bits = bin->ptr.b;
1045
1046    memSet( bits, 0, bin->used );
1047
1048    switch( ur_type(from) )
1049    {
1050        case UT_CHAR:
1051            ur_setBit( bits, ur_char(from) );
1052            break;
1053
1054        case UT_BLOCK:
1055        {
1056            UCell* it;
1057            UCell* end;
1058            UBlock* src = ur_block(from);
1059            int range = -1;
1060
1061            UR_ITER_BLOCK( it, end, src, from )
1062            while( it != end )
1063            {
1064                switch( ur_type(it) )
1065                {
1066                    case UT_WORD:
1067                        if( (ur_atom(it) == UR_ATOM_DASH) &&
1068                            (range > -1) )
1069                        {
1070                            int r2;
1071                            UCell* rend = it + 1;
1072                            if( (rend != end) && ur_is(rend, UT_CHAR) )
1073                            {
1074                                r2 = ur_char(rend);
1075                                while( range < r2 )
1076                                {
1077                                    ++range;
1078                                    ur_setBit( bits, range );
1079                                }
1080                            }
1081                            range = -1;
1082                        }
1083                        break;
1084
1085                    case UT_CHAR:
1086                        ur_setBit( bits, ur_char(it) );
1087                        range = ur_char(it);
1088                        break;
1089
1090                    case UT_BINARY:
1091                        _setBitsetBin( ut, bits, it );
1092                        break;
1093
1094                    case UT_STRING:
1095                        _setBitsetStr( ut, bits, it );
1096                        break;
1097                }
1098                ++it;
1099            }
1100        }
1101            break;
1102
1103        case UT_STRING:
1104            _setBitsetStr( ut, bits, from );
1105            break;
1106    }
1107
1108    return binN;
1109}
1110
1111
1112/*--------------------------------------------------------------------------*/
1113
1114
1115#define UR_MAX_PATH_LEN     16      // LIMIT: Maximum path/typemask nodes.
1116
1117
1118#define SET_PATH_NODE \
1119    if( count == (UR_MAX_PATH_LEN - 1) ) \
1120        return 0; \
1121    if( (*cp >= '0' && *cp <= '9') || (*cp == '-') ) { \
1122        node[ count ] = ur_stringToInt( cp, it, 0 ); \
1123    } else { \
1124        nodeType |= 1 << count; \
1125        node[ count ] = ur_intern( cp, it - cp ); \
1126    } \
1127    ++count;
1128
1129
1130/*
1131   Returns zero if spA is not a valid selector, datatype, or path.
1132*/
1133int ur_makeSelector( UThread* ut, UCell* res,
1134                     const char* spA, const char* end )
1135{
1136    const char* cp;
1137    co