root/trunk/orca/series.c

Revision 341, 54.1 kB (checked in by krobillard, 2 years ago)

Fixed 'at (thanks to Krzysztof Kowalczyk)
Thune - Added 'appen helper. [0 random] no longer crashes.

Line 
1/*============================================================================
2    ORCA Interpreter
3    Copyright (C) 2005-2006  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 "os.h"
22#include "ovalue.h"
23#include "charset.h"
24#include "internal.h"
25
26
27#define QUERY_TYPE(t) \
28    int logic; \
29    logic = (t) ? OR_TRUE : OR_FALSE; \
30    orResult( OT_LOGIC, logic )
31
32
33void orSeriesQNative( OValue* a1 )    { QUERY_TYPE(orIsSeries(a1->type)); }
34void orAnyStringQNative( OValue* a1 ) { QUERY_TYPE(orIsString(a1->type)); }
35void orAnyBlockQNative( OValue* a1 )  { QUERY_TYPE(orIsBlock(a1->type)); }
36void orAnyWordQNative( OValue* a1 )   { QUERY_TYPE(orIsWord(a1->type)); }
37void orIntegerQNative( OValue* a1 )   { QUERY_TYPE(a1->type == OT_INTEGER); }
38void orTagQNative( OValue* a1 )       { QUERY_TYPE(a1->type == OT_TAG); }
39
40void orBinaryQNative( OValue* a1 )    { QUERY_TYPE(a1->type == OT_BINARY); }
41void orBitsetQNative( OValue* a1 )    { QUERY_TYPE(a1->type == OT_BITSET); }
42void orBlockQNative( OValue* a1 )     { QUERY_TYPE(a1->type == OT_BLOCK); }
43void orCharQNative( OValue* a1 )      { QUERY_TYPE(a1->type == OT_CHAR); }
44void orDatatypeQNative( OValue* a1 )  { QUERY_TYPE(a1->type == OT_DATATYPE); }
45void orDecimalQNative( OValue* a1 )   { QUERY_TYPE(a1->type == OT_DECIMAL); }
46void orErrorQNative( OValue* a1 )     { QUERY_TYPE(a1->type == OT_ERROR); }
47void orFileQNative( OValue* a1 )      { QUERY_TYPE(a1->type == OT_FILE); }
48void orFunctionQNative( OValue* a1 )  { QUERY_TYPE(a1->type == OT_FUNCTION); }
49void orGetWordQNative( OValue* a1 )   { QUERY_TYPE(a1->type == OT_GETWORD); }
50void orHashQNative( OValue* a1 )      { QUERY_TYPE(a1->type == OT_HASH); }
51void orIssueQNative( OValue* a1 )     { QUERY_TYPE(a1->type == OT_ISSUE); }
52void orListQNative( OValue* a1 )      { QUERY_TYPE(a1->type == OT_LIST); }
53void orLitPathQNative( OValue* a1 )   { QUERY_TYPE(a1->type == OT_LITPATH); }
54void orLitWordQNative( OValue* a1 )   { QUERY_TYPE(a1->type == OT_LITWORD); }
55void orLogicQNative( OValue* a1 )     { QUERY_TYPE(a1->type == OT_LOGIC); }
56void orNativeQNative( OValue* a1 )    { QUERY_TYPE(a1->type == OT_NATIVE); }
57void orNoneQNative( OValue* a1 )      { QUERY_TYPE(a1->type == OT_NONE); }
58void orNumberQNative( OValue* a1 )    { QUERY_TYPE(orIsNumber(a1->type)); }
59void orObjectQNative( OValue* a1 )    { QUERY_TYPE(a1->type == OT_OBJECT); }
60void orOpQNative( OValue* a1 )        { QUERY_TYPE(a1->type == OT_OP); }
61void orPairQNative( OValue* a1 )      { QUERY_TYPE(a1->type == OT_PAIR); }
62void orParenQNative( OValue* a1 )     { QUERY_TYPE(a1->type == OT_PAREN); }
63void orPathQNative( OValue* a1 )      { QUERY_TYPE(a1->type == OT_PATH); }
64void orRefinementQNative( OValue* a1 ){ QUERY_TYPE(a1->type == OT_REFINEMENT); }
65void orSetPathQNative( OValue* a1 )   { QUERY_TYPE(a1->type == OT_SETPATH); }
66void orSetWordQNative( OValue* a1 )   { QUERY_TYPE(a1->type == OT_SETWORD); }
67void orStringQNative( OValue* a1 )    { QUERY_TYPE(a1->type == OT_STRING); }
68void orTimeQNative( OValue* a1 )      { QUERY_TYPE(a1->type == OT_TIME); }
69void orTupleQNative( OValue* a1 )     { QUERY_TYPE(a1->type == OT_TUPLE); }
70void orUnsetQNative( OValue* a1 )     { QUERY_TYPE(a1->type == OT_UNSET); }
71void orWordQNative( OValue* a1 )      { QUERY_TYPE(a1->type == OT_WORD); }
72
73#ifdef OR_CONFIG_NUMBER_ARRAYS
74void orDecArrQNative( OValue* a1 )    { QUERY_TYPE(a1->type == OT_DEC_ARRAY); }
75void orIntArrQNative( OValue* a1 )    { QUERY_TYPE(a1->type == OT_INT_ARRAY); }
76#endif
77
78
79/*
80   Returns -1 if val is not a series.
81*/
82int orSeriesUsed( OValue* val )
83{
84    switch( val->type )
85    {
86        case OT_BLOCK:
87        case OT_PAREN:
88        case OT_PATH:
89            return orBLOCK(val)->used;
90            break;
91
92        case OT_STRING:
93        case OT_ISSUE:
94        case OT_FILE:
95        case OT_TAG:
96        case OT_BINARY:
97            return orSTRING(val)->used;
98
99#ifdef OR_CONFIG_NUMBER_ARRAYS
100        case OT_DEC_ARRAY:
101            return orDEC_ARRAY(val)->used;
102        case OT_INT_ARRAY:
103            return orINT_ARRAY(val)->used;
104#endif
105    }
106    return -1;
107}
108
109
110OR_NATIVE( orLengthQNative )
111{
112    int len;
113
114    if( a1->type == OT_TUPLE )
115    {
116        len = a1->argc;
117    }
118    else if( a1->type == OT_LIST )
119    {
120        len = 0;
121        if( a1->series.it )
122        {
123            OBlock* blk = orBLOCK(a1);
124            OValue* it = blk->values + a1->series.it;
125            while( it->LIST_NEXT > 0 )
126            {
127                ++len;
128                orListNextNode( blk, it );
129            }
130        }
131    }
132    else
133    {
134        len = orSeriesUsed(a1);
135        if( len > -1 )
136            len -= a1->series.it;
137    }
138
139    orResult( OT_INTEGER, len );
140    //orError( "length? expected series argument" );
141}
142
143
144OR_NATIVE( orHeadNative )
145{
146    if( a1->type == OT_LIST )
147    {
148        OBlock* blk = orBLOCK(a1);
149        a1->series.it = blk->values->LIST_NEXT;
150    }
151    else if( orIsSeries(a1->type) )
152        a1->series.it = 0;
153    else
154        orError( "head expected series argument" );
155}
156
157
158OR_NATIVE( orTailNative )
159{
160    if( a1->type == OT_LIST )
161    {
162        a1->series.it = LIST_TAIL;
163    }
164    else
165    {
166        int len = orSeriesUsed(a1);
167        if( len > -1 )
168            a1->series.it = len;
169        else
170            orError( "tail expected series argument" );
171    }
172}
173
174
175OR_NATIVE( orBackNative )
176{
177    if( a1->type == OT_LIST )
178    {
179        OBlock* blk = orBLOCK(a1);
180        OValue* it = blk->values + a1->series.it;
181        if( it->LIST_PREV > 0 )
182            a1->series.it = it->LIST_PREV;
183    }
184    else if( orIsSeries(a1->type) )
185    {
186        if( a1->series.it > 0 )
187            --a1->series.it;
188    }
189    else
190    {
191        orError( "back expected series argument" );
192    }
193}
194
195
196OR_NATIVE( orNextNative )
197{
198    if( a1->type == OT_LIST )
199    {
200        if( a1->series.it )
201        {
202            OBlock* blk = orBLOCK(a1);
203            OValue* it = blk->values + a1->series.it;
204            if( it->LIST_NEXT > 0 )
205                a1->series.it = it->LIST_NEXT;
206        }
207    }
208    else
209    {
210        int len = orSeriesUsed(a1);
211        if( a1->series.it < len )
212            ++a1->series.it;
213    }
214}
215
216
217OR_NATIVE( orIndexQNative )
218{
219    if( a1->type == OT_LIST )
220    {
221        // TODO
222    }
223    else if( orIsSeries(a1->type) )
224    {
225        orResult( OT_INTEGER, a1->series.it + 1 );
226        return;
227    }
228    orError( "index? expected series argument" );
229}
230
231
232OR_NATIVE( orHeadQNative  )
233{
234    int logic = OR_FALSE;
235
236    if( a1->type == OT_LIST )
237    {
238        OBlock* blk = orBLOCK(a1);
239        OValue* it = blk->values + a1->series.it;
240        if( it->LIST_PREV == LIST_HEAD )
241            logic = OR_TRUE;
242    }
243    else
244    {
245        if( a1->series.it == 0 )
246            logic = OR_TRUE;
247    }
248
249    orResult( OT_LOGIC, logic );
250}
251
252
253OR_NATIVE( orTailQNative  )
254{
255    int logic = OR_FALSE;
256
257    if( a1->type == OT_LIST )
258    {
259        if( a1->series.it == LIST_TAIL )
260           logic = OR_TRUE;
261    }
262    else
263    {
264        int len = orSeriesUsed(a1);
265        if( len > -1)
266        {
267            if( a1->series.it >= len )
268               logic = OR_TRUE;
269        }
270    }
271
272    orResult( OT_LOGIC, logic );
273}
274
275
276OR_NATIVE( orClearNative )
277{
278    switch( a1->type )
279    {
280        case OT_BLOCK:
281        case OT_PAREN:
282        case OT_PATH:
283        {
284            OBlock* blk = orBLOCK(a1);
285            if( a1->series.it < blk->used )
286                blk->used = a1->series.it;
287        }
288            break;
289
290        case OT_STRING:
291        case OT_ISSUE:
292        case OT_FILE:
293        case OT_TAG:
294        case OT_BINARY:
295        {
296            OString* str = orSTRING(a1);
297            if( a1->series.it < str->used )
298                str->used = a1->series.it;
299        }
300            break;
301
302        case OT_BITSET:
303        {
304            OString* str = orSTRING(a1);
305            if( str->used )
306                memSet( str->byteArray, 0, str->used );
307        }
308            break;
309
310        case OT_LIST:
311            // TODO
312            break;
313
314#ifdef OR_CONFIG_NUMBER_ARRAYS
315        case OT_DEC_ARRAY:
316        {
317            OArray* arr = orDEC_ARRAY(a1);
318            if( a1->series.it < arr->used )
319                arr->used = a1->series.it;
320        }
321            break;
322
323        case OT_INT_ARRAY:
324        {
325            OArray* arr = orINT_ARRAY(a1);
326            if( a1->series.it < arr->used )
327                arr->used = a1->series.it;
328        }
329            break;
330#endif
331
332        case OT_NONE:
333            break;
334    }
335}
336
337
338static void copyV( OValue* src, OValue* srcEnd, OValue* dest )
339{
340#if __WORDSIZE == 64
341    uint64_t* it  = (uint64_t*) src;
342    uint64_t* end = (uint64_t*) srcEnd;
343    uint64_t* dst = (uint64_t*) dest;
344    while( it != end )
345    {
346        *dst++ = *it++;
347        *dst++ = *it++;
348    }
349#else
350    uint32_t* it  = (uint32_t*) src;
351    uint32_t* end = (uint32_t*) srcEnd;
352    uint32_t* dst = (uint32_t*) dest;
353    while( it != end )
354    {
355        *dst++ = *it++;
356        *dst++ = *it++;
357        *dst++ = *it++;
358        *dst++ = *it++;
359    }
360#endif
361}
362
363
364static void copyReverseV( OValue* src, OValue* srcEnd, OValue* dest )
365{
366#if __WORDSIZE == 64
367    uint64_t* it  = (uint64_t*) src;
368    uint64_t* end = (uint64_t*) srcEnd;
369    uint64_t* dst = (uint64_t*) dest;
370    it  += 1;
371    dst += 1;
372    end += 1;
373    while( it != end )
374    {
375        *dst-- = *it--;
376        *dst-- = *it--;
377    }
378#else
379    uint32_t* it  = (uint32_t*) src;
380    uint32_t* end = (uint32_t*) srcEnd;
381    uint32_t* dst = (uint32_t*) dest;
382    it  += 3;
383    dst += 3;
384    end += 3;
385    while( it != end )
386    {
387        *dst-- = *it--;
388        *dst-- = *it--;
389        *dst-- = *it--;
390        *dst-- = *it--;
391    }
392#endif
393}
394
395
396static void copyReverseC( const char* src, const char* end, char* dest )
397{
398    while( src != end )
399        *dest-- = *src--;
400}
401
402
403/*
404   Inserts buf into a1.
405*/
406static void stringInsert( OValue* a1, const char* buf, int len )
407{
408    char* ipos;
409    OString* s1 = orSTRING(a1);
410    int used = s1->used;
411
412    if( len > 0 )
413    {
414        orArrayReserve( s1, sizeof(char), used + len );
415
416        // Must get ipos after orArrayReserve.
417        ipos = orStrChars( s1, a1 );
418
419        if( a1->series.it < used )
420        {
421            copyReverseC( s1->charArray + used - 1, ipos - 1,
422                          s1->charArray + used + len - 1 );
423        }
424
425        memCpy( ipos, buf, len );
426
427        s1->used += len;
428        a1->series.it += len;
429    }
430}
431
432
433extern void orListInsertValue( OBlock*, int nodeIndex, OValue* );
434
435
436#define REF_INS_PART    a1+2
437#define REF_INS_RANGE   a1+3
438#define REF_INS_ONLY    a1+4
439
440OR_NATIVE( orInsertNative )
441{
442    OValue* a2 = a1 + 1;
443
444    switch( orType(a1) )
445    {
446        case OT_BLOCK:
447        case OT_PAREN:
448        case OT_PATH:
449            if( (orType(a2) != OT_BLOCK) || orRefineSet(REF_INS_ONLY) )
450            {
451                OValue* ipos;
452                OBlock* s1 = orBLOCK(a1);
453                int used = s1->used;
454
455                orArrayReserve( s1, sizeof(OValue), used + 1 );
456
457                // Must get ipos after orArrayReserve.
458                ipos = s1->values + a1->series.it;
459
460                copyReverseV( s1->values + used - 1, ipos - 1,
461                              s1->values + used );
462                ++s1->used;
463                ++a1->series.it;
464                *ipos = *a2;
465            }
466            else
467            {
468                OValue* ipos;
469                OBlock* s1 = orBLOCK(a1);
470                OBlock* s2 = orBLOCK(a2);
471                int used = s1->used;
472                int srcLen = s2->used - a2->series.it;
473
474                orArrayReserve( s1, sizeof(OValue), used + srcLen );
475
476                // Must get ipos after orArrayReserve.
477                ipos = s1->values + a1->series.it;
478
479                if( a1->series.it < used )
480                {
481                    copyReverseV( s1->values + used - 1, ipos - 1,
482                                  s1->values + used + srcLen - 1 );
483                }
484
485                copyV( s2->values + a2->series.it,
486                       s2->values + s2->used,
487                       ipos );
488
489                s1->used += srcLen;
490                a1->series.it += srcLen;
491            }
492            break;
493
494        case OT_STRING:
495        case OT_ISSUE:
496        case OT_FILE:
497        case OT_TAG:
498        case OT_BINARY:
499        {
500            if( orIsBlock( orType(a2) ) )
501            {
502                OBlock* blk = orBLOCK(a2);
503                if( blk->used )
504                {
505                    OString* tmp;
506                    OValue* it  = blk->values + a2->series.it;
507                    OValue* end = blk->values + blk->used;
508
509                    assert( a2->series.it <= blk->used );
510
511                    orRefPush( OT_BLOCK, a2->index );
512                    tmp = orMakeString( 0 );
513                    orRefPop( 1 );
514
515                    while( it != end )
516                    {
517                        orForm( tmp, it );
518                        ++it;
519                    }
520
521                    stringInsert( a1, tmp->charArray, tmp->used );
522
523                    // Garbage collection will free the container later.
524                    orArrayFree( tmp );
525                }
526                else
527                {
528                    return;
529                }
530            }
531            else if( orIsString( orType(a2) ) )
532            {
533                OString* s2 = orSTRING(a2);
534                stringInsert( a1, s2->charArray + a2->series.it,
535                                  s2->used - a2->series.it );
536            }
537            else if( orIs(a2, OT_CHAR) )
538            {
539                char tmp = orInt(a2);
540                stringInsert( a1, &tmp, 1 );
541            }
542            else if( orIs(a1, OT_STRING) )
543            {
544                // Result is string so mold whatever we haven't handled.
545                orMold( orSTRING(a1), a2 );
546            }
547            else
548            {
549                goto badMatch;
550            }
551        }
552            break;
553
554        case OT_LIST:
555            if( a1->series.it )
556            {
557                OBlock* lst = orBLOCK( a1 );
558                OValue* node = lst->values + a1->series.it;
559
560                if( node->LIST_PREV < 0 )
561                    goto badList;
562
563                if( (a2->type != OT_BLOCK) || orRefineSet(REF_INS_ONLY) )
564                {
565                    orListInsertValue( lst, a1->series.it, a2 );
566                }
567                else
568                {
569                    OBlock* blk = orBLOCK( a2 );
570                    OValue* it  = blk->values + a2->series.it;
571                    OValue* end = blk->values + blk->used;
572
573                    while( it != end )
574                    {
575                        orListInsertValue( lst, a1->series.it, it );
576                        ++it;
577                    }
578                }
579            }
580            else
581            {
582                goto badList;
583            }
584            break;
585
586#ifdef OR_CONFIG_NUMBER_ARRAYS
587        //TODO
588#endif
589
590        default:
591            orError( "insert expected series argument" );
592            break;
593    }
594    return;
595
596badMatch:
597
598    orError( "insert types (%s, %s) do not match",
599             orDatatypeName(a1->type), orDatatypeName(a2->type) );
600    return;
601
602badList:
603
604    orError( LIST_REMOVED_ERROR );
605}
606
607
608#define REF_RM_PART    a1+1
609#define REF_RM_RANGE   a1+2
610
611OR_NATIVE( orRemoveNative )
612{
613    int len;
614
615    if( orRefineSet(REF_RM_PART) )
616        len = orInt(REF_RM_RANGE);
617    else
618        len = 1;
619
620    switch( a1->type )
621    {
622        case OT_BLOCK:
623        case OT_PAREN:
624        case OT_PATH:
625        {
626            OBlock* arr = orBLOCK(a1);
627            if( a1->series.it < arr->used )
628                orArrayErase( arr, sizeof(OValue), a1->series.it, len );
629        }
630            break;
631
632        case OT_STRING:
633        case OT_ISSUE:
634        case OT_FILE:
635        case OT_TAG:
636        case OT_BINARY:
637        {
638            OString* arr = orSTRING(a1);
639            if( a1->series.it < arr->used )
640                orArrayErase( arr, sizeof(char), a1->series.it, len );
641        }
642            break;
643
644#ifdef OR_CONFIG_NUMBER_ARRAYS
645        case OT_DEC_ARRAY:
646        {
647            OArray* arr = orDEC_ARRAY(a1);
648            if( a1->series.it < arr->used )
649                orArrayErase( arr, sizeof(double), a1->series.it, len );
650        }
651            break;
652
653        case OT_INT_ARRAY:
654        {
655            OArray* arr = orINT_ARRAY(a1);
656            if( a1->series.it < arr->used )
657                orArrayErase( arr, sizeof(int32_t), a1->series.it, len );
658        }
659            break;
660#endif
661
662        case OT_LIST:
663        {
664            OIndex  nextI;
665            OValue* it;
666            OBlock* blk = orBLOCK(a1);
667            OValue* node = blk->values + a1->series.it;
668
669            if( node->LIST_LINKED )
670            {
671                nextI = node->LIST_NEXT;
672
673                it = blk->values + node->LIST_PREV;
674                it->LIST_NEXT = node->LIST_NEXT;
675
676                it = blk->values + node->LIST_NEXT;
677                it->LIST_PREV = node->LIST_PREV;
678
679                node->LIST_LINKED = 0;
680                node->LIST_PREV = -1;
681                node->LIST_NEXT = -1;
682
683                node->LIST_FREE = blk->values->LIST_FREE;
684                blk->values->LIST_FREE = a1->series.it;
685
686                /*
687                ++node;
688                orSetTF( node, OT_UNSET );
689                */
690
691                // NOTE: If this is the last node in the block we can
692                // optimize GC by moving blk->used down until a used node
693                // is found.
694
695                // Result.
696                a1->series.it = nextI;
697            }
698            else
699            {
700                orError( LIST_REMOVED_ERROR );
701            }
702        }
703            break;
704
705        case OT_NONE:
706            break;
707
708        default:
709            orError( "remove expected series argument" );
710    }
711}
712
713
714/**
715  n is zero based.
716  Sets result to none and returns zero if index is invalid.
717*/
718int orPick( const OValue* ser, int n, OValue* result )
719{
720    switch( ser->type )
721    {
722        case OT_BLOCK:
723        case OT_PAREN:
724        case OT_PATH:
725        {
726            OBlock* blk = orBLOCK( ser );
727            n += ser->series.it;
728            if( (n > -1) && (n < blk->used) )
729            {
730                orCopyV( result, blk->values[ n ] );
731                return 1;
732            }
733        }
734            break;
735
736        case OT_STRING:
737        case OT_ISSUE:
738        case OT_FILE:
739        case OT_TAG:
740        {
741            OString* str = orSTRING( ser );
742            n += ser->series.it;
743            if( (n > -1) && (n < str->used) )
744            {
745                orSetTF( result, OT_CHAR );
746                orInt(result) = str->charArray[ n ];
747                return 1;
748            }
749        }
750            break;
751
752        case OT_BINARY:
753        {
754            OBinary* str = orSTRING( ser );
755            n += ser->series.it;
756            if( (n > -1) && (n < str->used) )
757            {
758                orSetTF( result, OT_INTEGER );
759                orInt(result) = str->byteArray[ n ];
760                return 1;
761            }
762        }
763            break;
764
765        case OT_PAIR:
766            if( (n > -1) && (n < 2) )
767            {
768                orSetTF( result, OT_INTEGER );
769                orInt(result) = ser->pair[ n ];
770                return 1;
771            }
772            break;
773
774        case OT_TUPLE:
775            if( (n > -1) && (n < ser->argc) )
776            {
777                orSetTF( result, OT_INTEGER );
778                orInt(result) = ser->tuple[ n ];
779                return 1;
780            }
781            break;
782
783        case OT_LIST:
784            if( ser->series.it )
785            {
786                OBlock* blk = orBLOCK( ser );
787                OValue* it = blk->values + ser->series.it;
788
789                while( it->LIST_NEXT > 0 )
790                {
791                    if( n == 0 )
792                    {
793                        orCopyV( result, it[1] );
794                        return 1;
795                    }
796                    --n;
797                    orListNextNode( blk, it );
798                }
799            }
800            break;
801
802#ifdef OR_CONFIG_MATH3D
803        case OT_VEC2:
804        case OT_VEC3:
805            if( (n > -1) && (n < 3) )
806            {
807                const float* fp = &ser->vec3.x;
808                orSetTF( result, OT_DECIMAL );
809                orDecimal(result) = (double) fp[ n ];
810                return 1;
811            }
812            break;
813
814        case OT_MATRIX:
815            if( (n > -1) && (n < 16) )
816            {
817                OArray* arr = orSTRING( ser );
818                orSetTF( result, OT_DECIMAL );
819                orDecimal(result) = (double) arr->floats[ n ];
820                return 1;
821            }
822            break;
823#endif
824
825#ifdef OR_CONFIG_NUMBER_ARRAYS
826        case OT_DEC_ARRAY:
827        {
828            OArray* arr = orDEC_ARRAY( ser );
829            n += ser->series.it;
830            if( (n > -1) && (n < arr->used) )
831            {
832                orSetTF( result, OT_DECIMAL );
833                orDecimal(result) = arr->decimals[ n ];
834                return 1;
835            }
836        }
837            break;
838
839        case OT_INT_ARRAY:
840        {
841            OArray* arr = orINT_ARRAY( ser );
842            n += ser->series.it;
843            if( (n > -1) && (n < arr->used) )
844            {
845                orSetTF( result, OT_INTEGER );
846                orInt(result) = arr->integers[ n ];
847                return 1;
848            }
849        }
850            break;
851#endif
852    }
853    orSetTF( result, OT_NONE );
854    return 0;
855}
856
857
858OR_NATIVE( orFirstNative )
859{
860    if( a1->type == OT_OBJECT )
861    {
862        // NOTE: REBOL does not bind these words.
863        OBlock* blk = orCopyBlock( a1->ctx.wblkN, 0, 0 );
864        orResultBLOCK( orBlockN(blk) );
865    }
866    else
867    {
868        orPick( a1, 0, a1 );
869    }
870}
871
872
873OR_NATIVE( orSecondNative )
874{
875    orPick( a1, 1, a1 );
876}
877
878
879OR_NATIVE( orThirdNative )
880{
881    orPick( a1, 2, a1 );
882}
883
884
885OR_NATIVE( orLastNative )
886{
887    OValue* result = a1;
888
889    switch( a1->type )
890    {
891        case OT_BLOCK:
892        case OT_PAREN:
893        case OT_PATH:
894        {
895            OBlock* blk = orBLOCK(a1);
896            if( (blk->used - a1->series.it) < 1 )
897                break;
898            orCopyV( result, blk->values[ blk->used - 1 ] );
899        }
900            return;
901
902        case OT_STRING:
903        case OT_ISSUE:
904        case OT_FILE:
905        case OT_TAG:
906        case OT_BINARY:
907        {
908            OString* str = orSTRING(a1);
909            if( (str->used - a1->series.it) < 1 )
910                break;
911            orSetTF( result, OT_CHAR );
912            orInt(result) = str->charArray[ str->used - 1 ];
913        }
914            return;
915
916        case OT_TUPLE:
917            orResult( OT_INTEGER, a1->tuple[ a1->argc ] );
918            return;
919
920        /*
921        case OT_BITSET:
922            break;
923        */
924
925        case OT_LIST:
926        {
927            OBlock* blk = orBLOCK(a1);
928            OValue* node = blk->values + LIST_TAIL;
929            if( node->LIST_PREV != LIST_HEAD )
930            {
931                orCopyV( result, blk->values[ node->LIST_PREV + 1 ] );
932                return;
933            }
934        }
935            break;
936
937#ifdef OR_CONFIG_NUMBER_ARRAYS
938        case OT_DEC_ARRAY:
939        {
940            OArray* arr = orDEC_ARRAY(a1);
941            if( (arr->used - a1->series.it) < 1 )
942                break;
943            orSetTF( result, OT_DECIMAL );
944            orDecimal(result) = arr->decimals[ arr->used - 1 ];
945        }
946            return;
947
948        case OT_INT_ARRAY:
949        {
950            OArray* arr = orINT_ARRAY(a1);
951            if( (arr->used - a1->series.it) < 1 )
952                break;
953            orSetTF( result, OT_INTEGER );
954            orInt(result) = arr->integers[ arr->used - 1 ];
955        }
956            return;
957#endif
958    }
959    orError( "last series is empty" );
960}
961
962
963static void reverseV( OValue* it, OValue* end )
964{
965    OValue tmp;
966    while( it < end )
967    {
968        tmp = *it;
969        --end;
970        *it++ = *end;
971        *end = tmp;
972    }
973}
974
975
976static void reverseC( char* it, char* end )
977{
978    int tmp;
979    while( it < end )
980    {
981        tmp = *it;
982        --end;
983        *it++ = *end;
984        *end = tmp;
985    }
986}
987
988
989#define REF_REV_PART   a1+1
990#define REF_REV_RANGE  a1+2
991
992static int validRange( OValue* a1, int used )
993{
994    int range;
995
996    if( orRefineSet( REF_REV_PART ) )
997    {
998        OValue* rval = REF_REV_RANGE;
999        if( rval->type == OT_INTEGER )
1000            range = orInt(rval);
1001        else
1002            range = rval->series.it;
1003
1004        if( range > used )
1005            return used;
1006    }
1007    else
1008    {
1009        range = used;
1010    }
1011
1012    if( (range < 1) || (range < a1->series.it) )
1013    {
1014        orError( "Invalid range %d", range );
1015        return 0;
1016    }
1017    return range;
1018}
1019
1020
1021OR_NATIVE( orReverseNative )
1022{
1023    switch( a1->type )
1024    {
1025        case OT_BLOCK:
1026        case OT_PAREN:
1027        case OT_PATH:
1028        {
1029            int range;
1030            OBlock* blk = orBLOCK( a1 );
1031            range = validRange( a1, blk->used );
1032            if( range )
1033            {
1034                reverseV( blk->values + a1->series.it,
1035                          blk->values + range );
1036                a1->series.it = range;
1037            }
1038        }
1039            break;
1040
1041        case OT_STRING:
1042        case OT_ISSUE:
1043        case OT_FILE:
1044        case OT_TAG:
1045        case OT_BINARY:
1046        {
1047            int range;
1048            OString* str = orSTRING( a1 );
1049            range = validRange( a1, str->used );
1050            if( range )
1051            {
1052                reverseC( str->charArray + a1->series.it,
1053                          str->charArray + range );
1054                a1->series.it = range;
1055            }
1056        }
1057            break;
1058
1059        case OT_PAIR:
1060        {
1061            int tmp = a1->pair[0];
1062            a1->pair[0] = a1->pair[1];
1063            a1->pair[1] = tmp;
1064        }
1065            break;
1066
1067        case OT_TUPLE:
1068            reverseC( (char*) a1->tuple, (char*) a1->tuple + a1->argc );
1069            break;
1070    }
1071}
1072
1073
1074OR_NATIVE( orSkipNative )
1075{
1076    int n;
1077    OValue* a2 = a1 + 1;
1078    int len = orSeriesUsed( a1 );
1079    if( len > -1 )
1080    {
1081        if( a2->type == OT_INTEGER )
1082            n = orInt(a2);
1083        else if( a2->type == OT_DECIMAL )
1084            n = (int) orDecimal(a2);
1085        else    // OT_LOGIC
1086            n = orInt(a2) ? 0 : 1;
1087
1088        if( n )
1089        {
1090            n += a1->series.it;
1091            if( n < 0 )
1092                n = 0;
1093            else if( n > len )
1094                n = len;
1095            a1->series.it = n;
1096        }
1097        return;
1098    }
1099    orError( "skip expected series argument" );
1100}
1101
1102
1103OR_NATIVE( orAtNative )
1104{
1105    int n;
1106    int used;
1107    OValue* a2 = a1 + 1;
1108
1109    if( a2->type == OT_LOGIC )
1110    {
1111        n = orInt(a2) ? 0 : 1;
1112    }