root/trunk/orca/print.c

Revision 149, 28.3 kB (checked in by krobillard, 2 years ago)

Removed stack manipulation from 'form & 'mold which is no longer needed.

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 <time.h>
22 #include "os.h"
23 #include "ovalue.h"
24 #include "internal.h"
25
26
27 #define MOLD_NO_BRACES      1
28
29
30 static void form( OString* out, const OValue* val, int depth );
31 static void mold( OString* out, const OValue* val, int depth, int flags );
32
33
34
35 static char charStr[] = "#\"?\"";
36
37
38 static void append( OString* str, const char* cp, int len )
39 {
40     if( (str->used + len) > str->avail )
41         orArrayReserve( str, 1, str->used + len );
42     memCpy( str->charArray + str->used, cp, len );
43     str->used += len;
44 }
45
46
47 static void appendC( OString* str, const char* cp )
48 {
49     int len;
50     const char* it = cp;
51     while( *it != '\0' )
52         ++it;
53     len = it - cp;
54     orArrayReserve( str, 1, str->used + len );
55     memCpy( str->charArray + str->used, cp, len );
56     str->used += len;
57 }
58
59
60 static void append1( int c, OString* str )
61 {
62     orArrayReserve( str, 1, str->used + 1 );
63     str->charArray[ str->used ] = c;
64     ++str->used;
65 }
66
67
68 static void indent( OString* str, int depth )
69 {
70     while( depth > 0 )
71     {
72         append(str,"    ",4);
73         --depth;
74     }
75 }
76
77
78 static void appendInteger( OString* out, int32_t n )
79 {
80     char* cp;
81     orArrayReserve( out, 1, out->used + 16 );
82     cp = out->charArray + out->used;
83     strPrint( cp, "%d", n );
84     while( *cp != '\0' )
85         ++cp;
86     out->used = cp - out->charArray;
87 }
88
89
90 #ifdef OR_CONFIG_HEX_TOKEN
91 static void appendHex( OString* out, int32_t n )
92 {
93     char* cp;
94     orArrayReserve( out, 1, out->used + 16 );
95     cp = out->charArray + out->used;
96     strPrint( cp, "$%x", n );
97     while( *cp != '\0' )
98         ++cp;
99     out->used = cp - out->charArray;
100 }
101 #endif
102
103
104 static void appendDecimal( OString* out, double n )
105 {
106     char* cp;
107     orArrayReserve( out, 1, out->used + 16 );
108     cp = out->charArray + out->used;
109     strPrint( cp, "%g", n );
110     while( *cp != '\0' )
111         ++cp;
112     out->used = cp - out->charArray;
113 }
114
115
116 static void appendNibble( OString* str, int n )
117 {
118     n &= 0x0f;
119     if( n < 10 )
120         n += '0';
121     else
122         n += 'A' - 10;
123     str->charArray[ str->used ] = n;
124     ++str->used;
125 }
126
127
128 static void moldBinary( OString* out, const OValue* val )
129 {
130     const uint8_t* bp;
131     const uint8_t* end;
132     OString* bin = orSTRING( val );
133
134     append(out, "#{", 2);
135
136     bp  = bin->byteArray + val->series.it;
137     end = bin->byteArray + bin->used;
138
139     orArrayReserve( out, 1, bin->used + ((end - bp) * 2) );
140
141     while( bp != end )
142     {
143         appendNibble( out, *bp >> 4 );
144         appendNibble( out, *bp );
145         ++bp;
146     }
147
148     append1('}', out);
149 }
150
151
152 static void moldTuple( OString* out, const OValue* val )
153 {
154     char* cp;
155     const uint8_t* end;
156     const uint8_t* bp = val->tuple;
157
158     assert( val->argc >= 3 );
159
160     orArrayReserve( out, 1, out->used + (4 * val->argc) );
161
162     cp = out->charArray + out->used;
163     strPrint( cp, "%d.%d.%d", bp[0], bp[1], bp[2] );
164     while( *cp != '\0' )
165         ++cp;
166
167     end = bp + val->argc;
168     bp += 3;
169     while( bp != end )
170     {
171         strPrint( cp, ".%d", *bp++ );
172         while( *cp != '\0' )
173             ++cp;
174     }
175
176     out->used = cp - out->charArray;
177 }
178
179
180 static const char* _monthAbr[12] =
181 {
182     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
183     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
184 };
185
186
187 static char* append02d( char* cp, int n )
188 {
189     *cp++ = '0' + (n / 10);
190     *cp++ = '0' + (n % 10);
191     return cp;
192 }
193
194
195 static void moldDate( OString* out, const OValue* val )
196 {
197     struct tm* st;
198     time_t tt;
199     char* cp;
200     const char* month;
201     int year;
202     int yc;
203
204     tt = (time_t) orSeconds(val);
205     st = localtime( &tt );
206
207     orArrayReserve( out, 1, out->used + 22 );
208     cp = out->charArray + out->used;
209
210     cp = append02d( cp, st->tm_mday );
211     *cp++ = '-';
212
213     month = _monthAbr[ st->tm_mon ];
214     *cp++ = *month++;
215     *cp++ = *month++;
216     *cp++ = *month++;
217     *cp++ = '-';
218
219     year = st->tm_year + 1900;
220     yc = year / 1000;
221     *cp++ = '0' + yc;
222     year -= yc * 1000;
223     yc = year / 100;
224     *cp++ = '0' + yc;
225     year -= yc * 100;
226     *cp++ = '0' + year / 10;
227     *cp++ = '0' + (year % 10);
228
229     if( st->tm_hour || st->tm_min || st->tm_sec )
230     {
231         *cp++ = '/';
232         cp = append02d( cp, st->tm_hour );
233         *cp++ = ':';
234         cp = append02d( cp, st->tm_min );
235         *cp++ = ':';
236         cp = append02d( cp, st->tm_sec );
237     }
238
239     out->used = cp - out->charArray;
240 }
241
242
243 static void moldTime( OString* out, const OValue* val )
244 {
245     char* cp;
246
247     orArrayReserve( out, 1, out->used + 32 );
248
249     cp = out->charArray + out->used;
250     strPrint( cp, "%f", orSeconds(val) );
251     while( *cp != '\0' )
252         ++cp;
253     out->used = cp - out->charArray;
254 }
255
256
257 static void formList( OString* out, const OValue* val )
258 {
259     if( val->series.it )
260     {
261         OBlock* blk = orBLOCK(val);
262         OValue* it = blk->values + val->series.it;
263         int first = 1;
264
265         while( it->LIST_NEXT > 0 )
266         {
267             if( first )
268                 first = 0;
269             else
270                 append1( ' ', out );
271             mold( out, it + 1, 0, 0 );
272
273             orListNextNode( blk, it );
274         }
275     }
276 }
277
278
279 #if defined(OR_CONFIG_MATH3D) || defined(OR_CONFIG_NUMBER_ARRAYS)
280 static void termBlock( OString* out )
281 {
282     char* cp = out->charArray + out->used - 1;
283     if( *cp == ' ' )
284         *cp = ']';
285     else
286         append1( ']', out );
287 }
288 #endif
289
290
291 #ifdef OR_CONFIG_MATH3D
292 static void moldVec3( OString* out, const OValue* val )
293 {
294     const float* it  = &val->vec3.x;
295     const float* end;
296
297     if( val->type == OT_VEC2 )
298     {
299         end = it + 2;
300         append(out, "make vec2! [", 12);
301     }
302     else
303     {
304         end = it + 3;
305         append(out, "make vec3! [", 12);
306     }
307
308     while( it != end )
309     {
310         appendDecimal( out, *it );
311         append1( ' ', out );
312         ++it;
313     }
314     termBlock( out );
315 }
316
317
318 static void moldMatrix( OString* out, const OValue* val )
319 {
320     OString* arr = orSTRING(val);
321     float* it  = arr->floats;
322     float* end = it + 16;
323
324     append(out, "make matrix! [", 14);
325     while( it != end )
326     {
327         appendDecimal( out, *it );
328         append1( ' ', out );
329         ++it;
330     }
331     termBlock( out );
332 }
333 #endif
334
335
336 #ifdef OR_CONFIG_NUMBER_ARRAYS
337 static void moldDecArray( OString* out, OValue* val )
338 {
339     OArray* arr = orDEC_ARRAY( val );
340     int si = val->series.it;
341     int used = arr->used - si;
342     if( used > 0 )
343     {
344         double* it  = arr->decimals + si;
345         double* end = it + used;
346
347         append( out, "#[", 2 );
348         while( it != end )
349         {
350             appendDecimal( out, *it );
351             append1( ' ', out );
352             ++it;
353         }
354         termBlock( out );
355     }
356     else
357     {
358         append( out, "#[]", 3 );
359     }
360 }
361
362
363 static void moldIntArray( OString* out, OValue* val )
364 {
365     OArray* arr = orINT_ARRAY( val );
366     int si = val->series.it;
367     int used = arr->used - si;
368     if( used > 0 )
369     {
370         int32_t* it  = arr->integers + si;
371         int32_t* end = it + used;
372
373         append( out, "i#[", 3 );
374         while( it != end )
375         {
376             appendInteger( out, *it );
377             append1( ' ', out );
378             ++it;
379         }
380         termBlock( out );
381     }
382     else
383     {
384         append( out, "i#[]", 4 );
385     }
386 }
387 #endif
388
389
390 static void formObject( OString* out, const OContext* ctx, int depth )
391 {
392     OBlock* wblk;
393     OBlock* vblk;
394     OValue* wval;
395     OValue* it;
396     OValue* end;
397
398     wblk = orBlockPtr( ctx->wblkN );
399     vblk = orBlockPtr( ctx->vblkN );
400
401     wval = wblk->values;
402     it  = vblk->values;
403     end = it + vblk->used;
404
405     // Skip self.
406     if( it->type == OT_OBJECT && (it->ctx.vblkN == ctx->vblkN) )
407     {
408         ++wval;
409         ++it;
410     }
411
412     while( it != end )
413     {
414         indent( out, depth );
415
416         orAtomStr( orAtom(wval), out );
417         append( out, ": ", 2 );
418
419         // Mold gives us quotes around empty strings.
420         // Need to check correct behavior of nested objects.
421         mold( out, it, depth, 0 );
422
423         append1( '\n', out );
424
425         ++wval;
426         ++it;
427     }
428 }
429
430
431 static void writeErrorPosition( OString* out, const OValue* val )
432 {
433     OValue* it;
434     OValue* end;
435     OBlock* blk;
436
437     if( val->error.block )
438     {
439         append( out, "\n** Near:", 9 );
440
441         blk = orBlockPtr( val->error.block );
442
443         assert( blk->values );
444         it  = blk->values + val->error.nearVal;
445         end = blk->values + blk->used;
446
447         if( it != end )
448         {
449             while( 1 )
450             {
451                 append1( ' ', out );
452                 mold( out, it, 0, 0 );
453                 ++it;
454                 if( it == end )
455                     break;
456                 if( it->flags & OR_FLAG_EOL )
457                     break;
458             }
459         }
460     }
461 }
462
463
464 static char* errorText[] =
465 {
466     "Syntax",
467     "Script",
468     "Math",
469     "Access",
470     "Internal"
471 };
472
473
474 static void formError( OString* out, const OValue* val )
475 {
476     switch( orErrorType(val) )
477     {
478         case OR_ERROR_SYNTAX:
479         case OR_ERROR_MATH:
480         case OR_ERROR_SCRIPT:
481         case OR_ERROR_ACCESS:
482         case OR_ERROR_INTERNAL:
483         {
484             OString* str = orSTRINGS + val->error.msg;
485
486             append( out, "** ", 3 );
487             appendC( out, errorText[ orErrorType(val) ] );
488             append( out, " Error: ", 8 );
489             append( out, str->charArray, str->used );
490
491             writeErrorPosition( out, val );
492         }
493             break;
494
495         case OR_ERROR_BREAK:
496             appendC( out, "** Throw Error: Break" );
497             break;
498
499         case OR_ERROR_THROW:
500         {
501             appendC( out, "** Throw Error: No catch for throw: " );
502             // NOTE: Using val+1 assumes val is only from orEnv->error.
503             form( out, val + 1, 0 );
504
505             writeErrorPosition( out, val );
506         }
507             break;
508
509         case OR_ERROR_HALT:
510             appendC( out, "** Throw Error: Halt" );
511             break;
512
513         default:
514             appendC( out, "** Throw Error: Unknown type " );
515             append1( '0' + (orErrorType(val) & 15), out );
516             break;
517     }
518 }
519
520
521 static void form( OString* out, const OValue* val, int depth )
522 {
523     /*
524     if( val->flags & OR_FLAG_EOL )
525     {
526         int d;
527         append1('\n', out);
528         for( d = 0; d < depth; ++d )
529             append1( '\t', out );
530     }
531     */
532
533     switch( val->type )
534     {
535         case OT_NONE:       append(out, "none", 4); break;
536
537         case OT_DATATYPE:   appendC(out, orDatatypeName( val->index ));
538                             break;
539
540         case OT_REFINEMENT: orAtomStr( val->index, out );
541                             break;
542
543         case OT_WORD:
544         case OT_LITWORD:
545         case OT_SETWORD:    orAtomStr( orAtom(val), out );
546                             break;
547
548         case OT_STRING:
549         case OT_ISSUE:
550         case OT_FILE:       {
551                             OString* str = orSTRING( val );
552                             int n = val->series.it;
553                             int used = str->used - n;
554                             if( used > 0 )
555                                 append( out, str->charArray + n, used );
556                             }
557                             break;
558
559         case OT_TAG:        {
560                             OString* str = orSTRING( val );
561                             append1('<', out);
562                             append(out, str->charArray, str->used);
563                             append1('>', out);
564                             }
565                             break;
566
567         case OT_BITSET:     append(out, "make bitset! ", 13);
568                             // Fall through to binary.
569
570         case OT_BINARY:     moldBinary( out, val );
571                             break;
572
573         case OT_CHAR:       append1( orInt(val), out );
574                             break;
575
576         case OT_INTEGER:
577 #ifdef OR_CONFIG_HEX_TOKEN
578             if( val->flags & OR_FLAG_HEX )
579                 appendHex( out, orInt(val) );
580             else
581 #endif
582             appendInteger( out, orInt(val) );
583             break;
584
585         case OT_DECIMAL:    appendDecimal( out, orDecimal(val) );
586                             break;
587
588         case OT_TUPLE:      moldTuple( out, val );
589                             break;
590
591         case OT_DATE:       moldDate( out, val );
592                             break;
593
594         case OT_TIME:       moldTime( out, val );
595                             break;
596
597         case OT_PAIR:       {
598                             char* cp;
599                             orArrayReserve( out, 1, out->used + 32 );
600                             cp = out->charArray + out->used;
601                             strPrint( cp, "%dx%d", val->pair[0], val->pair[1]);
602                             while( *cp != '\0' )
603                                 ++cp;
604                             out->used = cp - out->charArray;
605                             }
606                             break;
607
608         case OT_LOGIC:      if( orInt(val) )
609                                 append( out, "true", 4 );
610                             else
611                                 append( out, "false", 5 );
612                             break;
613
614         case OT_UNSET:      append(out, "unset", 5); break;
615
616         case OT_PATH:
617         case OT_SETPATH:
618         case OT_LITPATH:
619         {
620             OBlock* path = orBlockPtr( val->index );
621             OValue* vp  = path->values;
622             OValue* end = vp + path->used;
623             for( ; vp != end; ++vp )
624             {
625                 if( vp != path->values )
626                     append1( '/', out );
627                 form( out, vp, 0 );
628             }
629         }
630             break;
631
632         case OT_PAREN:
633         case OT_BLOCK:
634         {
635             OBlock* blk = orBlockPtr( val->index );
636             OValue* vp  = blk->values + val->series.it;
637             OValue* end = blk->values + blk->used;
638
639             if( vp != end )
640             {
641                 while( 1 )
642                 {
643                     form( out, vp, depth + 1 );
644                     ++vp;
645                     if( vp == end )
646                         break;
647                     append1( ' ', out );
648                 }
649             }
650         }
651             break;
652
653         case OT_OBJECT:
654         case OT_PORT:
655             formObject( out, &val->ctx, depth );
656             //append( out, "?object?", 8 );
657             break;
658
659         case OT_LIST:
660             formList( out, val );
661             break;
662
663         case OT_ERROR:
664             formError( out, val );
665             break;
666
667         default:
668             append1( '?', out );
669             appendC( out, orDatatypeName( val->type ) );
670             append1( '?', out );
671             break;
672     }
673 }
674
675
676 void orForm( OString* out, const OValue* val )
677 {
678     form( out, val, 0 );
679     if( out->used )
680     {
681         orTermCStr( out );
682     }
683 }
684
685
686 static void mold( OString* out, const OValue* val, int depth, int mflags )
687 {
688     /*
689     if( val->flags & OR_FLAG_EOL )
690     {
691         int d;
692         append1('\n', out);
693         for( d = 0; d < depth; ++d )
694             append1( '\t', out );
695     }
696     */
697
698     switch( val->type )
699     {
700         case OT_NONE:       append(out, "none", 4); break;
701
702         case OT_DATATYPE:   appendC(out, orDatatypeName( val->index ));
703                             append1('!', out);
704                             break;
705
706         case OT_REFINEMENT: append1('/', out);
707                             orAtomStr( val->index, out );
708                             break;
709
710         case OT_LITWORD:    append1('\'', out);
711                             // fall through to OT_WORD
712
713         case OT_WORD:       orAtomStr( orAtom(val), out );
714                             break;
715
716         case OT_SETWORD:    orAtomStr( orAtom(val), out );
717                             append1(':', out);
718                             break;
719
720         case OT_GETWORD:    append1(':', out);
721                             orAtomStr( orAtom(val), out );
722                             break;
723
724         case OT_ERROR:      {
725                             OString* str = orSTRING( val );
726                             append(out, str->charArray, str->used);
727                             append1('\n', out);
728                             }
729                             break;
730
731         case OT_TAG:        {
732                             OString* str = orSTRING( val );
733                             append1('<', out);
734                             append(out, str->charArray, str->used);
735                             append1('>', out);
736                             }
737                             break;
738
739         case OT_STRING:
740         {
741             OString* str = orSTRING( val );
742             int si = val->series.it;
743             int used = str->used - si;
744             if( used > 0 )
745             {
746                 int newlines = 0;
747                 int quote = '{';
748                 if( used < 51 )
749                 {
750                     char* ci  = str->charArray + si;
751                     char* end = ci + used;
752                     while( ci != end )
753                     {
754                         if( *ci == '"' )
755                             break;
756                         if( *ci == '\n' )
757                         {
758                             if( newlines == 3 )
759                                 break;
760                             ++newlines;
761                         }
762                         ++ci;
763                     }
764                     if( ci == end )
765                         quote = '"';
766                 }
767
768                 append1( quote, out );
769 #if 0
770                 append( out, str->charArray + si, used );
771 #else
772                 {
773                     const char* put;
774                     const char* cp  = str->charArray + si;
775                     const char* end = cp + used;
776
777 #define PUT     if(cp != put) {append(out,put,cp - put);} put = cp + 1;
778
779                     put = cp;
780                     while( cp != end )
781                     {
782                         if( *cp == '^' )
783                         {
784                             PUT
785                             append( out, "^^", 2 );
786                         }
787                         else if( *cp == '}' )
788                         {
789                             PUT
790                             if( quote == '"' )
791                                 append1( '}', out );
792                             else
793                                 append( out, "^}", 2 );
794                         }
795                         else if( *cp == '\n' )
796                         {
797                             PUT
798                             if( quote == '"' )
799                                 append( out, "^/", 2 );
800                             else
801                                 append1( '\n', out );
802                         }
803                         else if( *cp == '\t' )
804                         {
805                             PUT
806                             append( out, "^-", 2 );
807                         }
808                         else if( *cp == '\0' )
809                         {
810                             PUT
811                             append( out, "^@", 2 );
812                         }
813                         ++cp;
814                     }
815                     if( cp != put )
816                         append( out, put, cp - put );
817                 }
818 #endif
819                 if( quote == '{' )
820                     quote = '}';
821                 append1( quote, out );
822             }
823             else
824             {
825                 append( out, "\"\"", 2 );
826             }
827         }
828             break;
829
830         case OT_ISSUE:      {
831                             OString* str = orSTRING( val );
832                             append1('#', out);
833                             append(out, str->charArray, str->used);
834                             }
835                             break;
836
837         case OT_FILE:       {
838                             OString* str = orSTRING( val );
839                             append1('%', out);
840                             append(out, str->charArray, str->used);
841                             }
842                             break;
843
844         case OT_BITSET:     append(out, "make bitset! ", 13);
845                             // Fall through to binary.
846
847         case OT_BINARY:
848             moldBinary( out, val );
849             break;
850
851         case OT_CHAR:
852             switch( orInt(val) )
853             {
854                 case '^':
855                     append( out, "#\"^^\"", 5 );
856                     break;
857
858                 case '\n':
859                     append( out, "#\"^/\"", 5 );
860                     break;
861
862                 case '\t':
863                     append( out, "#\"^-\"", 5 );
864                     break;
865
866                 case '\0':
867                     append( out, "#\"^@\"", 5 );
868                     break;
869
870                 default:
871                     charStr[2] = (char) orInt(val);
872                     append(out, charStr, 4);
873                     break;
874             }
875             break;
876
877         case OT_INTEGER:
878 #ifdef OR_CONFIG_HEX_TOKEN
879             if( val->flags & OR_FLAG_HEX )
880                 appendHex( out, orInt(val) );
881             else
882 #endif
883             appendInteger( out, orInt(val) );
884             break;
885
886         case OT_DECIMAL:    appendDecimal( out, orDecimal(val) );
887                             break;
888
889         case OT_TUPLE:      moldTuple( out, val );
890                             break;
891
892         case OT_DATE:       moldDate( out, val );
893                             break;
894
895         case OT_TIME:       moldTime( out, val );
896                             break;
897
898         case OT_PAIR:       {
899                             char* cp;
900                             orArrayReserve( out, 1, out->used + 32 );
901                             cp = out->charArray + out->used;
902                             strPrint( cp, "%dx%d", val->pair[0], val->pair[1]);
903                             while( *cp != '\0' )
904                                 ++cp;
905                             out->used = cp - out->charArray;
906                             }
907                             break;
908
909         case OT_LOGIC:      if( orInt(val) )
910                                 append( out, "true", 4 );
911                             else
912                                 append( out, "false", 5 );
913                             break;
914
915         case OT_UNSET:      append(out, "unset", 5); break;
916
917         case OT_LITPATH:    append1( '!', out );
918                             // Fall through to path.
919         case