1 /*  sexp.c -- standalone sexp library implementation          */
2 /*  Copyright (c) 2009-2015 Alex Shinn.  All rights reserved. */
3 /*  BSD-style license: http://synthcode.com/license.txt       */
4 
5 #include "chibi/sexp.h"
6 
7 /* optional huffman-compressed immediate symbols */
8 struct sexp_huff_entry {
9   unsigned char len;
10   unsigned short bits;
11 };
12 
13 #if SEXP_USE_HUFF_SYMS
14 #include "chibi/sexp-hufftabs.h"
15 #include "chibi/sexp-huff.h"
16 #endif
17 
18 #ifdef _WIN32
19 #include <io.h>
20 #endif
21 
22 static int sexp_initialized_p = 0;
23 
24 static const char sexp_separators[] = {
25   /* 1  2  3  4  5  6  7  8  9  a  b  c  d  e  f         */
26   0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, /* x0_ */
27   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* x1_ */
28   1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, /* x2_ */
29   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* x3_ */
30   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* x4_ */
31   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, /* x5_ */
32   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* x6_ */
33   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, /* x7_ */
34 };
35 
digit_value(int c)36 static int digit_value (int c) {
37   return (((c)<='9') ? ((c) - '0') : ((sexp_tolower(c) - 'a') + 10));
38 }
39 
hex_digit(int n)40 static int hex_digit (int n) {
41   return ((n<=9) ? ('0' + n) : ('a' + n - 10));
42 }
43 
is_precision_indicator(int c)44 static int is_precision_indicator(int c) {
45   return c=='d' || c=='D' || c=='e' || c=='E' || c=='f' || c=='F'
46     || c=='l' || c=='L' || c=='s' || c=='S';
47 }
48 
sexp_is_separator(int c)49 int sexp_is_separator(int c) {
50   return 0<c && c<0x80 && sexp_separators[c];
51 }
52 
53 #if SEXP_USE_GLOBAL_SYMBOLS
54 sexp sexp_symbol_table[SEXP_SYMBOL_TABLE_SIZE];
55 #endif
56 
57 #if ! SEXP_USE_UNSAFE_PUSH
sexp_push_op(sexp ctx,sexp * loc,sexp x)58 sexp sexp_push_op(sexp ctx, sexp* loc, sexp x) {
59   sexp tmp = sexp_cons(ctx, x, *loc);
60   if (sexp_exceptionp(tmp)) return *loc;
61   *loc = tmp;
62   return tmp;
63 }
64 #endif
65 
sexp_alloc_tagged_aux(sexp ctx,size_t size,sexp_uint_t tag sexp_current_source_param)66 sexp sexp_alloc_tagged_aux(sexp ctx, size_t size, sexp_uint_t tag sexp_current_source_param) {
67 #if SEXP_USE_TRACK_ALLOC_BACKTRACE
68   int i;
69   void* trace[SEXP_BACKTRACE_SIZE + 1];
70 #endif
71   sexp res = (sexp) sexp_alloc(ctx, size);
72   if (res && ! sexp_exceptionp(res)) {
73     sexp_pointer_tag(res) = tag;
74 #if SEXP_USE_TRACK_ALLOC_SOURCE
75     sexp_pointer_source(res) = source;
76 #if SEXP_USE_TRACK_ALLOC_BACKTRACE
77     backtrace(trace, SEXP_BACKTRACE_SIZE + 1);
78     for (i=0; i<SEXP_BACKTRACE_SIZE; i++) res->backtrace[i] = trace[i+1];
79 #endif
80 #endif
81 #if SEXP_USE_HEADER_MAGIC
82     sexp_pointer_magic(res) = SEXP_POINTER_MAGIC;
83 #endif
84   }
85   return res;
86 }
87 
88 #if SEXP_USE_OBJECT_BRACE_LITERALS
sexp_write_simple_object(sexp ctx,sexp self,sexp_sint_t n,sexp obj,sexp writer,sexp out)89 sexp sexp_write_simple_object (sexp ctx, sexp self, sexp_sint_t n, sexp obj, sexp writer, sexp out) {
90   sexp t, x;
91   sexp_gc_var1(args);
92   sexp_sint_t i, len, nulls=0;
93   i = sexp_pointer_tag(obj);
94   sexp_write_char(ctx, '{', out);
95   if (i >= sexp_context_num_types(ctx)) {
96     sexp_write_string(ctx, "invalid", out);
97   } else {
98     sexp_gc_preserve1(ctx, args);
99     t = sexp_object_type(ctx, obj);
100     sexp_write_string(ctx, sexp_string_data(sexp_type_name(t)), out);
101     sexp_write_char(ctx, ' ', out);
102     if (sexp_type_id(t) && sexp_truep(sexp_type_id(t))) {
103       sexp_write(ctx, sexp_type_id(t), out);
104     } else {
105       sexp_write_char(ctx, '#', out);
106       sexp_write(ctx, sexp_make_fixnum(sexp_type_tag(t)), out);
107     }
108     len = sexp_type_num_slots_of_object(t, obj);
109     args = sexp_list1(ctx, SEXP_FALSE);
110     for (i=0; i<len; i++) {
111       x = sexp_slot_ref(obj, i);
112       if (x) {
113         for ( ; nulls; --nulls)
114           sexp_write_string(ctx, " #f", out);
115         sexp_write_char(ctx, ' ', out);
116         if (writer && sexp_applicablep(writer)) {
117           sexp_car(args) = x;
118           x = sexp_apply(ctx, writer, args);
119           if (sexp_exceptionp(x)) sexp_print_exception(ctx, x, out);
120         } else {
121           sexp_write(ctx, sexp_slot_ref(obj, i), out);
122         }
123       } else {
124         nulls++;
125       }
126     }
127     sexp_gc_release1(ctx);
128   }
129   sexp_write_char(ctx, '}', out);
130   return SEXP_VOID;
131 }
132 #else
133 #define sexp_write_simple_object NULL
134 #endif
135 
136 #if SEXP_USE_UNIFORM_VECTOR_LITERALS
sexp_write_uvector(sexp ctx,sexp self,sexp_sint_t n,sexp obj,sexp writer,sexp out)137 sexp sexp_write_uvector(sexp ctx, sexp self, sexp_sint_t n, sexp obj, sexp writer, sexp out) {
138   sexp_uint_t i, len;
139   char* str;
140   sexp_gc_var2(f, tmp);
141   sexp_gc_preserve2(ctx, f, tmp);
142   f = sexp_make_flonum(ctx, 0.0f);
143   sexp_write_char(ctx, '#', out);
144   sexp_write_char(ctx, sexp_uvector_prefix(sexp_uvector_type(obj)), out);
145   sexp_write(ctx, sexp_make_fixnum(sexp_uvector_element_size(sexp_uvector_type(obj))), out);
146   sexp_write_char(ctx, '(', out);
147   len = sexp_uvector_length(obj);
148   str = (char*) sexp_uvector_data(obj);
149   for (i=0; i<(sexp_sint_t)len; i++) {
150     if (i!=0) sexp_write_char(ctx, ' ', out);
151     switch (sexp_uvector_type(obj)) {
152     case SEXP_U1: sexp_write(ctx, sexp_make_fixnum(sexp_bit_ref(obj, i)), out); break;
153     case SEXP_S8: sexp_write(ctx, sexp_make_fixnum(((signed char*)str)[i]), out); break;
154     case SEXP_S16: sexp_write(ctx, sexp_make_fixnum(((signed short*)str)[i]), out); break;
155     case SEXP_U16: sexp_write(ctx, sexp_make_fixnum(((unsigned short*)str)[i]), out); break;
156     case SEXP_S32: sexp_write(ctx, tmp=sexp_make_integer(ctx, ((int32_t*)str)[i]), out); break;
157     case SEXP_U32: sexp_write(ctx, tmp=sexp_make_unsigned_integer(ctx, ((uint32_t*)str)[i]), out); break;
158     case SEXP_S64: sexp_write(ctx, tmp=sexp_make_integer(ctx, ((int64_t*)str)[i]), out); break;
159     case SEXP_U64: sexp_write(ctx, tmp=sexp_make_unsigned_integer(ctx, ((uint64_t*)str)[i]), out); break;
160 #if SEXP_USE_FLONUMS
161     case SEXP_F32: sexp_flonum_value_set(f, ((float*)str)[i]); sexp_write(ctx, f, out); break;
162     case SEXP_F64: sexp_flonum_value_set(f, ((double*)str)[i]); sexp_write(ctx, f, out); break;
163 #endif
164 #if SEXP_USE_COMPLEX
165     case SEXP_C64:
166       sexp_flonum_value_set(f, ((float*)str)[i*2]);
167       sexp_write(ctx, f, out);
168       if (((float*)str)[i*2 + 1] >= 0)
169         sexp_write_char(ctx, '+', out);
170       sexp_flonum_value_set(f, ((float*)str)[i*2 + 1]);
171       sexp_write(ctx, f, out);
172       sexp_write_char(ctx, 'i', out);
173       break;
174     case SEXP_C128:
175       sexp_flonum_value_set(f, ((double*)str)[i*2]);
176       sexp_write(ctx, f, out);
177       if (((double*)str)[i*2 + 1] >= 0)
178         sexp_write_char(ctx, '+', out);
179       sexp_flonum_value_set(f, ((double*)str)[i*2 + 1]);
180       sexp_write(ctx, f, out);
181       sexp_write_char(ctx, 'i', out);
182       break;
183 #endif
184     }
185   }
186   sexp_write_char(ctx, ')', out);
187   sexp_gc_release2(ctx);
188   return SEXP_VOID;
189 }
190 #endif
191 
sexp_finalize_fileno(sexp ctx,sexp self,sexp_sint_t n,sexp fileno)192 sexp sexp_finalize_fileno (sexp ctx, sexp self, sexp_sint_t n, sexp fileno) {
193   if (sexp_fileno_openp(fileno) && !sexp_fileno_no_closep(fileno)) {
194     sexp_fileno_openp(fileno) = 0;
195     close(sexp_fileno_fd(fileno));
196   }
197   return SEXP_VOID;
198 }
199 
sexp_finalize_port(sexp ctx,sexp self,sexp_sint_t n,sexp port)200 sexp sexp_finalize_port (sexp ctx, sexp self, sexp_sint_t n, sexp port) {
201   sexp res = SEXP_VOID;
202   if (sexp_port_openp(port)) {
203     sexp_port_openp(port) = 0;
204     if (sexp_oportp(port)) sexp_flush_forced(ctx, port);
205 #ifndef PLAN9
206     if (sexp_filenop(sexp_port_fd(port))
207         && sexp_fileno_openp(sexp_port_fd(port))) {
208       if (sexp_port_shutdownp(port)) {
209         /* shutdown the socket if requested */
210         if (sexp_iportp(port))
211           shutdown(sexp_port_fileno(port), sexp_oportp(port) ? SHUT_RDWR : SHUT_RD);
212         if (sexp_oportp(port))
213           shutdown(sexp_port_fileno(port), SHUT_WR);
214       }
215       if (!sexp_port_no_closep(port)) {
216         if (--sexp_fileno_count(sexp_port_fd(port)) == 0)
217           sexp_finalize_fileno(ctx, self, n, sexp_port_fd(port));
218       }
219     }
220 #endif
221     if (sexp_port_stream(port) && ! sexp_port_no_closep(port))
222       /* close the stream */
223       fclose(sexp_port_stream(port));
224     sexp_port_offset(port) = 0;
225     sexp_port_size(port) = 0;
226   }
227   return res;
228 }
229 
230 #if SEXP_USE_DL
231 #ifdef _WIN32
sexp_finalize_dl(sexp ctx,sexp self,sexp_sint_t n,sexp dl)232 sexp sexp_finalize_dl (sexp ctx, sexp self, sexp_sint_t n, sexp dl) {
233   FreeLibrary(sexp_dl_handle(dl));
234   return SEXP_VOID;
235 }
236 #else
sexp_finalize_dl(sexp ctx,sexp self,sexp_sint_t n,sexp dl)237 sexp sexp_finalize_dl (sexp ctx, sexp self, sexp_sint_t n, sexp dl) {
238   dlclose(sexp_dl_handle(dl));
239   return SEXP_VOID;
240 }
241 #endif
242 #endif
243 
244 #if SEXP_USE_UNIFORM_VECTOR_LITERALS
sexp_finalize_uvector(sexp ctx,sexp self,sexp_sint_t n,sexp obj)245 sexp sexp_finalize_uvector (sexp ctx, sexp self, sexp_sint_t n, sexp obj) {
246   /* if (sexp_uvector_freep(obj)) */
247   /*   free(sexp_uvector_data(obj)); */
248   return SEXP_VOID;
249 }
250 #endif
251 
252 static struct sexp_type_struct _sexp_type_specs[] = {
253   {(sexp)"Object", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_OBJECT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL},
254   {(sexp)"Type", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_TYPE, sexp_offsetof(type, name), 9, 9, 0, 0, sexp_sizeof(type), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
255   {(sexp)"Integer", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_FIXNUM, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL},
256   {(sexp)"Number", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_NUMBER, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL},
257   {(sexp)"Char", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_CHAR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL},
258   {(sexp)"Boolean", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_BOOLEAN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL},
259   {(sexp)"Pair", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_PAIR, sexp_offsetof(pair, car), 2, 3, 0, 0, sexp_sizeof(pair), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
260   {(sexp)"Symbol", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_SYMBOL, 0, 0, 0, 0, 0, sexp_sizeof(symbol)+1, sexp_offsetof(symbol, length), 1, 0, 0, 0, 0, 0, 0, NULL},
261   {(sexp)"Byte-Vector", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_BYTES, 0, 0, 0, 0, 0, sexp_sizeof(bytes)+1, sexp_offsetof(bytes, length), 1, 0, 0, 0, 0, 0, 0, NULL},
262 #if SEXP_USE_PACKED_STRINGS
263   {(sexp)"String", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_STRING, 0, 0, 0, 0, 0, sexp_sizeof(string)+1, sexp_offsetof(string, length), 1, 0, 0, 0, 0, 0, 0, NULL},
264 #else
265   {(sexp)"String", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_STRING, sexp_offsetof(string, bytes), 1, 1+SEXP_USE_STRING_INDEX_TABLE, 0, 0, sexp_sizeof(string), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
266 #endif
267   {(sexp)"Vector", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_VECTOR, sexp_offsetof(vector, data), 0, 0, sexp_offsetof(vector, length), 1, sexp_sizeof(vector), sexp_offsetof(vector, length), sizeof(sexp), 0, 0, 0, 0, 0, 0, NULL},
268   {(sexp)"Flonum", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_FLONUM, 0, 0, 0, 0, 0, sexp_sizeof(flonum), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
269   {(sexp)"Bignum", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_BIGNUM, 0, 0, 0, 0, 0, sexp_sizeof(bignum), sexp_offsetof(bignum, length), sizeof(sexp_uint_t), 0, 0, 0, 0, 0, 0, NULL},
270 #if SEXP_USE_STABLE_ABI || SEXP_USE_RATIOS
271   {(sexp)"Ratio", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_RATIO, sexp_offsetof(ratio, numerator), 2, 2, 0, 0, sexp_sizeof(ratio), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
272 #endif
273 #if SEXP_USE_STABLE_ABI || SEXP_USE_COMPLEX
274   {(sexp)"Complex", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_COMPLEX, sexp_offsetof(complex, real), 2, 2, 0, 0, sexp_sizeof(complex), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
275 #endif
276 #if SEXP_USE_STABLE_ABI || SEXP_USE_DISJOINT_STRING_CURSORS
277   {(sexp)"String-Cursor", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_STRING_CURSOR, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL},
278 #endif
279   {(sexp)"Input-Port", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, SEXP_FINALIZE_PORTN, SEXP_IPORT, sexp_offsetof(port, name), 3, 3, 0, 0, sexp_sizeof(port), 0, 0, 0, 0, 0, 0, 0, 0, SEXP_FINALIZE_PORT},
280   {(sexp)"Output-Port", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, SEXP_FINALIZE_PORTN, SEXP_OPORT, sexp_offsetof(port, name), 3, 3, 0, 0, sexp_sizeof(port), 0, 0, 0, 0, 0, 0, 0, 0, SEXP_FINALIZE_PORT},
281   {(sexp)"File-Descriptor", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, SEXP_FINALIZE_FILENON, SEXP_FILENO, 0, 0, 0, 0, 0, sexp_sizeof(fileno), 0, 0, 0, 0, 0, 0, 0, 0, SEXP_FINALIZE_FILENO},
282   {(sexp)"Exception", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, SEXP_EXCEPTION, sexp_offsetof(exception, kind), 6, 6, 0, 0, sexp_sizeof(exception), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
283   {(sexp)"Procedure", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_PROCEDURE, sexp_offsetof(procedure, bc), 2, 2, 0, 0, sexp_sizeof(procedure), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
284   {(sexp)"Macro", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_MACRO, sexp_offsetof(macro, proc), 4, 4, 0, 0, sexp_sizeof(macro), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
285   {(sexp)"Sc", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, SEXP_SYNCLO, sexp_offsetof(synclo, env), 4, 4, 0, 0, sexp_sizeof(synclo), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
286   {(sexp)"Environment", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_ENV, sexp_offsetof(env, parent), 3+(SEXP_USE_STABLE_ABI||SEXP_USE_RENAME_BINDINGS), 3+(SEXP_USE_STABLE_ABI||SEXP_USE_RENAME_BINDINGS), 0, 0, sexp_sizeof(env), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
287   {(sexp)"Bytecode", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_BYTECODE, sexp_offsetof(bytecode, name), 3, 3, 0, 0, sexp_sizeof(bytecode), offsetof(struct sexp_struct, value.bytecode.length), 1, 0, 0, 0, 0, 0, 0, NULL},
288   {(sexp)"Core-Form", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_CORE, sexp_offsetof(core, name), 1, 1, 0, 0, sexp_sizeof(core), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
289 #if SEXP_USE_STABLE_ABI || SEXP_USE_DL
290   {(sexp)"Dynamic-Library", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, SEXP_FINALIZE_DLN, SEXP_DL, sexp_offsetof(dl, file), 1, 1, 0, 0, sexp_sizeof(dl), 0, 0, 0, 0, 0, 0, 0, 0, SEXP_FINALIZE_DL},
291 #endif
292   {(sexp)"Opcode", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_OPCODE, sexp_offsetof(opcode, name), 11, 11, 0, 0, sexp_sizeof(opcode), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
293   {(sexp)"Lambda", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, SEXP_LAMBDA, sexp_offsetof(lambda, name), 11, 11, 0, 0, sexp_sizeof(lambda), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
294   {(sexp)"If", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, SEXP_CND, sexp_offsetof(cnd, test), 4, 4, 0, 0, sexp_sizeof(cnd), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
295   {(sexp)"Ref", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, SEXP_REF, sexp_offsetof(ref, name), 3, 3, 0, 0, sexp_sizeof(ref), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
296   {(sexp)"Set!", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, SEXP_SET, sexp_offsetof(set, var), 3, 3, 0, 0, sexp_sizeof(set), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
297   {(sexp)"Set-Syn!", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, SEXP_SET_SYN, sexp_offsetof(set_syn, var), 3, 3, 0, 0, sexp_sizeof(set_syn), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
298   {(sexp)"Seq", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, SEXP_SEQ, sexp_offsetof(seq, ls), 2, 2, 0, 0, sexp_sizeof(seq), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
299   {(sexp)"Lit", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_simple_object, NULL, NULL, SEXP_LIT, sexp_offsetof(lit, value), 2, 2, 0, 0, sexp_sizeof(lit), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
300   {(sexp)"Stack", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_STACK, sexp_offsetof(stack, data), 0, 0, sexp_offsetof(stack, top), 1, sexp_sizeof(stack), offsetof(struct sexp_struct, value.stack.length), sizeof(sexp), 0, 0, 0, 0, 0, 0, NULL},
301   {(sexp)"Context", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_CONTEXT, sexp_offsetof(context, stack), 12+(SEXP_USE_STABLE_ABI||SEXP_USE_DL), 12+(SEXP_USE_STABLE_ABI||SEXP_USE_DL), 0, 0, sexp_sizeof(context), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
302   {(sexp)"Cpointer", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_CPOINTER, sexp_offsetof(cpointer, parent), 1, 0, 0, 0, sexp_sizeof(cpointer), sexp_offsetof(cpointer, length), 1, 0, 0, 0, 0, 0, 0, NULL},
303 #if SEXP_USE_STABLE_ABI || SEXP_USE_UNIFORM_VECTOR_LITERALS
304   {(sexp)"Uniform-Vector", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, (sexp)sexp_write_uvector, NULL, (sexp)"sexp_finalize_uvector", SEXP_UNIFORM_VECTOR, sexp_offsetof(uvector, bytes), 1, 1, 0, 0, sexp_sizeof(uvector), 0, 0, 0, 0, 0, 0, 0, 0, sexp_finalize_uvector},
305 #endif
306 #if SEXP_USE_STABLE_ABI || SEXP_USE_AUTO_FORCE
307   {(sexp)"Promise", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_PROMISE, sexp_offsetof(promise, value), 1, 1, 0, 0, sexp_sizeof(promise), 0, 0, 0, 0, 0, 0, 0, 0, NULL},
308 #endif
309 #if SEXP_USE_STABLE_ABI || SEXP_USE_WEAK_REFERENCES
310   {(sexp)"Ephemeron", SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, SEXP_FALSE, NULL, NULL, NULL, SEXP_EPHEMERON, sexp_offsetof(ephemeron, key), 2, 0, 0, 0, sexp_sizeof(ephemeron), 0, 0, sexp_offsetof(ephemeron, key), 1, 0, 0, 1, 0, NULL},
311 #endif
312 };
313 
314 #define SEXP_INIT_NUM_TYPES (SEXP_NUM_CORE_TYPES*2)
315 
316 #if SEXP_USE_TYPE_DEFS
317 
sexp_register_type_op(sexp ctx,sexp self,sexp_sint_t n,sexp name,sexp parent,sexp slots,sexp fb,sexp felb,sexp flb,sexp flo,sexp fls,sexp sb,sexp so,sexp sc,sexp w,sexp wb,sexp wo,sexp ws,sexp we,sexp p,const char * fname,sexp_proc2 f)318 sexp sexp_register_type_op (sexp ctx, sexp self, sexp_sint_t n, sexp name,
319                             sexp parent, sexp slots,
320                             sexp fb, sexp felb, sexp flb, sexp flo, sexp fls,
321                             sexp sb, sexp so, sexp sc, sexp w, sexp wb, sexp wo,
322                             sexp ws, sexp we, sexp p, const char* fname, sexp_proc2 f) {
323   sexp *v1, *v2;
324   sexp_gc_var2(res, type);
325   sexp_uint_t i, len, num_types=sexp_context_num_types(ctx),
326     type_array_size=sexp_context_type_array_size(ctx);
327   sexp_gc_preserve2(ctx, res, type);
328   if (num_types >= SEXP_MAXIMUM_TYPES) {
329     res = sexp_user_exception(ctx, self, "register-type: exceeded maximum type limit", name);
330   } else if (! sexp_stringp(name)) {
331     res = sexp_type_exception(ctx, self, SEXP_STRING, name);
332   } else {
333     if (num_types >= type_array_size) {
334       len = type_array_size*2;
335       if (len > SEXP_MAXIMUM_TYPES) len = SEXP_MAXIMUM_TYPES;
336       res = sexp_make_vector(ctx, sexp_make_fixnum(len), SEXP_VOID);
337       if (sexp_exceptionp(res)) {
338         sexp_gc_release2(ctx);
339         return res;
340       }
341       v1 = sexp_vector_data(res);
342       v2 = sexp_vector_data(sexp_global(ctx, SEXP_G_TYPES));
343       for (i=0; i<num_types; i++)
344         v1[i] = v2[i];
345       sexp_global(ctx, SEXP_G_TYPES) = res;
346     }
347     sexp_type_by_index(ctx, num_types) = sexp_alloc_type(ctx, type, SEXP_TYPE);
348     type = sexp_type_by_index(ctx, num_types);
349     if (!sexp_exceptionp(type)) {
350       sexp_pointer_tag(type) = SEXP_TYPE;
351       sexp_type_tag(type) = num_types;
352       sexp_type_slots(type) = slots;
353       sexp_type_field_base(type) = (short)sexp_unbox_fixnum(fb);
354       sexp_type_field_eq_len_base(type) = (short)sexp_unbox_fixnum(felb);
355       sexp_type_field_len_base(type) = (short)sexp_unbox_fixnum(flb);
356       sexp_type_field_len_off(type) = (short)sexp_unbox_fixnum(flo);
357       sexp_type_field_len_scale(type) = (unsigned short)sexp_unbox_fixnum(fls);
358       sexp_type_size_base(type) = (short)sexp_unbox_fixnum(sb);
359       sexp_type_size_off(type) = (short)sexp_unbox_fixnum(so);
360       sexp_type_size_scale(type) = (unsigned short)sexp_unbox_fixnum(sc);
361       sexp_type_weak_base(type) = (short)sexp_unbox_fixnum(w);
362       sexp_type_weak_len_base(type) = (short)sexp_unbox_fixnum(wb);
363       sexp_type_weak_len_off(type) = (short)sexp_unbox_fixnum(wo);
364       sexp_type_weak_len_scale(type) = (short)sexp_unbox_fixnum(ws);
365       sexp_type_weak_len_extra(type) = (short)sexp_unbox_fixnum(we);
366       sexp_type_name(type) = name;
367       sexp_type_getters(type) = SEXP_FALSE;
368       sexp_type_setters(type) = SEXP_FALSE;
369       sexp_type_finalize(type) = f;
370       sexp_type_finalize_name(type) = (fname) ? sexp_c_string(ctx, fname, -1) : NULL;
371       sexp_type_id(type) = SEXP_FALSE;
372 #if SEXP_USE_DL
373       if (f) sexp_type_dl(type) = sexp_context_dl(ctx);
374 #endif
375       sexp_type_print(type) = p;
376       if (parent && sexp_typep(parent)) {
377         len = sexp_vectorp(sexp_type_cpl(parent)) ? sexp_vector_length(sexp_type_cpl(parent)) : 1;
378         sexp_type_cpl(type) = sexp_make_vector(ctx, sexp_make_fixnum(len+1), SEXP_VOID);
379         if (parent && sexp_vectorp(sexp_type_cpl(parent)))
380           memcpy(sexp_vector_data(sexp_type_cpl(type)),
381                  sexp_vector_data(sexp_type_cpl(parent)),
382                  len * sizeof(sexp));
383         else
384           sexp_vector_data(sexp_type_cpl(type))[len-1] = parent;
385       } else {
386         len = 0;
387         sexp_type_cpl(type) = sexp_make_vector(ctx, SEXP_ONE, SEXP_VOID);
388       }
389       sexp_vector_data(sexp_type_cpl(type))[len] = type;
390       sexp_type_depth(type) = (short)len;
391       sexp_global(ctx, SEXP_G_NUM_TYPES) = sexp_make_fixnum(num_types + 1);
392     }
393     res = type;
394   }
395   sexp_gc_release2(ctx);
396   return res;
397 }
398 
sexp_register_simple_type_op(sexp ctx,sexp self,sexp_sint_t n,sexp name,sexp parent,sexp slots)399 sexp sexp_register_simple_type_op (sexp ctx, sexp self, sexp_sint_t n, sexp name, sexp parent, sexp slots) {
400   short i, num_slots = (short)sexp_unbox_fixnum(sexp_length(ctx, slots));
401   sexp type_size, num_slots_obj, cpl, tmp;
402   if (parent && sexp_typep(parent)) {
403     num_slots += (short)sexp_unbox_fixnum(sexp_length(ctx, sexp_type_slots(parent)));
404     if (sexp_vectorp((cpl = sexp_type_cpl(parent))))
405       for (i=(short)sexp_vector_length(cpl)-1; i>=0; i--) {
406         tmp = sexp_vector_ref(cpl, sexp_make_fixnum(i));
407         num_slots += (short)sexp_unbox_fixnum(sexp_length(ctx, sexp_type_slots(tmp)));
408       }
409   }
410   num_slots_obj = sexp_make_fixnum(num_slots);
411   type_size = sexp_make_fixnum(sexp_sizeof_header + sizeof(sexp)*num_slots);
412   return
413     sexp_register_type(ctx, name, parent, slots,
414                        sexp_make_fixnum(sexp_offsetof_slot0),
415                        num_slots_obj, num_slots_obj, SEXP_ZERO, SEXP_ZERO,
416                        type_size, SEXP_ZERO, SEXP_ZERO, SEXP_ZERO, SEXP_ZERO,
417                        SEXP_ZERO, SEXP_ZERO, SEXP_ZERO,
418                        sexp_type_print(sexp_type_by_index(ctx, SEXP_EXCEPTION)),
419                        NULL, NULL);
420 }
421 
422 #if SEXP_USE_OBJECT_BRACE_LITERALS
sexp_lookup_type_op(sexp ctx,sexp self,sexp_sint_t n,sexp name,sexp id)423 sexp sexp_lookup_type_op(sexp ctx, sexp self, sexp_sint_t n, sexp name, sexp id) {
424   int i;
425   sexp res;
426   const char* str;
427   sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, name);
428   str = sexp_string_data(name);
429   if (sexp_fixnump(id)) {
430     i = sexp_unbox_fixnum(id);
431     if (i < sexp_context_num_types(ctx)
432         && strcmp(str, sexp_string_data(sexp_type_name_by_index(ctx, i))) == 0)
433       return sexp_type_by_index(ctx, i);
434     else
435       return SEXP_FALSE;
436   }
437   for (i=sexp_context_num_types(ctx)-1; i>=0; i--)
438     if (strcmp(str, sexp_string_data(sexp_type_name_by_index(ctx, i))) == 0) {
439       res = sexp_type_by_index(ctx, i);
440       if (sexp_stringp(id)
441           && !(sexp_stringp(sexp_type_id(res))
442                && strcmp(sexp_string_data(id), sexp_string_data(sexp_type_id(res))) == 0))
443         continue;
444       return res;
445     }
446   return SEXP_FALSE;
447 }
448 #endif
449 
sexp_finalize_c_type(sexp ctx,sexp self,sexp_sint_t n,sexp obj)450 sexp sexp_finalize_c_type (sexp ctx, sexp self, sexp_sint_t n, sexp obj) {
451   if (sexp_cpointer_freep(obj))
452     free(sexp_cpointer_value(obj));
453   return SEXP_VOID;
454 }
455 
456 #else
457 #define sexp_num_types SEXP_NUM_CORE_TYPES
458 #endif
459 
460 /****************************** contexts ******************************/
461 
462 static const char* sexp_initial_features[] = {
463   sexp_platform,
464 #if SEXP_BSD
465   "bsd",
466 #endif
467 #if SEXP_DARWIN
468   "darwin",
469 #endif
470 #if SEXP_OPENBSD
471   "openbsd",
472 #endif
473 #if SEXP_FREEBSD
474   "freebsd",
475 #endif
476 #if SEXP_NETBSD
477   "netbsd",
478 #endif
479 #if SEXP_DRAGONFLY
480   "dragonfly",
481 #endif
482 #if defined(_WIN32)
483   "windows",
484 #endif
485 #if SEXP_USE_DL
486   "dynamic-loading",
487 #endif
488 #if SEXP_USE_BIDIRECTIONAL_PORTS
489   "bidir-ports",
490 #endif
491 #if SEXP_USE_MODULES
492   "modules",
493 #endif
494 #if SEXP_USE_BOEHM
495   "boehm-gc",
496 #endif
497 #if SEXP_USE_UTF8_STRINGS
498   "full-unicode",
499 #endif
500 #if SEXP_USE_STRING_INDEX_TABLE
501   "string-index",
502 #endif
503 #if SEXP_USE_GREEN_THREADS
504   "threads",
505 #endif
506 #if SEXP_USE_NTP_GETTIME
507   "ntp",
508 #endif
509 #if SEXP_USE_AUTO_FORCE
510   "auto-force",
511 #endif
512 #if SEXP_USE_UNIFORM_VECTOR_LITERALS
513   "uvector",
514 #endif
515 #if SEXP_USE_COMPLEX
516   "complex",
517 #endif
518 #if SEXP_USE_RATIOS
519   "ratios",
520 #endif
521   "r7rs",
522   "chibi",
523   NULL,
524 };
525 
sexp_init_context_globals(sexp ctx)526 void sexp_init_context_globals (sexp ctx) {
527   const char** features;
528   int i, endianess_check = 1;
529   sexp type, *vec, print=NULL;
530   sexp_gc_var1(feature);
531   sexp_context_globals(ctx)
532     = sexp_make_vector(ctx, sexp_make_fixnum(SEXP_G_NUM_GLOBALS), SEXP_VOID);
533 #if ! SEXP_USE_GLOBAL_SYMBOLS
534   sexp_global(ctx, SEXP_G_SYMBOLS) = sexp_make_vector(ctx, sexp_make_fixnum(SEXP_SYMBOL_TABLE_SIZE), SEXP_NULL);
535 #endif
536   sexp_global(ctx, SEXP_G_STRICT_P) = SEXP_FALSE;
537   sexp_global(ctx, SEXP_G_NO_TAIL_CALLS_P) = SEXP_FALSE;
538 #if SEXP_USE_FOLD_CASE_SYMS
539   sexp_global(ctx, SEXP_G_FOLD_CASE_P) = sexp_make_boolean(SEXP_DEFAULT_FOLD_CASE_SYMS);
540 #endif
541 #if ! SEXP_USE_BOEHM
542   sexp_global(ctx, SEXP_G_PRESERVATIVES) = SEXP_NULL;
543 #endif
544 #if SEXP_USE_WEAK_REFERENCES
545   sexp_global(ctx, SEXP_G_WEAK_OBJECTS_PRESENT) = SEXP_FALSE;
546   sexp_global(ctx, SEXP_G_FILE_DESCRIPTORS) = SEXP_FALSE;
547   sexp_global(ctx, SEXP_G_NUM_FILE_DESCRIPTORS) = SEXP_ZERO;
548 #endif
549   sexp_global(ctx, SEXP_G_OOM_ERROR) = sexp_user_exception(ctx, SEXP_FALSE, "out of memory", SEXP_NULL);
550   sexp_global(ctx, SEXP_G_OOS_ERROR) = sexp_user_exception(ctx, SEXP_FALSE, "out of stack space", SEXP_NULL);
551   sexp_global(ctx, SEXP_G_ABI_ERROR) = sexp_user_exception(ctx, SEXP_FALSE, "incompatible ABI", SEXP_NULL);
552   sexp_global(ctx, SEXP_G_INTERRUPT_ERROR) = sexp_user_exception(ctx, SEXP_FALSE, "interrupt", SEXP_NULL);
553   sexp_global(ctx, SEXP_G_QUOTE_SYMBOL) = sexp_intern(ctx, "quote", -1);
554   sexp_global(ctx, SEXP_G_QUASIQUOTE_SYMBOL) = sexp_intern(ctx, "quasiquote", -1);
555   sexp_global(ctx, SEXP_G_UNQUOTE_SYMBOL) = sexp_intern(ctx, "unquote", -1);
556   sexp_global(ctx, SEXP_G_UNQUOTE_SPLICING_SYMBOL) = sexp_intern(ctx, "unquote-splicing", -1);
557   sexp_global(ctx, SEXP_G_SYNTAX_SYMBOL) = sexp_intern(ctx, "syntax", -1);
558   sexp_global(ctx, SEXP_G_QUASISYNTAX_SYMBOL) = sexp_intern(ctx, "quasisyntax", -1);
559   sexp_global(ctx, SEXP_G_UNSYNTAX_SYMBOL) = sexp_intern(ctx, "unsyntax", -1);
560   sexp_global(ctx, SEXP_G_UNSYNTAX_SPLICING_SYMBOL) = sexp_intern(ctx, "unsyntax-splicing", -1);
561   sexp_global(ctx, SEXP_G_CUR_IN_SYMBOL) = sexp_intern(ctx, "current-input-port", -1);
562   sexp_global(ctx, SEXP_G_CUR_OUT_SYMBOL) = sexp_intern(ctx, "current-output-port", -1);
563   sexp_global(ctx, SEXP_G_CUR_ERR_SYMBOL) = sexp_intern(ctx, "current-error-port", -1);
564   sexp_global(ctx, SEXP_G_INTERACTION_ENV_SYMBOL) = sexp_intern(ctx, "interaction-environment", -1);
565   sexp_global(ctx, SEXP_G_CONTINUABLE_SYMBOL) = sexp_intern(ctx, "continuable", -1);
566   sexp_global(ctx, SEXP_G_EMPTY_VECTOR) = sexp_alloc_type(ctx, vector, SEXP_VECTOR);
567   sexp_vector_length(sexp_global(ctx, SEXP_G_EMPTY_VECTOR)) = 0;
568   sexp_global(ctx, SEXP_G_FEATURES) = SEXP_NULL;
569   sexp_push(ctx, sexp_global(ctx, SEXP_G_FEATURES), SEXP_FALSE);
570   sexp_car(sexp_global(ctx, SEXP_G_FEATURES)) = sexp_intern(ctx, (*(unsigned char*) &endianess_check) ? "little-endian" : "big-endian", -1);
571   sexp_global(ctx, SEXP_G_ENDIANNESS) = sexp_intern(ctx, (*(unsigned char*) &endianess_check) ? "little" : "big", -1);
572   sexp_gc_preserve1(ctx, feature);
573   for (features=sexp_initial_features; *features; features++) {
574     feature = sexp_intern(ctx, *features, -1);
575     if (sexp_not(sexp_memq(ctx, feature, sexp_global(ctx, SEXP_G_FEATURES)))) {
576       sexp_push(ctx, sexp_global(ctx, SEXP_G_FEATURES), SEXP_FALSE);
577       sexp_car(sexp_global(ctx, SEXP_G_FEATURES)) = feature;
578     }
579   }
580   sexp_gc_release1(ctx);
581   sexp_global(ctx, SEXP_G_NUM_TYPES) = sexp_make_fixnum(SEXP_NUM_CORE_TYPES);
582   sexp_global(ctx, SEXP_G_TYPES)
583     = sexp_make_vector(ctx, sexp_make_fixnum(SEXP_INIT_NUM_TYPES), SEXP_VOID);
584   vec = sexp_vector_data(sexp_global(ctx, SEXP_G_TYPES));
585   for (i=0; i<SEXP_NUM_CORE_TYPES; i++) {
586     type = sexp_alloc_type(ctx, type, SEXP_TYPE);
587     if (!type) {
588       return; /* TODO - fundamental OOM, what to do here? */
589     }
590     memcpy(&(type->value), &(_sexp_type_specs[i]), sizeof(_sexp_type_specs[0]));
591     vec[i] = type;
592     sexp_type_name(type) = sexp_c_string(ctx, (char*)sexp_type_name(type), -1);
593     if (sexp_type_finalize_name(type)) {
594       sexp_type_finalize_name(type) = sexp_c_string(ctx, (char*)sexp_type_finalize_name(type), -1);
595     }
596     if (sexp_type_print(type)) {
597       if (print && ((sexp_proc1)sexp_type_print(type) == sexp_opcode_func(print)))
598         sexp_type_print(type) = print;
599       else
600         sexp_type_print(type) = print = sexp_make_foreign(ctx, "sexp_write_simple_object", 3, 0, NULL, (sexp_proc1)sexp_type_print(type), NULL);
601     }
602   }
603 }
604 
605 #if ! SEXP_USE_GLOBAL_HEAP
sexp_bootstrap_context(sexp_uint_t size,sexp_uint_t max_size)606 sexp sexp_bootstrap_context (sexp_uint_t size, sexp_uint_t max_size) {
607   sexp ctx;
608   sexp_heap heap;
609   struct sexp_struct dummy_ctx;
610   if (size < SEXP_MINIMUM_HEAP_SIZE) size = SEXP_INITIAL_HEAP_SIZE;
611   size = sexp_heap_align(size);
612   max_size = sexp_heap_align(max_size);
613   heap = sexp_make_heap(size, max_size, 0);
614   if (!heap) return 0;
615   sexp_pointer_tag(&dummy_ctx) = SEXP_CONTEXT;
616   sexp_context_mark_stack_ptr(&dummy_ctx) = NULL;
617   sexp_context_saves(&dummy_ctx) = NULL;
618   sexp_context_heap(&dummy_ctx) = heap;
619   ctx = sexp_alloc_type(&dummy_ctx, context, SEXP_CONTEXT);
620   if (!ctx || sexp_exceptionp(ctx)) {
621     sexp_free_heap(heap);
622   } else {
623     sexp_context_heap(ctx) = heap;
624 #if SEXP_USE_FIXED_CHUNK_SIZE_HEAPS
625     heap->chunk_size = sexp_heap_align(1);
626     heap->next = sexp_make_heap(size, max_size, 0);
627     if (heap->next) {
628       heap->next->chunk_size = sexp_heap_align(1 + sexp_heap_align(1));
629       heap->next->next = sexp_make_heap(size, max_size, 0);
630       if (heap->next->next) {
631         heap->next->next->chunk_size = sexp_heap_align(1 + sexp_heap_align(1 + sexp_heap_align(1)));
632         heap->next->next->next = sexp_make_heap(size, max_size, 0);
633       }
634     }
635 #endif
636   }
637   return ctx;
638 }
639 #endif
640 
sexp_make_context(sexp ctx,size_t size,size_t max_size)641 sexp sexp_make_context (sexp ctx, size_t size, size_t max_size) {
642   sexp_gc_var1(res);
643   if (ctx) sexp_gc_preserve1(ctx, res);
644 #if ! SEXP_USE_GLOBAL_HEAP
645   if (! ctx) {
646     res = sexp_bootstrap_context(size, max_size);
647     if (!res || sexp_exceptionp(res)) return res;
648   } else
649 #endif
650     {
651       res = sexp_alloc_type(ctx, context, SEXP_CONTEXT);
652 #if ! SEXP_USE_BOEHM && ! SEXP_USE_MALLOC
653       sexp_context_heap(res) = sexp_context_heap(ctx);
654 #endif
655     }
656   if (!res || sexp_exceptionp(res)) return res;
657   sexp_context_parent(res) = ctx;
658   sexp_context_name(res) = sexp_context_specific(res) = SEXP_FALSE;
659   sexp_context_mark_stack_ptr(res) = NULL;
660   sexp_context_saves(res) = NULL;
661   sexp_context_params(res) = SEXP_NULL;
662   sexp_context_last_fp(res) = 0;
663 #if SEXP_USE_TIME_GC
664   sexp_context_gc_count(res) = 0;
665   sexp_context_gc_usecs(res) = 0;
666 #endif
667 #if SEXP_USE_TRACK_ALLOC_TIMES
668   sexp_context_alloc_count(res) = 0;
669   sexp_context_alloc_usecs(res) = 0;
670   sexp_context_alloc_usecs_sq(res) = 0;
671 #endif
672   sexp_context_tracep(res) = 0;
673   sexp_context_timeoutp(res) = 0;
674   sexp_context_tailp(res) = 1;
675 #if SEXP_USE_GREEN_THREADS
676   sexp_context_errorp(res) = 0;
677   sexp_context_event(res) = SEXP_FALSE;
678   sexp_context_refuel(res) = SEXP_DEFAULT_QUANTUM;
679 #endif
680 #if SEXP_USE_DL
681   sexp_context_dl(res) = ctx ? sexp_context_dl(ctx) : SEXP_FALSE;
682 #endif
683   if (ctx) {
684     sexp_context_globals(res) = sexp_context_globals(ctx);
685     sexp_context_dk(res) = sexp_context_dk(ctx);
686     sexp_gc_release1(ctx);
687   } else {
688     sexp_init_context_globals(res);
689   }
690   return res;
691 }
692 
693 #if ! SEXP_USE_GLOBAL_HEAP
sexp_destroy_context(sexp ctx)694 sexp sexp_destroy_context (sexp ctx) {
695   sexp_heap heap, tmp;
696   size_t sum_freed;
697   if (sexp_context_heap(ctx)) {
698     heap = sexp_context_heap(ctx);
699 #if SEXP_USE_DEBUG_GC
700     sexp_debug_heap_stats(heap);
701 #endif
702 #if SEXP_USE_TRACK_ALLOC_TIMES
703     sexp_debug_alloc_times(ctx);
704 #endif
705 #if SEXP_USE_TRACK_ALLOC_SIZES
706     sexp_debug_alloc_sizes(ctx);
707 #endif
708     sexp_markedp(ctx) = 1;
709     sexp_markedp(sexp_context_globals(ctx)) = 1;
710     sexp_mark(ctx, sexp_global(ctx, SEXP_G_TYPES));
711     if (sexp_finalize(ctx) == SEXP_FALSE) { return SEXP_FALSE; }
712     sexp_sweep(ctx, &sum_freed);
713     if (sexp_finalize(ctx) == SEXP_FALSE) { return SEXP_FALSE; }
714     sexp_context_heap(ctx) = NULL;
715     for ( ; heap; heap=tmp) {
716       tmp = heap->next;
717       sexp_free_heap(heap);
718     }
719   }
720   return SEXP_TRUE;
721 }
722 #endif
723 
724 /***************************** exceptions *****************************/
725 
sexp_make_exception(sexp ctx,sexp kind,sexp message,sexp irritants,sexp procedure,sexp source)726 sexp sexp_make_exception (sexp ctx, sexp kind, sexp message, sexp irritants,
727                           sexp procedure, sexp source) {
728   sexp exn = sexp_alloc_type(ctx, exception, SEXP_EXCEPTION);
729   sexp_exception_kind(exn) = kind;
730   sexp_exception_message(exn) = message;
731   sexp_exception_irritants(exn) = irritants;
732   sexp_exception_procedure(exn) = procedure;
733   sexp_exception_source(exn) = source;
734   sexp_exception_stack_trace(exn) = SEXP_FALSE;
735   return exn;
736 }
737 
sexp_string_cat3(sexp ctx,const char * pre,const char * mid,const char * suf)738 sexp sexp_string_cat3 (sexp ctx, const char *pre, const char *mid, const char* suf) {
739   int plen=strlen(pre), mlen=strlen(mid), slen=strlen(suf);
740   char *s;
741   sexp str;
742   str = sexp_make_string(ctx, sexp_make_fixnum(plen+mlen+slen), SEXP_VOID);
743   memcpy(s=sexp_string_data(str), pre, plen);
744   memcpy(s+plen, mid, mlen);
745   memcpy(s+plen+mlen, suf, slen);
746   return str;
747 }
748 
sexp_user_exception(sexp ctx,sexp self,const char * ms,sexp ir)749 sexp sexp_user_exception (sexp ctx, sexp self, const char *ms, sexp ir) {
750   sexp res;
751   sexp_gc_var3(sym, str, irr);
752   sexp_gc_preserve3(ctx, sym, str, irr);
753   res = sexp_make_exception(ctx, sym = sexp_intern(ctx, "user", -1),
754                             str = sexp_c_string(ctx, ms, -1),
755                             ((sexp_pairp(ir) || sexp_nullp(ir))
756                              ? ir : (irr = sexp_list1(ctx, ir))),
757                             self, SEXP_FALSE);
758   sexp_gc_release3(ctx);
759   return res;
760 }
761 
sexp_user_exception_ls(sexp ctx,sexp self,const char * msg,int n,...)762 sexp sexp_user_exception_ls (sexp ctx, sexp self, const char *msg, int n, ...) {
763   int i;
764   va_list ap;
765   sexp_gc_var2(res, ir);
766   sexp_gc_preserve2(ctx, res, ir);
767   va_start(ap, n);
768   for (i=0, ir=SEXP_NULL; i < n; ++i) {
769     ir = sexp_cons(ctx, va_arg(ap, sexp), ir);
770   }
771   ir = sexp_nreverse(ctx, ir);
772   res = sexp_user_exception(ctx, self, msg, ir);
773   sexp_gc_release2(ctx);
774   va_end(ap);
775   return res;
776 }
777 
sexp_file_exception(sexp ctx,sexp self,const char * ms,sexp ir)778 sexp sexp_file_exception (sexp ctx, sexp self, const char *ms, sexp ir) {
779   sexp_gc_var1(res);
780   sexp_gc_preserve1(ctx, res);
781   res = sexp_user_exception(ctx, self, ms, ir);
782   sexp_exception_kind(res) = sexp_intern(ctx, "file", -1);
783   sexp_gc_release1(ctx);
784   return res;
785 }
786 
type_exception(sexp ctx,sexp self,sexp str,sexp obj,sexp src)787 static sexp type_exception (sexp ctx, sexp self, sexp str, sexp obj, sexp src) {
788   sexp_gc_var2(res, sym);
789   sexp_gc_preserve2(ctx, res, sym);
790   sym = sexp_intern(ctx, "type", -1);
791   res = sexp_make_exception(ctx, sym, str, obj, self, src);
792   sexp_exception_irritants(res)=sexp_list1(ctx, sexp_exception_irritants(res));
793   sexp_gc_release2(ctx);
794   return res;
795 }
796 
sexp_xtype_exception(sexp ctx,sexp self,const char * msg,sexp obj)797 sexp sexp_xtype_exception (sexp ctx, sexp self, const char *msg, sexp obj) {
798   sexp_gc_var1(res);
799   sexp_gc_preserve1(ctx, res);
800   res = sexp_c_string(ctx, msg, -1);
801   res = type_exception(ctx, self, res, obj, SEXP_FALSE);
802   sexp_gc_release1(ctx);
803   return res;
804 }
805 
sexp_type_exception(sexp ctx,sexp self,sexp_uint_t type_id,sexp obj)806 sexp sexp_type_exception (sexp ctx, sexp self, sexp_uint_t type_id, sexp obj) {
807   sexp_gc_var1(res);
808   sexp_gc_preserve1(ctx, res);
809   res = sexp_string_cat3(ctx, "invalid type, expected ",
810                          sexp_string_data(sexp_type_name_by_index(ctx, type_id)), "");
811   res = type_exception(ctx, self, res, obj, SEXP_FALSE);
812   sexp_gc_release1(ctx);
813   return res;
814 }
815 
sexp_range_exception(sexp ctx,sexp obj,sexp start,sexp end)816 sexp sexp_range_exception (sexp ctx, sexp obj, sexp start, sexp end) {
817   sexp_gc_var2(res, msg);
818   sexp_gc_preserve2(ctx, res, msg);
819   msg = sexp_c_string(ctx, "bad index range", -1);
820   res = sexp_list2(ctx, start, end);
821   res = sexp_cons(ctx, obj, res);
822   res = sexp_make_exception(ctx, sexp_intern(ctx, "range", -1), msg, res,
823                             SEXP_FALSE, SEXP_FALSE);
824   sexp_gc_release2(ctx);
825   return res;
826 }
827 
sexp_print_exception_op(sexp ctx,sexp self,sexp_sint_t n,sexp exn,sexp out)828 sexp sexp_print_exception_op (sexp ctx, sexp self, sexp_sint_t n, sexp exn, sexp out) {
829   sexp_gc_var2(ls, tmp);
830   /* unwrap continuable exceptions */
831   if (sexp_exceptionp(exn)
832       && ((sexp_exception_kind(exn) == sexp_global(ctx, SEXP_G_CONTINUABLE_SYMBOL)
833            && sexp_exceptionp(sexp_exception_irritants(exn)))
834           || sexp_exception_kind(exn) == SEXP_UNCAUGHT)) {
835     return sexp_print_exception_op(ctx, self, n, sexp_exception_irritants(exn), out);
836   }
837   sexp_gc_preserve2(ctx, ls, tmp);
838   if (! sexp_oportp(out))
839     out = tmp = sexp_make_output_port(ctx, stderr, SEXP_FALSE);
840   sexp_write_string(ctx, "ERROR", out);
841   if (sexp_exceptionp(exn)) {
842     if (sexp_exception_procedure(exn)) {
843       if (sexp_procedurep(sexp_exception_procedure(exn))) {
844         ls = sexp_bytecode_name(
845               sexp_procedure_code(sexp_exception_procedure(exn)));
846         if (ls && sexp_symbolp(ls)) {
847           sexp_write_string(ctx, " in ", out);
848           sexp_write(ctx, ls, out);
849         }
850       } else if (sexp_opcodep(sexp_exception_procedure(exn))) {
851         sexp_write_string(ctx, " in ", out);
852         sexp_write(ctx, sexp_opcode_name(sexp_exception_procedure(exn)), out);
853       }
854     }
855     ls = sexp_exception_source(exn);
856     if ((! (ls && sexp_pairp(ls)))
857         && sexp_exception_procedure(exn)
858         && sexp_procedurep(sexp_exception_procedure(exn)))
859       ls = sexp_bytecode_source(sexp_procedure_code(sexp_exception_procedure(exn)));
860     if (ls && sexp_pairp(ls)) {
861       if (sexp_fixnump(sexp_cdr(ls)) && (sexp_cdr(ls) >= SEXP_ZERO)) {
862         sexp_write_string(ctx, " on line ", out);
863         sexp_write(ctx, sexp_cdr(ls), out);
864       }
865       if (sexp_stringp(sexp_car(ls))) {
866         sexp_write_string(ctx, " of file ", out);
867         sexp_write_string(ctx, sexp_string_data(sexp_car(ls)), out);
868       }
869     }
870     sexp_write_string(ctx, ": ", out);
871     if (sexp_stringp(sexp_exception_message(exn)))
872       sexp_write_string(ctx, sexp_string_data(sexp_exception_message(exn)), out);
873     else
874       sexp_write(ctx, sexp_exception_message(exn), out);
875     if (sexp_exception_irritants(exn)
876         && sexp_pairp(sexp_exception_irritants(exn))) {
877       if (sexp_nullp(sexp_cdr(sexp_exception_irritants(exn)))) {
878         sexp_write_string(ctx, ": ", out);
879         sexp_write(ctx, sexp_car(sexp_exception_irritants(exn)), out);
880         sexp_write_string(ctx, "\n", out);
881       } else {
882         sexp_write_string(ctx, "\n", out);
883         for (ls=sexp_exception_irritants(exn);
884              sexp_pairp(ls); ls=sexp_cdr(ls)) {
885           sexp_write_string(ctx, "    ", out);
886           sexp_write(ctx, sexp_car(ls), out);
887           sexp_write_char(ctx, '\n', out);
888         }
889       }
890     } else {
891       sexp_write_char(ctx, '\n', out);
892     }
893   } else {
894     sexp_write_string(ctx, ": ", out);
895     if (sexp_stringp(exn))
896       sexp_write_string(ctx, sexp_string_data(exn), out);
897     else
898       sexp_write(ctx, exn, out);
899     sexp_write_char(ctx, '\n', out);
900   }
901   sexp_gc_release2(ctx);
902   return SEXP_VOID;
903 }
904 
sexp_read_error(sexp ctx,const char * msg,sexp ir,sexp port)905 sexp sexp_read_error (sexp ctx, const char *msg, sexp ir, sexp port) {
906   sexp res;
907   sexp_gc_var4(sym, name, str, irr);
908   sexp_gc_preserve4(ctx, sym, name, str, irr);
909   name = (sexp_port_name(port) ? sexp_port_name(port) : SEXP_FALSE);
910   name = sexp_cons(ctx, name, sexp_make_fixnum(sexp_port_line(port)));
911   str = sexp_c_string(ctx, msg, -1);
912   irr = ((sexp_pairp(ir) || sexp_nullp(ir)) ? ir : sexp_list1(ctx, ir));
913   res = sexp_make_exception(ctx, sym = sexp_intern(ctx, "read", -1),
914                             str, irr, SEXP_FALSE, name);
915   sexp_gc_release4(ctx);
916   return res;
917 }
918 
sexp_read_incomplete_error(sexp ctx,const char * msg,sexp ir,sexp port)919 sexp sexp_read_incomplete_error (sexp ctx, const char *msg, sexp ir, sexp port) {
920   sexp_gc_var1(res);
921   sexp_gc_preserve1(ctx, res);
922   res = sexp_read_error(ctx, msg, ir, port);
923   if (sexp_exceptionp(res))
924     sexp_exception_kind(res) = sexp_intern(ctx, "read-incomplete", -1);
925   sexp_gc_release1(ctx);
926   return res;
927 }
928 
929 /*************************** list utilities ***************************/
930 
sexp_cons_op(sexp ctx,sexp self,sexp_sint_t n,sexp head,sexp tail)931 sexp sexp_cons_op (sexp ctx, sexp self, sexp_sint_t n, sexp head, sexp tail) {
932   sexp pair = sexp_alloc_type(ctx, pair, SEXP_PAIR);
933   if (sexp_exceptionp(pair)) return pair;
934   sexp_car(pair) = head;
935   sexp_cdr(pair) = tail;
936   sexp_pair_source(pair) = SEXP_FALSE;
937   return pair;
938 }
939 
sexp_list2(sexp ctx,sexp a,sexp b)940 sexp sexp_list2 (sexp ctx, sexp a, sexp b) {
941   sexp_gc_var1(res);
942   sexp_gc_preserve1(ctx, res);
943   res = sexp_cons(ctx, b, SEXP_NULL);
944   res = sexp_cons(ctx, a, res);
945   sexp_gc_release1(ctx);
946   return res;
947 }
948 
sexp_list3(sexp ctx,sexp a,sexp b,sexp c)949 sexp sexp_list3 (sexp ctx, sexp a, sexp b, sexp c) {
950   sexp_gc_var1(res);
951   sexp_gc_preserve1(ctx, res);
952   res = sexp_list2(ctx, b, c);
953   res = sexp_cons(ctx, a, res);
954   sexp_gc_release1(ctx);
955   return res;
956 }
957 
sexp_listp_op(sexp ctx,sexp self,sexp_sint_t n,sexp hare)958 sexp sexp_listp_op (sexp ctx, sexp self, sexp_sint_t n, sexp hare) {
959   sexp turtle;
960   if (! sexp_pairp(hare))
961     return sexp_make_boolean(sexp_nullp(hare));
962   turtle = hare;
963   hare = sexp_cdr(hare);
964   for ( ; sexp_pairp(hare); turtle=sexp_cdr(turtle)) {
965     if (hare == turtle) return SEXP_FALSE;
966     hare = sexp_cdr(hare);
967     if (sexp_pairp(hare)) hare = sexp_cdr(hare);
968   }
969   return sexp_make_boolean(sexp_nullp(hare));
970 }
971 
sexp_memq_op(sexp ctx,sexp self,sexp_sint_t n,sexp x,sexp ls)972 sexp sexp_memq_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp ls) {
973   while (sexp_pairp(ls))
974     if (x == sexp_car(ls))
975       return ls;
976     else
977       ls = sexp_cdr(ls);
978   return SEXP_FALSE;
979 }
980 
sexp_assq_op(sexp ctx,sexp self,sexp_sint_t n,sexp x,sexp ls)981 sexp sexp_assq_op (sexp ctx, sexp self, sexp_sint_t n, sexp x, sexp ls) {
982   while (sexp_pairp(ls))
983     if (sexp_pairp(sexp_car(ls)) && (x == sexp_caar(ls)))
984       return sexp_car(ls);
985     else
986       ls = sexp_cdr(ls);
987   return SEXP_FALSE;
988 }
989 
sexp_reverse_op(sexp ctx,sexp self,sexp_sint_t n,sexp ls)990 sexp sexp_reverse_op (sexp ctx, sexp self, sexp_sint_t n, sexp ls) {
991   sexp_gc_var1(res);
992   sexp_gc_preserve1(ctx, res);
993   for (res=SEXP_NULL; sexp_pairp(ls); ls=sexp_cdr(ls))
994     res = sexp_cons(ctx, sexp_car(ls), res);
995   sexp_gc_release1(ctx);
996   return res;
997 }
998 
sexp_nreverse_op(sexp ctx,sexp self,sexp_sint_t n,sexp ls)999 sexp sexp_nreverse_op (sexp ctx, sexp self, sexp_sint_t n, sexp ls) {
1000   sexp a, b, tmp;
1001   if (ls == SEXP_NULL) return ls;
1002   sexp_assert_type(ctx, sexp_pairp, SEXP_PAIR, ls);
1003   b = ls;
1004   a = sexp_cdr(ls);
1005   sexp_cdr(b) = SEXP_NULL;
1006   for ( ; sexp_pairp(a); b=a, a=tmp) {
1007     tmp = sexp_cdr(a);
1008     sexp_cdr(a) = b;
1009   }
1010   return b;
1011 }
1012 
sexp_copy_list_op(sexp ctx,sexp self,sexp_sint_t n,sexp ls)1013 sexp sexp_copy_list_op (sexp ctx, sexp self, sexp_sint_t n, sexp ls) {
1014   sexp tmp;
1015   sexp_gc_var1(res);
1016   if (! sexp_pairp(ls)) return ls;
1017   sexp_gc_preserve1(ctx, res);
1018   tmp = res = sexp_cons(ctx, sexp_car(ls), sexp_cdr(ls));
1019   for (ls=sexp_cdr(ls); sexp_pairp(ls); ls=sexp_cdr(ls), tmp=sexp_cdr(tmp))
1020     sexp_cdr(tmp) = sexp_cons(ctx, sexp_car(ls), sexp_cdr(ls));
1021   sexp_gc_release1(ctx);
1022   return res;
1023 }
1024 
sexp_append2_op(sexp ctx,sexp self,sexp_sint_t n,sexp a,sexp b)1025 sexp sexp_append2_op (sexp ctx, sexp self, sexp_sint_t n, sexp a, sexp b) {
1026   sexp_gc_var2(a1, b1);
1027   sexp_gc_preserve2(ctx, a1, b1);
1028   b1 = b;
1029   for (a1=sexp_reverse(ctx, a); sexp_pairp(a1); a1=sexp_cdr(a1))
1030     b1 = sexp_cons(ctx, sexp_car(a1), b1);
1031   sexp_gc_release2(ctx);
1032   return b1;
1033 }
1034 
sexp_length_op(sexp ctx,sexp self,sexp_sint_t n,sexp ls1)1035 sexp sexp_length_op (sexp ctx, sexp self, sexp_sint_t n, sexp ls1) {
1036   sexp ls2;
1037   sexp_uint_t res = 1;
1038   if (!sexp_pairp(ls1))
1039     return SEXP_ZERO;
1040   for (ls2=sexp_cdr(ls1); sexp_pairp(ls2) && sexp_pairp(sexp_cdr(ls2));
1041        res+=2, ls1=sexp_cdr(ls1), ls2=sexp_cddr(ls2))
1042     if (ls1 == ls2)
1043       return SEXP_FALSE;
1044   return sexp_make_fixnum(res + (sexp_pairp(ls2) ? 1 : 0));
1045 }
1046 
sexp_equalp_bound(sexp ctx,sexp self,sexp_sint_t n,sexp a,sexp b,sexp depth,sexp bound)1047 sexp sexp_equalp_bound (sexp ctx, sexp self, sexp_sint_t n, sexp a, sexp b, sexp depth, sexp bound) {
1048   sexp_uint_t left_size, right_size;
1049   sexp_sint_t i, len;
1050   sexp t, *p, *q, depth2;
1051   char *p_left, *p_right, *q_left, *q_right;
1052 
1053  loop:
1054   if (a == b)
1055     return bound;
1056   else if ((!a || !sexp_pointerp(a)) || (!b || !sexp_pointerp(b))
1057            || (sexp_pointer_tag(a) != sexp_pointer_tag(b)))
1058     return SEXP_FALSE;
1059 
1060   /* a and b are both pointers of the same type */
1061 #if SEXP_USE_BIGNUMS
1062   if (sexp_pointer_tag(a) == SEXP_BIGNUM)
1063     return !sexp_bignum_compare(a, b) ? bound : SEXP_FALSE;
1064 #endif
1065 #if SEXP_USE_FLONUMS && ! SEXP_USE_IMMEDIATE_FLONUMS
1066   if (sexp_pointer_tag(a) == SEXP_FLONUM)
1067     return sexp_flonum_eqv(a, b) ? bound : SEXP_FALSE;
1068 #endif
1069   /* check limits */
1070   if (sexp_unbox_fixnum(bound) < 0 || sexp_unbox_fixnum(depth) < 0)
1071     return bound;
1072   depth2 = sexp_fx_sub(depth, SEXP_ONE);
1073   bound = sexp_fx_sub(bound, SEXP_ONE);
1074   t = sexp_object_type(ctx, a);
1075   p_left = ((char*)a) + offsetof(struct sexp_struct, value);
1076   p = (sexp*) (((char*)a) + sexp_type_field_base(t));
1077   q_left = ((char*)b) + offsetof(struct sexp_struct, value);
1078   q = (sexp*) (((char*)b) + sexp_type_field_base(t));
1079   /* if no fields, the base is value (just past the header) */
1080   if ((sexp)p == a) {p=(sexp*)p_left; q=(sexp*)q_left;}
1081   /* check preliminary non-object data */
1082   left_size = (char*)p - p_left;
1083   if ((left_size > 0) && memcmp(p_left, q_left, left_size))
1084     return SEXP_FALSE;
1085   /* check trailing non-object data */
1086   p_right = ((char*)p + sexp_type_num_slots_of_object(t,a)*sizeof(sexp));
1087   right_size = ((char*)a + sexp_type_size_of_object(t, a)) - p_right;
1088   if (right_size > 0) {
1089     q_right = ((char*)q + sexp_type_num_slots_of_object(t,b)*sizeof(sexp));
1090     if (right_size != ((char*)b + sexp_type_size_of_object(t, b)) - q_right)
1091       return SEXP_FALSE;
1092     if (memcmp(p_right, q_right, right_size))
1093       return SEXP_FALSE;
1094   }
1095   /* left and right non-object data is the same, now check eq-object slots */
1096   len = sexp_type_num_eq_slots_of_object(t, a);
1097   if (len > 0) {
1098     for (; len > 1; len--) {
1099       a = p[len-1]; b = q[len-1];
1100       if (a != b) {
1101         if ((!a || !sexp_pointerp(a)) || (!b || !sexp_pointerp(b))
1102             || (sexp_pointer_tag(a) != sexp_pointer_tag(b)))
1103           return SEXP_FALSE;
1104         else break;
1105       }
1106     }
1107     for (i=0; i<len-1; i++) {
1108       bound = sexp_equalp_bound(ctx, self, n, p[i], q[i], depth2, bound);
1109       if (sexp_not(bound)) return SEXP_FALSE;
1110     }
1111     /* tail-recurse on the last value (same depth) */
1112     a = p[len-1]; b = q[len-1]; goto loop;
1113   }
1114   return bound;
1115 }
1116 
sexp_equalp_op(sexp ctx,sexp self,sexp_sint_t n,sexp a,sexp b)1117 sexp sexp_equalp_op (sexp ctx, sexp self, sexp_sint_t n, sexp a, sexp b) {
1118   return sexp_make_boolean(
1119     sexp_truep(sexp_equalp_bound(ctx, self, n, a, b,
1120                                  sexp_make_fixnum(SEXP_DEFAULT_EQUAL_DEPTH),
1121                                  sexp_make_fixnum(SEXP_DEFAULT_EQUAL_BOUND))));
1122 }
1123 
1124 /********************* strings, symbols, vectors **********************/
1125 
sexp_flonump_op(sexp ctx,sexp self,sexp_sint_t n,sexp x)1126 sexp sexp_flonump_op (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
1127   return sexp_make_boolean(sexp_flonump(x));
1128 }
1129 
1130 #if ! SEXP_USE_IMMEDIATE_FLONUMS
sexp_make_flonum(sexp ctx,double f)1131 sexp sexp_make_flonum (sexp ctx, double f) {
1132   sexp x = sexp_alloc_type(ctx, flonum, SEXP_FLONUM);
1133   if (sexp_exceptionp(x)) return x;
1134   sexp_flonum_value(x) = f;
1135   return x;
1136 }
1137 #else
1138 #if SEXP_64_BIT
sexp_flonum_value(sexp x)1139 float sexp_flonum_value (sexp x) {
1140   union sexp_flonum_conv r;
1141   r.bits = (sexp_uint_t)x >> 32;
1142   return r.flonum;
1143 }
sexp_make_flonum(sexp ctx,float f)1144 sexp sexp_make_flonum (sexp ctx, float f) {
1145   union sexp_flonum_conv x;
1146   x.flonum = f;
1147   return (sexp)(((sexp_uint_t)(x.bits) << 32) + SEXP_IFLONUM_TAG);
1148 }
1149 #endif
1150 #endif
1151 
sexp_make_bytes_op(sexp ctx,sexp self,sexp_sint_t n,sexp len,sexp i)1152 sexp sexp_make_bytes_op (sexp ctx, sexp self, sexp_sint_t n, sexp len, sexp i) {
1153   sexp_sint_t clen = sexp_unbox_fixnum(len);
1154   sexp s;
1155   sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, len);
1156   if (clen < 0) return sexp_xtype_exception(ctx, self, "negative length", len);
1157   s = sexp_alloc_atomic(ctx, sexp_sizeof(bytes)+clen+1);
1158   if (sexp_exceptionp(s)) return s;
1159   sexp_pointer_tag(s) = SEXP_BYTES;
1160 #if SEXP_USE_HEADER_MAGIC
1161   sexp_pointer_magic(s) = SEXP_POINTER_MAGIC;
1162 #endif
1163   sexp_bytes_length(s) = clen;
1164   if (sexp_fixnump(i))
1165     memset(sexp_bytes_data(s), sexp_unbox_fixnum(i), clen);
1166   sexp_bytes_data(s)[clen] = '\0';
1167   return s;
1168 }
1169 
1170 #if SEXP_USE_UNIFORM_VECTOR_LITERALS
sexp_make_uvector_op(sexp ctx,sexp self,sexp_sint_t n,sexp elt_type,sexp len)1171 sexp sexp_make_uvector_op(sexp ctx, sexp self, sexp_sint_t n, sexp elt_type, sexp len) {
1172   sexp_sint_t etype = sexp_unbox_fixnum(elt_type), elen = sexp_unbox_fixnum(len), clen;
1173   sexp_gc_var1(res);
1174   if (etype == SEXP_U8)
1175     return sexp_make_bytes(ctx, len, SEXP_ZERO);
1176   sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, elt_type);
1177   sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, len);
1178   if (etype < SEXP_U1 || etype > SEXP_C128)
1179     return sexp_xtype_exception(ctx, self, "unknown uniform vector type", elt_type);
1180   if (elen < 0)
1181     return sexp_xtype_exception(ctx, self, "negative length", len);
1182   sexp_gc_preserve1(ctx, res);
1183   res = sexp_alloc_type(ctx, uvector, SEXP_UNIFORM_VECTOR);
1184   if (!sexp_exceptionp(res)) {
1185     clen = ((elen * sexp_uvector_element_size(etype)) + 7) / 8;
1186     sexp_uvector_type(res) = etype;
1187     sexp_uvector_length(res) = elen;
1188     sexp_uvector_bytes(res) = sexp_make_bytes(ctx, sexp_make_fixnum(clen), SEXP_ZERO);
1189     if (sexp_exceptionp(sexp_uvector_bytes(res)))
1190       res = sexp_uvector_bytes(res);
1191   }
1192   sexp_gc_release1(ctx);
1193   return res;
1194 }
1195 #endif
1196 
1197 #if SEXP_USE_UTF8_STRINGS
1198 
sexp_utf8_initial_byte_count(int c)1199 int sexp_utf8_initial_byte_count (int c) {
1200   if (c < 0xC0) return 1;
1201   if (c < 0xE0) return 2;
1202   return ((c>>4)&1)+3;
1203 }
1204 
sexp_utf8_char_byte_count(int c)1205 int sexp_utf8_char_byte_count (int c) {
1206   if (c < 0x80) return 1;
1207   if (c < 0x800) return 2;
1208   if (c < 0x10000) return 3;
1209   return 4;
1210 }
1211 
sexp_string_utf8_length(unsigned char * p,long len)1212 sexp_uint_t sexp_string_utf8_length (unsigned char *p, long len) {
1213   unsigned char *q = p+len;
1214   sexp_uint_t i;
1215   for (i=0; p<q; i++)
1216     p += sexp_utf8_initial_byte_count(*p);
1217   return i;
1218 }
1219 
sexp_string_utf8_prev(unsigned char * p)1220 char* sexp_string_utf8_prev (unsigned char *p) {
1221   while ((*--p)>>6 == 2)
1222     ;
1223   return (char*)p;
1224 }
1225 
sexp_string_utf8_ref(sexp ctx,sexp str,sexp i)1226 sexp sexp_string_utf8_ref (sexp ctx, sexp str, sexp i) {
1227   unsigned char *p=(unsigned char*)sexp_string_data(str) + sexp_unbox_string_cursor(i);
1228   if (*p < 0x80)
1229     return sexp_make_character(*p);
1230   else if ((*p < 0xC0) || (*p > 0xF7))
1231     return sexp_user_exception(ctx, NULL, "string-ref: invalid utf8 byte", i);
1232   else if (*p < 0xE0)
1233     return sexp_make_character(((p[0]&0x3F)<<6) + (p[1]&0x3F));
1234   else if (*p < 0xF0)
1235     return sexp_make_character(((p[0]&0x1F)<<12) + ((p[1]&0x3F)<<6) + (p[2]&0x3F));
1236   else
1237     return sexp_make_character(((p[0]&0x0F)<<18) + ((p[1]&0x3F)<<12) + ((p[2]&0x3F)<<6) + (p[3]&0x3F));
1238 }
1239 
sexp_utf8_encode_char(unsigned char * p,int len,int c)1240 void sexp_utf8_encode_char (unsigned char* p, int len, int c) {
1241   switch (len) {
1242   case 4:  *p++ = (0xF0 + ((c)>>18)); *p++ = (0x80 + ((c>>12)&0x3F));
1243     *p++ = (0x80 + ((c>>6)&0x3F));    *p = (0x80 + (c&0x3F)); break;
1244   case 3:  *p++ = (0xE0 + ((c)>>12)); *p++ = (0x80 + ((c>>6)&0x3F));
1245     *p = (0x80 + (c&0x3F)); break;
1246   case 2:  *p++ = (0xC0 + ((c)>>6));  *p = (0x80 + (c&0x3F)); break;
1247   default: *p = c; break;
1248   }
1249 }
1250 
sexp_string_index_to_cursor(sexp ctx,sexp self,sexp_sint_t n,sexp str,sexp index)1251 sexp sexp_string_index_to_cursor (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp index) {
1252 #if SEXP_USE_STRING_INDEX_TABLE
1253   sexp charlens;
1254   sexp_sint_t* chunklens;
1255   sexp_sint_t chunk;
1256 #endif
1257   sexp_sint_t i, j, limit;
1258   unsigned char *p;
1259   sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str);
1260   sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, index);
1261   p = (unsigned char*)sexp_string_data(str);
1262   limit = sexp_string_size(str);
1263   i = sexp_unbox_fixnum(index);
1264   j = 0;
1265 #if SEXP_USE_STRING_INDEX_TABLE
1266   if (i > SEXP_STRING_INDEX_TABLE_CHUNK_SIZE) {
1267     charlens = sexp_string_charlens(str);
1268     if (charlens) {
1269       chunklens = (sexp_sint_t*)sexp_bytes_data(charlens);
1270       chunk = i / SEXP_STRING_INDEX_TABLE_CHUNK_SIZE - 1;
1271       j = chunklens[chunk];
1272       i -= (chunk+1) * SEXP_STRING_INDEX_TABLE_CHUNK_SIZE;
1273     }
1274   }
1275 #endif
1276   for ( ; i>0 && j<limit; i--)
1277     j += sexp_utf8_initial_byte_count(p[j]);
1278   if (i != 0)
1279     return sexp_user_exception(ctx, self, "string-index->cursor: index out of range", index);
1280   return sexp_make_string_cursor(j);
1281 }
1282 
sexp_string_cursor_to_index(sexp ctx,sexp self,sexp_sint_t n,sexp str,sexp offset)1283 sexp sexp_string_cursor_to_index (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp offset) {
1284   sexp_sint_t off = sexp_unbox_string_cursor(offset);
1285   sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str);
1286   sexp_assert_type(ctx, sexp_string_cursorp, SEXP_STRING_CURSOR, offset);
1287   if (off < 0 || off > (sexp_sint_t)sexp_string_size(str))
1288     return sexp_user_exception(ctx, self, "string-cursor->index: offset out of range", offset);
1289   return sexp_make_fixnum(sexp_string_utf8_length((unsigned char*)sexp_string_data(str), off));
1290 }
1291 
sexp_string_cursor_offset(sexp ctx,sexp self,sexp_sint_t n,sexp cur)1292 sexp sexp_string_cursor_offset (sexp ctx, sexp self, sexp_sint_t n, sexp cur) {
1293   sexp_assert_type(ctx, sexp_string_cursorp, SEXP_STRING_CURSOR, cur);
1294   return sexp_make_fixnum(sexp_unbox_string_cursor(cur));
1295 }
1296 
1297 #endif
1298 
1299 #if SEXP_USE_STRING_INDEX_TABLE
sexp_update_string_index_lookup(sexp ctx,sexp s)1300 void sexp_update_string_index_lookup(sexp ctx, sexp s) {
1301   char *p;
1302   sexp_sint_t numchunks, len, i, *chunks;
1303   sexp_gc_var1(tmp);
1304   if (sexp_string_size(s) < SEXP_STRING_INDEX_TABLE_CHUNK_SIZE*1.2) {
1305     sexp_string_charlens(s) = NULL; /* don't build table for just a few chars */
1306     return;
1307   }
1308   sexp_gc_preserve1(ctx, tmp);
1309   tmp = s;
1310   len = sexp_string_utf8_length((unsigned char*) sexp_string_data(s), sexp_string_size(s));
1311   numchunks = ((len + SEXP_STRING_INDEX_TABLE_CHUNK_SIZE - 1) / SEXP_STRING_INDEX_TABLE_CHUNK_SIZE) - 1;
1312   sexp_string_charlens(s) =
1313     sexp_make_bytes_op(ctx, NULL, 2, sexp_make_fixnum(numchunks * sizeof(sexp_sint_t)), SEXP_VOID);
1314   chunks = (sexp_sint_t*)sexp_bytes_data(sexp_string_charlens(s));
1315   p = sexp_string_data(s);
1316   i = 0;
1317   while (1) {
1318     p += sexp_utf8_initial_byte_count(*p);
1319     if (++i % SEXP_STRING_INDEX_TABLE_CHUNK_SIZE == 0) {
1320       chunks[i/SEXP_STRING_INDEX_TABLE_CHUNK_SIZE - 1] = p - sexp_string_data(s);
1321       if (i / SEXP_STRING_INDEX_TABLE_CHUNK_SIZE >= numchunks-1)
1322         break;
1323     }
1324   }
1325   sexp_gc_release1(ctx);
1326 }
1327 #endif
1328 
sexp_make_string_op(sexp ctx,sexp self,sexp_sint_t n,sexp len,sexp ch)1329 sexp sexp_make_string_op (sexp ctx, sexp self, sexp_sint_t n, sexp len, sexp ch)
1330 {
1331   sexp i = (sexp_charp(ch) ? sexp_make_fixnum(sexp_unbox_character(ch)) : ch);
1332 #if SEXP_USE_PACKED_STRINGS
1333   sexp b;
1334 #else
1335   sexp_gc_var2(b, s);
1336 #endif
1337 #if SEXP_USE_UTF8_STRINGS
1338   int j, clen;
1339   if (sexp_charp(ch) && (sexp_unbox_character(ch) >= 0x80)) {
1340     sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, len);
1341     clen = sexp_utf8_char_byte_count(sexp_unbox_character(ch));
1342     b = sexp_make_bytes_op(ctx, self, n,
1343                            sexp_fx_mul(len, sexp_make_fixnum(clen)), SEXP_VOID);
1344     if (sexp_exceptionp(b)) return b;
1345     for (j=0; j<sexp_unbox_fixnum(len); j++)
1346       sexp_utf8_encode_char((unsigned char*)sexp_bytes_data(b)+(j*clen), clen,
1347                             sexp_unbox_character(ch));
1348   } else
1349 #endif
1350   b = sexp_make_bytes_op(ctx, self, n, len, i);
1351   if (sexp_exceptionp(b)) return b;
1352 #if SEXP_USE_PACKED_STRINGS
1353   sexp_pointer_tag(b) = SEXP_STRING;
1354   return b;
1355 #else
1356   sexp_gc_preserve2(ctx, b, s);
1357   s = sexp_alloc_type(ctx, string, SEXP_STRING);
1358   sexp_string_bytes(s) = b;
1359   sexp_string_offset(s) = 0;
1360   sexp_string_size(s) = sexp_bytes_length(b);
1361   sexp_update_string_index_lookup(ctx, s);
1362   sexp_gc_release2(ctx);
1363   return s;
1364 #endif
1365 }
1366 
sexp_c_string(sexp ctx,const char * str,sexp_sint_t slen)1367 sexp sexp_c_string (sexp ctx, const char *str, sexp_sint_t slen) {
1368   sexp_sint_t len;
1369   sexp s;
1370   if (str == NULL) return SEXP_FALSE;
1371   len = ((slen >= 0) ? slen : strlen(str));
1372   s = sexp_make_string(ctx, sexp_make_fixnum(len), SEXP_VOID);
1373   if (sexp_exceptionp(s)) return s;
1374   memcpy(sexp_string_data(s), str, len);
1375   sexp_string_data(s)[len] = '\0';
1376   sexp_update_string_index_lookup(ctx, s);
1377   return s;
1378 }
1379 
sexp_substring_op(sexp ctx,sexp self,sexp_sint_t n,sexp str,sexp start,sexp end)1380 sexp sexp_substring_op (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp start, sexp end) {
1381   sexp res;
1382   sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str);
1383   sexp_assert_type(ctx, sexp_string_cursorp, SEXP_STRING_CURSOR, start);
1384   if (sexp_not(end))
1385     end = sexp_make_string_cursor(sexp_string_size(str));
1386   sexp_assert_type(ctx, sexp_string_cursorp, SEXP_STRING_CURSOR, end);
1387   if ((sexp_unbox_string_cursor(start) < 0)
1388       || (sexp_unbox_string_cursor(start) > (sexp_sint_t)sexp_string_size(str))
1389       || (sexp_unbox_string_cursor(end) < 0)
1390       || (sexp_unbox_string_cursor(end) > (sexp_sint_t)sexp_string_size(str))
1391       || (end < start))
1392     return sexp_range_exception(ctx, str, start, end);
1393   res = sexp_make_string(ctx, sexp_make_fixnum(sexp_unbox_string_cursor(end) - sexp_unbox_string_cursor(start)), SEXP_VOID);
1394   memcpy(sexp_string_data(res),
1395          sexp_string_data(str)+sexp_unbox_string_cursor(start),
1396          sexp_string_size(res));
1397   sexp_string_data(res)[sexp_string_size(res)] = '\0';
1398   sexp_update_string_index_lookup(ctx, res);
1399   return res;
1400 }
1401 
sexp_subbytes_op(sexp ctx,sexp self,sexp_sint_t n,sexp vec,sexp start,sexp end)1402 sexp sexp_subbytes_op (sexp ctx, sexp self, sexp_sint_t n, sexp vec, sexp start, sexp end) {
1403   sexp res;
1404   sexp_gc_var1(str);
1405   sexp_assert_type(ctx, sexp_bytesp, SEXP_BYTES, vec);
1406   sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, start);
1407   if (sexp_not(end))
1408     end = sexp_make_fixnum(sexp_bytes_length(vec));
1409   sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, end);
1410   sexp_gc_preserve1(ctx, str);
1411 #if SEXP_USE_PACKED_STRINGS
1412   str = sexp_c_string(ctx, sexp_bytes_data(vec), sexp_bytes_length(vec));
1413 #else
1414   str = sexp_alloc_type(ctx, string, SEXP_STRING);
1415   sexp_string_bytes(str) = vec;
1416   sexp_string_offset(str) = 0;
1417   sexp_string_size(str) = sexp_bytes_length(vec);
1418 #endif
1419   res = sexp_substring_op(ctx, self, n, str, sexp_fixnum_to_string_cursor(start), sexp_fixnum_to_string_cursor(end));
1420   if (!sexp_exceptionp(res))
1421     res = sexp_string_to_bytes(ctx, res);
1422   sexp_gc_release1(ctx);
1423   return res;
1424 }
1425 
1426 #if SEXP_USE_UTF8_STRINGS
sexp_utf8_substring_op(sexp ctx,sexp self,sexp_sint_t n,sexp str,sexp start,sexp end)1427 sexp sexp_utf8_substring_op (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp start, sexp end) {
1428   sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str);
1429   sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, start);
1430   start = sexp_string_index_to_cursor(ctx, self, n, str, start);
1431   if (sexp_exceptionp(start)) return start;
1432   if (sexp_fixnump(end)) {
1433     end = sexp_string_index_to_cursor(ctx, self, n, str, end);
1434     if (sexp_exceptionp(end)) return end;
1435   }
1436   return sexp_substring_op(ctx, self, n, str, start, end);
1437 }
1438 #endif
1439 
sexp_string_concatenate_op(sexp ctx,sexp self,sexp_sint_t n,sexp str_ls,sexp sep)1440 sexp sexp_string_concatenate_op (sexp ctx, sexp self, sexp_sint_t n, sexp str_ls, sexp sep) {
1441   sexp res, ls;
1442   sexp_uint_t len=0, i=0, sep_len=0;
1443   char *p, *csep=NULL;
1444   for (ls=str_ls; sexp_pairp(ls); ls=sexp_cdr(ls), i++)
1445     if (! sexp_stringp(sexp_car(ls)))
1446       return sexp_type_exception(ctx, self, SEXP_STRING, sexp_car(ls));
1447     else
1448       len += sexp_string_size(sexp_car(ls));
1449   if ((i > 0) && sexp_stringp(sep) && ((sep_len=sexp_string_size(sep)) > 0)) {
1450     csep = sexp_string_data(sep);
1451     len += sep_len*(i-1);
1452   }
1453   res = sexp_make_string(ctx, sexp_make_fixnum(len), SEXP_VOID);
1454   p = sexp_string_data(res);
1455   for (ls=str_ls; sexp_pairp(ls); ls=sexp_cdr(ls)) {
1456     len = sexp_string_size(sexp_car(ls));
1457     memcpy(p, sexp_string_data(sexp_car(ls)), len);
1458     p += len;
1459     if (sep_len && sexp_pairp(sexp_cdr(ls))) {
1460       memcpy(p, csep, sep_len);
1461       p += sep_len;
1462     }
1463   }
1464   *p = '\0';
1465   sexp_update_string_index_lookup(ctx, res);
1466   return res;
1467 }
1468 
1469 #define FNV_PRIME 16777619
1470 #define FNV_OFFSET_BASIS ((sexp_sint_t)2166136261)
1471 
1472 #if SEXP_USE_HASH_SYMS
1473 
sexp_string_hash(const char * str,sexp_sint_t len,sexp_uint_t acc)1474 static sexp_uint_t sexp_string_hash(const char *str, sexp_sint_t len,
1475                                     sexp_uint_t acc) {
1476   for ( ; len; len--) {acc *= FNV_PRIME; acc ^= *str++;}
1477   return acc;
1478 }
1479 
1480 #endif
1481 
sexp_intern(sexp ctx,const char * str,sexp_sint_t len)1482 sexp sexp_intern(sexp ctx, const char *str, sexp_sint_t len) {
1483 #if SEXP_USE_HUFF_SYMS
1484   struct sexp_huff_entry he;
1485   sexp_sint_t space, newbits;
1486   char c;
1487 #endif
1488   sexp ls, tmp;
1489   sexp_gc_var1(sym);
1490   sexp_sint_t bucket=0;
1491 #if (SEXP_USE_HASH_SYMS || SEXP_USE_HUFF_SYMS)
1492   sexp_sint_t i=0, res=FNV_OFFSET_BASIS;
1493   const char *p=str;
1494 #endif
1495 
1496   if (len < 0) len = strlen(str);
1497 
1498 #if SEXP_USE_HUFF_SYMS
1499   res = 0;
1500   space = SEXP_IMMEDIATE_BITS;
1501   if (len == 0 || sexp_isdigit((unsigned char)p[0])
1502       || ((p[0] == '+' || p[0] == '-') && len > 1))
1503     goto normal_intern;
1504   for ( ; i<len; i++, p++) {
1505     c = *p;
1506     if ((unsigned char)c <= 32 || (unsigned char)c > 127 || c == '\\' || c == '|' || c == '.' || c =='#' || sexp_is_separator(c))
1507       goto normal_intern;
1508     he = huff_table[(unsigned char)c];
1509     newbits = he.len;
1510     if ((space+newbits) > (sizeof(sexp)*8))
1511       goto normal_intern;
1512     res |= (((sexp_uint_t) he.bits) << space);
1513     space += newbits;
1514   }
1515   return (sexp) (res + SEXP_ISYMBOL_TAG);
1516 
1517  normal_intern:
1518 #endif
1519 #if SEXP_USE_HASH_SYMS
1520   bucket = (sexp_string_hash(p, len-i, res) % SEXP_SYMBOL_TABLE_SIZE);
1521 #endif
1522   for (ls=sexp_context_symbols(ctx)[bucket]; sexp_pairp(ls); ls=sexp_cdr(ls))
1523     if ((sexp_lsymbol_length(tmp=sexp_car(ls)) == len)
1524         && ! strncmp(str, sexp_lsymbol_data(tmp), len))
1525       return sexp_car(ls);
1526 
1527   /* not found, make a new symbol */
1528   sexp_gc_preserve1(ctx, sym);
1529   sym = sexp_c_string(ctx, str, len);
1530   if (sexp_exceptionp(sym)) return sym;
1531 #if ! SEXP_USE_PACKED_STRINGS
1532   sym = sexp_string_bytes(sym);
1533 #endif
1534   sexp_pointer_tag(sym) = SEXP_SYMBOL;
1535   sexp_push(ctx, sexp_context_symbols(ctx)[bucket], sym);
1536   sexp_gc_release1(ctx);
1537   return sym;
1538 }
1539 
sexp_string_to_symbol_op(sexp ctx,sexp self,sexp_sint_t n,sexp str)1540 sexp sexp_string_to_symbol_op (sexp ctx, sexp self, sexp_sint_t n, sexp str) {
1541   sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str);
1542   return sexp_intern(ctx, sexp_string_data(str), sexp_string_size(str));
1543 }
1544 
sexp_make_vector_op(sexp ctx,sexp self,sexp_sint_t n,sexp len,sexp dflt)1545 sexp sexp_make_vector_op (sexp ctx, sexp self, sexp_sint_t n, sexp len, sexp dflt) {
1546   sexp vec, *x;
1547   sexp_sint_t i, clen = sexp_unbox_fixnum(len);
1548   if (! clen) return sexp_global(ctx, SEXP_G_EMPTY_VECTOR);
1549   if (clen < 0 || clen > SEXP_MAX_VECTOR_LENGTH)
1550     return sexp_xtype_exception(ctx, self, "vector length out of range", len);
1551   vec = sexp_alloc_tagged(ctx, sexp_sizeof(vector) + clen*sizeof(sexp),
1552                           SEXP_VECTOR);
1553   if (sexp_exceptionp(vec)) return vec;
1554   x = sexp_vector_data(vec);
1555   for (i=0; i<clen; i++)
1556     x[i] = dflt;
1557   sexp_vector_length(vec) = clen;
1558   return vec;
1559 }
1560 
sexp_list_to_vector_op(sexp ctx,sexp self,sexp_sint_t n,sexp ls)1561 sexp sexp_list_to_vector_op (sexp ctx, sexp self, sexp_sint_t n, sexp ls) {
1562   int i;
1563   sexp x, *elts, vec = sexp_make_vector(ctx, sexp_length(ctx, ls), SEXP_VOID);
1564   if (sexp_exceptionp(vec)) return vec;
1565   elts = sexp_vector_data(vec);
1566   for (i=0, x=ls; sexp_pairp(x); i++, x=sexp_cdr(x))
1567     elts[i] = sexp_car(x);
1568   return vec;
1569 }
1570 
sexp_make_cpointer(sexp ctx,sexp_uint_t type_id,void * value,sexp parent,int freep)1571 sexp sexp_make_cpointer (sexp ctx, sexp_uint_t type_id, void *value,
1572                          sexp parent, int freep) {
1573   sexp ptr;
1574   if (! value) return SEXP_FALSE;
1575   ptr = sexp_alloc_type(ctx, cpointer, type_id);
1576   if (sexp_exceptionp(ptr)) return ptr;
1577   sexp_freep(ptr) = freep;
1578   sexp_cpointer_value(ptr) = value;
1579   sexp_cpointer_parent(ptr) = parent;
1580   sexp_cpointer_length(ptr) = 0;
1581   return ptr;
1582 }
1583 
1584 /************************ reading and writing *************************/
1585 
1586 /* start 4 bytes in so we can always unread a utf8 char in peek-char */
1587 #define BUF_START 4
1588 
sexp_buffered_read_char(sexp ctx,sexp p)1589 int sexp_buffered_read_char (sexp ctx, sexp p) {
1590   sexp_gc_var2(tmp, origbytes);
1591   int res = 0;
1592   if (sexp_port_offset(p) < sexp_port_size(p)) {
1593     return ((unsigned char*)sexp_port_buf(p))[sexp_port_offset(p)++];
1594   } else if (!sexp_port_openp(p)) {
1595     return EOF;
1596   } else if (sexp_port_stream(p)) {
1597     res = fread(sexp_port_buf(p) + BUF_START, 1, SEXP_PORT_BUFFER_SIZE - BUF_START, sexp_port_stream(p));
1598     if (res >= 0) {
1599       sexp_port_offset(p) = BUF_START;
1600       sexp_port_size(p) = res + BUF_START;
1601       res = ((sexp_port_offset(p) < sexp_port_size(p))
1602              ? ((unsigned char*)sexp_port_buf(p))[sexp_port_offset(p)++] : EOF);
1603     }
1604   } else if (sexp_filenop(sexp_port_fd(p))) {
1605     res = read(sexp_port_fileno(p), sexp_port_buf(p) + BUF_START, SEXP_PORT_BUFFER_SIZE - BUF_START);
1606     if (res >= 0) {
1607       sexp_port_offset(p) = BUF_START;
1608       sexp_port_size(p) = res + BUF_START;
1609       res = ((sexp_port_offset(p) < sexp_port_size(p))
1610              ? ((unsigned char*)sexp_port_buf(p))[sexp_port_offset(p)++] : EOF);
1611     }
1612   } else if (sexp_port_customp(p)) {
1613     sexp_gc_preserve2(ctx, tmp, origbytes);
1614     tmp = sexp_list2(ctx, sexp_make_fixnum(BUF_START), sexp_make_fixnum(SEXP_PORT_BUFFER_SIZE));
1615     origbytes = sexp_port_binaryp(p) && !SEXP_USE_PACKED_STRINGS ? sexp_string_bytes(sexp_port_buffer(p)) : sexp_port_buffer(p);
1616     tmp = sexp_cons(ctx, origbytes, tmp);
1617     tmp = sexp_apply(ctx, sexp_port_reader(p), tmp);
1618     if (sexp_fixnump(tmp) && sexp_unbox_fixnum(tmp) > BUF_START) {
1619       sexp_port_offset(p) = BUF_START;
1620       sexp_port_size(p) = sexp_unbox_fixnum(tmp);
1621       if (!sexp_port_binaryp(p) && !SEXP_USE_PACKED_STRINGS
1622           && origbytes != sexp_string_bytes(sexp_port_buffer(p))) {
1623         /* handle resize */
1624         memcpy(sexp_port_buf(p), sexp_string_data(sexp_port_buffer(p)), sexp_port_size(p));
1625       }
1626       res = ((sexp_port_offset(p) < sexp_port_size(p))
1627              ? ((unsigned char*)sexp_port_buf(p))[sexp_port_offset(p)++] : EOF);
1628     } else {
1629       res = EOF;
1630       sexp_port_size(p) = 0;
1631     }
1632     sexp_gc_release2(ctx);
1633   } else {
1634     res = EOF;
1635   }
1636   return res;
1637 }
1638 
sexp_buffered_write_char(sexp ctx,int c,sexp p)1639 int sexp_buffered_write_char (sexp ctx, int c, sexp p) {
1640   int res;
1641   if (sexp_port_offset(p)+1 >= sexp_port_size(p))
1642     if ((res = sexp_buffered_flush(ctx, p, 0)))
1643       return res;
1644   sexp_port_buf(p)[sexp_port_offset(p)++] = c;
1645   return 0;
1646 }
1647 
sexp_buffered_write_string_n(sexp ctx,const char * str,sexp_uint_t len,sexp p)1648 int sexp_buffered_write_string_n (sexp ctx, const char *str,
1649                                   sexp_uint_t len, sexp p) {
1650   int diff, res, written=0;
1651   while (sexp_port_offset(p)+len >= sexp_port_size(p)) {
1652     diff = sexp_port_size(p) - sexp_port_offset(p);
1653     memcpy(sexp_port_buf(p)+sexp_port_offset(p), str, diff);
1654     sexp_port_offset(p) = sexp_port_size(p);
1655     if ((res = sexp_buffered_flush(ctx, p, 0)))
1656       return written + diff;
1657     written += sexp_port_size(p);
1658     str += diff;
1659     len -= diff;
1660   }
1661   memcpy(sexp_port_buf(p)+sexp_port_offset(p), str, len);
1662   sexp_port_offset(p) += len;
1663   return written + len;
1664 }
1665 
sexp_buffered_write_string(sexp ctx,const char * str,sexp p)1666 int sexp_buffered_write_string (sexp ctx, const char *str, sexp p) {
1667   return sexp_buffered_write_string_n(ctx, str, strlen(str), p);
1668 }
1669 
sexp_buffered_flush(sexp ctx,sexp p,int forcep)1670 int sexp_buffered_flush (sexp ctx, sexp p, int forcep) {
1671   sexp_sint_t res = 0, off;
1672   sexp_gc_var1(tmp);
1673   if (!sexp_oportp(p) || (!forcep && !sexp_port_openp(p)))
1674     return -1;
1675   off = sexp_port_offset(p);
1676   if (sexp_port_stream(p)) {
1677     if (off > 0) fwrite(sexp_port_buf(p), 1, off, sexp_port_stream(p));
1678     res = fflush(sexp_port_stream(p));
1679   } else if (sexp_filenop(sexp_port_fd(p))) {
1680     if (off > 0)
1681       res = write(sexp_fileno_fd(sexp_port_fd(p)), sexp_port_buf(p), off);
1682     if (res < off) {
1683       if (res > 0) {
1684         memmove(sexp_port_buf(p), sexp_port_buf(p) + res, off - res);
1685         sexp_port_offset(p) = off - res;
1686         res = 0;
1687       } else {
1688         res = -1;
1689       }
1690     } else {
1691       sexp_port_offset(p) = 0;
1692       res = 0;
1693     }
1694   } else if (!sexp_port_openp(p)) {
1695     return -1;
1696   } else if (sexp_port_offset(p) > 0) {
1697     sexp_gc_preserve1(ctx, tmp);
1698     if (sexp_port_customp(p)) {   /* custom port */
1699       tmp = sexp_list2(ctx, SEXP_ZERO, sexp_make_fixnum(sexp_port_offset(p)));
1700       tmp = sexp_cons(ctx, sexp_port_binaryp(p) ? sexp_string_bytes(sexp_port_buffer(p)) : sexp_port_buffer(p), tmp);
1701       tmp = sexp_apply(ctx, sexp_port_writer(p), tmp);
1702       sexp_port_offset(p) = 0;
1703       res = (sexp_fixnump(tmp) && sexp_unbox_fixnum(tmp) > 0) ? 0 : -1;
1704     } else {                      /* string port */
1705       tmp = sexp_c_string(ctx, sexp_port_buf(p), off);
1706       if (tmp && sexp_stringp(tmp)) {
1707         sexp_push(ctx, sexp_cdr(sexp_port_cookie(p)), tmp);
1708         sexp_port_offset(p) = 0;
1709         res = 0;
1710       } else {
1711         res = -1;
1712       }
1713     }
1714     sexp_gc_release1(ctx);
1715   }
1716   return res;
1717 }
1718 
sexp_open_input_string_op(sexp ctx,sexp self,sexp_sint_t n,sexp str)1719 sexp sexp_open_input_string_op (sexp ctx, sexp self, sexp_sint_t n, sexp str) {
1720   sexp res;
1721   sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str);
1722   res = sexp_make_input_port(ctx, NULL, SEXP_FALSE);
1723   if (sexp_exceptionp(res)) return res;
1724   sexp_port_cookie(res) = str;
1725   sexp_port_buf(res) = sexp_string_data(str);
1726   sexp_port_offset(res) = 0;
1727   sexp_port_size(res) = sexp_string_size(str);
1728   sexp_port_binaryp(res) = 0;
1729   return res;
1730 }
1731 
sexp_open_output_string_op(sexp ctx,sexp self,sexp_sint_t n)1732 sexp sexp_open_output_string_op (sexp ctx, sexp self, sexp_sint_t n) {
1733   sexp_gc_var1(res);
1734   sexp_gc_preserve1(ctx, res);
1735   res = sexp_make_output_port(ctx, NULL, SEXP_FALSE);
1736   if (!sexp_exceptionp(res)) {
1737     sexp_port_cookie(res) = sexp_cons(ctx, SEXP_FALSE, SEXP_NULL);
1738     sexp_car(sexp_port_cookie(res)) =
1739       sexp_make_bytes(ctx, sexp_make_fixnum(SEXP_PORT_BUFFER_SIZE), SEXP_VOID);
1740     if (sexp_exceptionp(sexp_car(sexp_port_cookie(res)))) {
1741       res = sexp_car(sexp_port_cookie(res));
1742     } else {
1743       sexp_port_buf(res) = sexp_bytes_data(sexp_car(sexp_port_cookie(res)));
1744       sexp_port_size(res) = SEXP_PORT_BUFFER_SIZE;
1745       sexp_port_offset(res) = 0;
1746       sexp_port_binaryp(res) = 0;
1747     }
1748   }
1749   sexp_gc_release1(ctx);
1750   return res;
1751 }
1752 
sexp_get_output_string_op(sexp ctx,sexp self,sexp_sint_t n,sexp out)1753 sexp sexp_get_output_string_op (sexp ctx, sexp self, sexp_sint_t n, sexp out) {
1754   sexp res;
1755   sexp_gc_var3(ls, rev, tmp);
1756   sexp_assert_type(ctx, sexp_oportp, SEXP_OPORT, out);
1757   if (!sexp_port_openp(out))
1758     return sexp_xtype_exception(ctx, self, "output port is closed", out);
1759   if (!sexp_pairp(sexp_port_cookie(out)))
1760     return sexp_xtype_exception(ctx, self, "not a string output port", out);
1761   sexp_gc_preserve3(ctx, ls, rev, tmp);
1762   if (sexp_port_offset(out) > 0) {
1763     tmp = sexp_c_string(ctx, sexp_port_buf(out), sexp_port_offset(out));
1764     rev = sexp_cons(ctx, tmp, sexp_cdr(sexp_port_cookie(out)));
1765   } else {
1766     rev = sexp_cdr(sexp_port_cookie(out));
1767   }
1768   ls = sexp_reverse(ctx, rev);
1769   res = SEXP_FALSE;
1770   for (tmp = ls; sexp_pairp(tmp); tmp = sexp_cdr(tmp))
1771     if (!sexp_stringp(sexp_car(tmp)))
1772       res = sexp_xtype_exception(ctx, self, "not an output string port", out);
1773   if (!sexp_nullp(tmp))
1774     res = sexp_xtype_exception(ctx, self, "not an output string port", out);
1775   if (!sexp_exceptionp(res))
1776     res = sexp_string_concatenate(ctx, ls, SEXP_FALSE);
1777   sexp_gc_release3(ctx);
1778   return res;
1779 }
1780 
sexp_open_input_file_descriptor(sexp ctx,sexp self,sexp_sint_t n,sexp fileno,sexp shutdownp)1781 sexp sexp_open_input_file_descriptor (sexp ctx, sexp self, sexp_sint_t n, sexp fileno, sexp shutdownp) {
1782   sexp_gc_var2(res, str);
1783   sexp_assert_type(ctx, sexp_filenop, SEXP_FILENO, fileno);
1784   if (sexp_fileno_fd(fileno) < 0)
1785     return sexp_file_exception(ctx, self, "invalid file descriptor", fileno);
1786   sexp_gc_preserve2(ctx, res, str);
1787   str = sexp_make_string(ctx, sexp_make_fixnum(SEXP_PORT_BUFFER_SIZE), SEXP_VOID);
1788   res = sexp_open_input_string(ctx, str);
1789   if (!sexp_exceptionp(res)) {
1790     sexp_port_fd(res) = fileno;
1791     sexp_port_offset(res) = SEXP_PORT_BUFFER_SIZE;
1792     sexp_port_binaryp(res) = 1;
1793     sexp_port_shutdownp(res) = sexp_truep(shutdownp);
1794     sexp_fileno_count(fileno)++;
1795   }
1796   sexp_gc_release2(ctx);
1797   return res;
1798 }
1799 
sexp_open_output_file_descriptor(sexp ctx,sexp self,sexp_sint_t n,sexp fileno,sexp shutdownp)1800 sexp sexp_open_output_file_descriptor (sexp ctx, sexp self, sexp_sint_t n, sexp fileno, sexp shutdownp) {
1801   sexp res = sexp_open_input_file_descriptor(ctx, self, n, fileno, shutdownp);
1802   if (!sexp_exceptionp(res)) {
1803     sexp_pointer_tag(res) = SEXP_OPORT;
1804     sexp_port_offset(res) = 0;
1805   }
1806   return res;
1807 }
1808 
1809 #if SEXP_USE_WEAK_REFERENCES
sexp_make_ephemeron_op(sexp ctx,sexp self,sexp_sint_t n,sexp key,sexp value)1810 sexp sexp_make_ephemeron_op(sexp ctx, sexp self, sexp_sint_t n, sexp key, sexp value) {
1811   sexp res = sexp_alloc_type(ctx, pair, SEXP_EPHEMERON);
1812   if (!sexp_exceptionp(res)) {
1813     sexp_global(ctx, SEXP_G_WEAK_OBJECTS_PRESENT) = SEXP_TRUE;
1814     sexp_ephemeron_key(res) = key;
1815     sexp_ephemeron_value(res) = value;
1816   }
1817   return res;
1818 }
1819 #endif /* SEXP_USE_WEAK_REFERENCES */
1820 
1821 #if SEXP_USE_UNIFY_FILENOS_BY_NUMBER
sexp_fileno_cell(sexp ctx,sexp vec,int fd)1822 static sexp* sexp_fileno_cell(sexp ctx, sexp vec, int fd) {
1823   sexp *data;
1824   sexp_sint_t i, cell, len;
1825   if (!sexp_vectorp(vec))
1826     return NULL;
1827   len = sexp_vector_length(vec);
1828   if (len == 0)
1829     return NULL;
1830   data = sexp_vector_data(vec);
1831   cell = (fd * FNV_PRIME) % len;
1832   if (cell < 0) cell += len;
1833   for (i = 0; i < len; i++, cell=(cell+1)%len)
1834     if (!sexp_ephemeronp(data[cell])
1835         || (sexp_filenop(sexp_ephemeron_key(data[cell]))
1836             && sexp_fileno_fd(sexp_ephemeron_key(data[cell])) == fd))
1837         return &(data[cell]);
1838   return NULL;
1839 }
1840 
sexp_lookup_fileno(sexp ctx,int fd)1841 static sexp sexp_lookup_fileno(sexp ctx, int fd) {
1842   sexp* cell = sexp_fileno_cell(ctx, sexp_global(ctx, SEXP_G_FILE_DESCRIPTORS), fd);
1843   if (cell && sexp_ephemeronp(*cell)
1844       && sexp_filenop(sexp_ephemeron_key(*cell))
1845       && sexp_fileno_fd(sexp_ephemeron_key(*cell)) == fd) {
1846     if (sexp_fileno_openp(sexp_ephemeron_key(*cell)))
1847       return sexp_ephemeron_key(*cell);
1848   }
1849   return SEXP_FALSE;
1850 }
1851 
sexp_insert_fileno_ephemeron(sexp ctx,sexp vec,sexp eph)1852 static sexp* sexp_insert_fileno_ephemeron(sexp ctx, sexp vec, sexp eph) {
1853   sexp *data = sexp_fileno_cell(ctx, vec, sexp_fileno_fd(sexp_ephemeron_key(eph)));
1854   if (data) *data = eph;
1855   return data;
1856 }
1857 
sexp_insert_fileno(sexp ctx,sexp fileno)1858 static void sexp_insert_fileno(sexp ctx, sexp fileno) {
1859   sexp *data, tmp, vec = sexp_global(ctx, SEXP_G_FILE_DESCRIPTORS);
1860   sexp_sint_t i, n2, n = sexp_unbox_fixnum(sexp_global(ctx, SEXP_G_NUM_FILE_DESCRIPTORS));
1861   if (!sexp_vectorp(vec)) {
1862     vec = sexp_global(ctx, SEXP_G_FILE_DESCRIPTORS)
1863         = sexp_make_vector(ctx, sexp_make_fixnum(128), SEXP_FALSE);
1864   } else if (n >= (sexp_sint_t)sexp_vector_length(vec)) {
1865     data = sexp_vector_data(vec);
1866     for (i = n2 = 0; i < (sexp_sint_t)sexp_vector_length(vec); i++)
1867       if (sexp_ephemeronp(data[i]) && !sexp_brokenp(data[i]))
1868         n2++;
1869     if (n2 * 2 >= n)
1870       n2 = n * 2;
1871     tmp = sexp_global(ctx, SEXP_G_FILE_DESCRIPTORS)
1872         = sexp_make_vector(ctx, sexp_make_fixnum(n2), SEXP_FALSE);
1873     for (i = n = 0; i < (sexp_sint_t)sexp_vector_length(vec); i++)
1874       if (sexp_ephemeronp(data[i]) && !sexp_brokenp(data[i])
1875           && sexp_insert_fileno_ephemeron(ctx, tmp, data[i]))
1876         n++;
1877     vec = tmp;
1878   }
1879   if (sexp_insert_fileno_ephemeron(ctx, sexp_global(ctx, SEXP_G_FILE_DESCRIPTORS), sexp_make_ephemeron(ctx, fileno, SEXP_FALSE)))
1880     n++;
1881   sexp_global(ctx, SEXP_G_NUM_FILE_DESCRIPTORS) = sexp_make_fixnum(n);
1882 }
1883 #endif  /* SEXP_USE_UNIFY_FILENOS_BY_NUMBER */
1884 
sexp_make_fileno_op(sexp ctx,sexp self,sexp_sint_t n,sexp fd,sexp no_closep)1885 sexp sexp_make_fileno_op (sexp ctx, sexp self, sexp_sint_t n, sexp fd, sexp no_closep) {
1886   sexp_gc_var1(res);
1887   sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, fd);
1888   if (sexp_unbox_fixnum(fd) < 0) return SEXP_FALSE;
1889 #if SEXP_USE_UNIFY_FILENOS_BY_NUMBER
1890   res = sexp_lookup_fileno(ctx, sexp_unbox_fixnum(fd));
1891   if (sexp_filenop(res)) {
1892     sexp_fileno_no_closep(res) = sexp_truep(no_closep);
1893     sexp_fileno_openp(res) = 1;  /* not necessarily */
1894     return res;
1895   }
1896 #endif
1897   sexp_gc_preserve1(ctx, res);
1898   res = sexp_alloc_type(ctx, fileno, SEXP_FILENO);
1899   if (!sexp_exceptionp(res)) {
1900     sexp_fileno_fd(res) = sexp_unbox_fixnum(fd);
1901     sexp_fileno_openp(res) = 1;
1902     sexp_fileno_no_closep(res) = sexp_truep(no_closep);
1903 #if SEXP_USE_UNIFY_FILENOS_BY_NUMBER
1904     sexp_insert_fileno(ctx, res);
1905 #endif
1906   }
1907   sexp_gc_release1(ctx);
1908   return res;
1909 }
1910 
sexp_make_input_port(sexp ctx,FILE * in,sexp name)1911 sexp sexp_make_input_port (sexp ctx, FILE* in, sexp name) {
1912   sexp p = sexp_alloc_type(ctx, port, SEXP_IPORT);
1913   if (sexp_exceptionp(p)) return p;
1914   sexp_port_stream(p) = in;
1915   sexp_port_name(p) = name;
1916   sexp_port_line(p) = 1;
1917   sexp_port_flags(p) = SEXP_PORT_UNKNOWN_FLAGS;
1918   sexp_port_buf(p) = NULL;
1919   sexp_port_fd(p) = SEXP_FALSE;
1920   sexp_port_openp(p) = 1;
1921   sexp_port_bidirp(p) = 0;
1922   sexp_port_binaryp(p) = 1;
1923   sexp_port_shutdownp(p) = 0;
1924   sexp_port_no_closep(p) = 0;
1925   sexp_port_sourcep(p) = 0;
1926   sexp_port_blockedp(p) = 0;
1927 #if SEXP_USE_FOLD_CASE_SYMS
1928   sexp_port_fold_casep(p) = sexp_truep(sexp_global(ctx, SEXP_G_FOLD_CASE_P));
1929 #endif
1930 #if SEXP_USE_UNIFY_FILENOS_BY_NUMBER
1931   /* if the fd was previously opened by a non-stream port, preserve it */
1932   /* here to avoid gc timing issues */
1933   if (in && fileno(in) >= 0) {
1934     sexp_port_fd(p) = sexp_lookup_fileno(ctx, fileno(in));
1935     if (sexp_filenop(sexp_port_fd(p))) {
1936       sexp_fileno_openp(sexp_port_fd(p)) = 1;
1937       ++sexp_fileno_count(sexp_port_fd(p));
1938     }
1939   }
1940 #endif
1941   sexp_port_cookie(p) = SEXP_VOID;
1942   return p;
1943 }
1944 
sexp_make_output_port(sexp ctx,FILE * out,sexp name)1945 sexp sexp_make_output_port (sexp ctx, FILE* out, sexp name) {
1946   sexp p = sexp_make_input_port(ctx, out, name);
1947   if (sexp_exceptionp(p)) return p;
1948   sexp_pointer_tag(p) = SEXP_OPORT;
1949   return p;
1950 }
1951 
sexp_make_non_null_input_port(sexp ctx,FILE * in,sexp name)1952 sexp sexp_make_non_null_input_port (sexp ctx, FILE* in, sexp name) {
1953   if (!in) return sexp_user_exception(ctx, SEXP_FALSE, "null input-port", name);
1954   return sexp_make_input_port(ctx, in, name);
1955 }
1956 
sexp_make_non_null_output_port(sexp ctx,FILE * out,sexp name)1957 sexp sexp_make_non_null_output_port (sexp ctx, FILE* out, sexp name) {
1958   if (!out) return sexp_user_exception(ctx, SEXP_FALSE, "null output-port", name);
1959   return sexp_make_output_port(ctx, out, name);
1960 }
1961 
1962 #if SEXP_USE_BIDIRECTIONAL_PORTS
sexp_make_non_null_input_output_port(sexp ctx,FILE * io,sexp name)1963 sexp sexp_make_non_null_input_output_port (sexp ctx, FILE* io, sexp name) {
1964   sexp res;
1965   if (!io) return sexp_user_exception(ctx, SEXP_FALSE, "null input-output-port", name);
1966   res = sexp_make_input_port(ctx, io, name);
1967   if (sexp_portp(res)) sexp_port_bidirp(res) = 1;
1968   return res;
1969 }
1970 #else
1971 #define sexp_make_non_null_input_output_port sexp_make_non_null_input_port
1972 #endif
1973 
sexp_port_outputp_op(sexp ctx,sexp self,sexp_sint_t n,sexp obj)1974 sexp sexp_port_outputp_op (sexp ctx, sexp self, sexp_sint_t n, sexp obj) {
1975   return sexp_make_boolean(sexp_oportp(obj));
1976 }
1977 
sexp_port_binaryp_op(sexp ctx,sexp self,sexp_sint_t n,sexp obj)1978 sexp sexp_port_binaryp_op (sexp ctx, sexp self, sexp_sint_t n, sexp obj) {
1979   return sexp_make_boolean(sexp_portp(obj) && sexp_port_binaryp(obj));
1980 }
1981 
sexp_port_openp_op(sexp ctx,sexp self,sexp_sint_t n,sexp obj)1982 sexp sexp_port_openp_op (sexp ctx, sexp self, sexp_sint_t n, sexp obj) {
1983   return sexp_make_boolean(sexp_portp(obj) && sexp_port_openp(obj));
1984 }
1985 
1986 #if SEXP_USE_FOLD_CASE_SYMS
sexp_get_port_fold_case(sexp ctx,sexp self,sexp_sint_t n,sexp in)1987 sexp sexp_get_port_fold_case (sexp ctx, sexp self, sexp_sint_t n, sexp in) {
1988   sexp_assert_type(ctx, sexp_iportp, SEXP_IPORT, in);
1989   return sexp_make_boolean(sexp_port_fold_casep(in));
1990 }
sexp_set_port_fold_case(sexp ctx,sexp self,sexp_sint_t n,sexp in,sexp x)1991 sexp sexp_set_port_fold_case (sexp ctx, sexp self, sexp_sint_t n, sexp in, sexp x) {
1992   sexp_assert_type(ctx, sexp_iportp, SEXP_IPORT, in);
1993   sexp_assert_type(ctx, sexp_booleanp, SEXP_BOOLEAN, x);
1994   sexp_port_fold_casep(in) = sexp_truep(x);
1995   return SEXP_VOID;
1996 }
1997 #endif
1998 
1999 #if SEXP_USE_GREEN_THREADS
sexp_maybe_block_port(sexp ctx,sexp in,int forcep)2000 int sexp_maybe_block_port (sexp ctx, sexp in, int forcep) {
2001   sexp f;
2002   int c;
2003   if ((sexp_port_stream(in) || sexp_filenop(sexp_port_fd(in)))
2004       && sexp_port_fileno(in) >= 0) {
2005     if (sexp_port_flags(in) == SEXP_PORT_UNKNOWN_FLAGS)
2006       sexp_port_flags(in) = fcntl(sexp_port_fileno(in), F_GETFL);
2007     if (sexp_port_flags(in) & O_NONBLOCK) {
2008       if (!forcep
2009           && (((c = sexp_read_char(ctx, in)) == EOF)
2010               && sexp_port_stream(in)
2011               && (sexp_port_stream(in) ? ferror(sexp_port_stream(in)) : 1)
2012               && (errno == EAGAIN))) {
2013         if (sexp_port_stream(in))
2014           clearerr(sexp_port_stream(in));
2015         f = sexp_global(ctx, SEXP_G_THREADS_BLOCKER);
2016         if (sexp_applicablep(f)) {
2017           sexp_apply2(ctx, f, in, SEXP_FALSE);
2018           return 1;
2019         }
2020       }
2021       if (!forcep) sexp_push_char(ctx, c, in);
2022       sexp_port_blockedp(in) = 1;
2023       fcntl(sexp_port_fileno(in), F_SETFL, sexp_port_flags(in) & ~O_NONBLOCK);
2024     }
2025   }
2026   return 0;
2027 }
2028 
sexp_maybe_block_output_port(sexp ctx,sexp out)2029 int sexp_maybe_block_output_port (sexp ctx, sexp out) {
2030   if (sexp_port_stream(out) && sexp_port_fileno(out) >= 0) {
2031     if (sexp_port_flags(out) == SEXP_PORT_UNKNOWN_FLAGS)
2032       sexp_port_flags(out) = fcntl(sexp_port_fileno(out), F_GETFL);
2033     if (sexp_port_flags(out) & O_NONBLOCK) {
2034       sexp_port_blockedp(out) = 1;
2035       fcntl(sexp_port_fileno(out), F_SETFL, sexp_port_flags(out) & ~O_NONBLOCK);
2036       return 1;
2037     }
2038   }
2039   return 0;
2040 }
2041 
sexp_maybe_unblock_port(sexp ctx,sexp port)2042 void sexp_maybe_unblock_port (sexp ctx, sexp port) {
2043   if (sexp_port_blockedp(port)) {
2044     sexp_port_blockedp(port) = 0;
2045     fcntl(sexp_port_fileno(port), F_SETFL, sexp_port_flags(port));
2046   }
2047 }
2048 #endif
2049 
2050 #if SEXP_USE_GREEN_THREADS
sexp_fileno_ready_p(int fd)2051 static int sexp_fileno_ready_p (int fd) {
2052   struct pollfd pfd;
2053   if (fd < 0) return 0;
2054   pfd.fd = fd;
2055   pfd.events = POLLIN;
2056   return poll(&pfd, 1, 0) == 1;
2057 }
2058 
sexp_stream_ready_p(FILE * in)2059 static int sexp_stream_ready_p (FILE* in) {
2060   int flags = fcntl(fileno(in), F_GETFL), res;
2061   if (! (flags & O_NONBLOCK)) fcntl(fileno(in), F_SETFL, flags & O_NONBLOCK);
2062   res = getc(in);
2063   if (! (flags & O_NONBLOCK)) fcntl(fileno(in), F_SETFL, flags);
2064   if (res == EOF || ferror(in)) {
2065     clearerr(in);
2066     return 0;
2067   }
2068   ungetc(res, in);
2069   return 1;
2070 }
2071 #endif
2072 
sexp_char_ready_p(sexp ctx,sexp self,sexp_sint_t n,sexp in)2073 sexp sexp_char_ready_p (sexp ctx, sexp self, sexp_sint_t n, sexp in) {
2074   sexp_assert_type(ctx, sexp_iportp, SEXP_IPORT, in);
2075   if (!sexp_port_openp(in))
2076     return SEXP_FALSE;
2077   if (sexp_port_buf(in))
2078     if (sexp_port_offset(in) < sexp_port_size(in)
2079         || (!sexp_filenop(sexp_port_fd(in)) && !sexp_port_stream(in)))
2080       return SEXP_TRUE;
2081 #if SEXP_USE_GREEN_THREADS     /* maybe not just when threads are enabled */
2082   if (sexp_filenop(sexp_port_fd(in)))
2083     return sexp_make_boolean(sexp_fileno_ready_p(sexp_port_fileno(in)));
2084   else if (sexp_port_stream(in))
2085     return sexp_make_boolean(sexp_stream_ready_p(sexp_port_stream(in)));
2086 #endif
2087   /* for custom ports and unthreaded compiles we just return true for now */
2088   return SEXP_TRUE;
2089 }
2090 
2091 #define NUMBUF_LEN 32
2092 
2093 static struct {const char* name; char ch;} sexp_char_names[] = {
2094   {"newline", '\n'},
2095   {"return", '\r'},
2096   {"space", ' '},
2097   {"tab", '\t'},
2098 #if SEXP_USE_EXTENDED_CHAR_NAMES
2099   {"alarm", '\a'},
2100   {"backspace", '\b'},
2101   {"delete", 127},
2102   {"escape", 27},
2103   {"null", 0},
2104 #endif
2105 };
2106 
2107 #define sexp_num_char_names (sizeof(sexp_char_names)/sizeof(sexp_char_names[0]))
2108 
sexp_write_one(sexp ctx,sexp obj,sexp out,sexp_sint_t bound)2109 sexp sexp_write_one (sexp ctx, sexp obj, sexp out, sexp_sint_t bound) {
2110 #if SEXP_USE_HUFF_SYMS
2111   sexp_uint_t res;
2112 #endif
2113   sexp_uint_t len, c;
2114   sexp_sint_t i=0;
2115 #if SEXP_USE_FLONUMS
2116   double f, ftmp;
2117 #endif
2118 #if SEXP_USE_BYTEVECTOR_LITERALS && SEXP_BYTEVECTOR_HEX_LITERALS
2119   char buf[5];
2120 #endif
2121   sexp x, x2, *elts;
2122   char *str=NULL, numbuf[NUMBUF_LEN];
2123 
2124   if (! obj) {
2125     sexp_write_string(ctx, "#<null>", out); /* shouldn't happen */
2126   } else if (sexp_pointerp(obj)) {
2127     if (bound >= SEXP_DEFAULT_WRITE_BOUND) {
2128       sexp_write_string(ctx, "...", out);
2129       return SEXP_VOID;
2130     }
2131     switch (sexp_pointer_tag(obj)) {
2132     case SEXP_PAIR:
2133       sexp_write_char(ctx, '(', out);
2134       sexp_write_one(ctx, sexp_car(obj), out, bound+1);
2135       x = sexp_cdr(obj);
2136       for (x2=sexp_pairp(x)?sexp_cdr(x):SEXP_NULL; sexp_pairp(x); x=sexp_cdr(x), x2=(sexp_pairp(x2)&&sexp_pairp(sexp_cdr(x2))?sexp_cddr(x2):SEXP_NULL)) {
2137         if (x == x2) {
2138           sexp_write_string(ctx, "...", out);
2139           return SEXP_VOID;
2140         }
2141         sexp_write_char(ctx, ' ', out);
2142         sexp_write_one(ctx, sexp_car(x), out, bound+1);
2143       }
2144       if (! sexp_nullp(x)) {
2145         sexp_write_string(ctx, " . ", out);
2146         sexp_write_one(ctx, x, out, bound+1);
2147       }
2148       sexp_write_char(ctx, ')', out);
2149       break;
2150     case SEXP_VECTOR:
2151       len = sexp_vector_length(obj);
2152       elts = sexp_vector_data(obj);
2153       if (len == 0) {
2154         sexp_write_string(ctx, "#()", out);
2155       } else {
2156         sexp_write_string(ctx, "#(", out);
2157         sexp_write_one(ctx, elts[0], out, bound+1);
2158         for (i=1; i<(sexp_sint_t)len; i++) {
2159           sexp_write_char(ctx, ' ', out);
2160           sexp_write_one(ctx, elts[i], out, bound+1);
2161         }
2162         sexp_write_char(ctx, ')', out);
2163       }
2164       break;
2165 #if SEXP_USE_FLONUMS
2166 #if ! SEXP_USE_IMMEDIATE_FLONUMS
2167     case SEXP_FLONUM:
2168       f = sexp_flonum_value(obj);
2169 #if SEXP_USE_INFINITIES
2170       if (isinf(f) || isnan(f)) {
2171         numbuf[0] = (isinf(f) && f < 0 ? '-' : '+');
2172         strncpy(numbuf+1, isinf(f) ? "inf.0" : "nan.0", NUMBUF_LEN-1);
2173       } else
2174 #endif
2175       {
2176         i = snprintf(numbuf, NUMBUF_LEN, "%.15lg", f);
2177         if (sscanf(numbuf, "%lg", &ftmp) == 1 && ftmp != f) {
2178           i = snprintf(numbuf, NUMBUF_LEN, "%.16lg", f);
2179           if (sscanf(numbuf, "%lg", &ftmp) == 1 && ftmp != f) {
2180             i = snprintf(numbuf, NUMBUF_LEN, "%.17lg", f);
2181           }
2182         }
2183         if (!strchr(numbuf, '.') && !strchr(numbuf, 'e')) {
2184           numbuf[i++] = '.'; numbuf[i++] = '0'; numbuf[i++] = '\0';
2185         }
2186       }
2187       sexp_write_string(ctx, numbuf, out);
2188       break;
2189 #endif
2190 #endif
2191     case SEXP_PROCEDURE:
2192       sexp_write_string(ctx, "#<procedure ", out);
2193       x = sexp_bytecode_name(sexp_procedure_code(obj));
2194       sexp_write_one(ctx, sexp_synclop(x) ? sexp_synclo_expr(x): x, out, bound+1);
2195 #if SEXP_USE_DEBUG_VM
2196       if (sexp_procedure_source(obj)) {
2197         sexp_write_string(ctx, " ", out);
2198         sexp_write(ctx, sexp_procedure_source(obj), out);
2199       }
2200 #endif
2201       sexp_write_string(ctx, ">", out);
2202       break;
2203     case SEXP_TYPE:
2204       sexp_write_string(ctx, "#<type ", out);
2205       sexp_write(ctx, sexp_type_name(obj), out);
2206       sexp_write_string(ctx, ">", out);
2207       break;
2208 #if 0
2209     case SEXP_ENV:
2210       sexp_write_string(ctx, "#<Env ", out);
2211       sexp_write(ctx, sexp_make_fixnum(obj), out);
2212       sexp_write_string(ctx, " ", out);
2213       sexp_write(ctx, sexp_make_fixnum(sexp_env_bindings(obj)), out);
2214       sexp_write_string(ctx, " (", out);
2215       sexp_write(ctx, sexp_length(ctx, sexp_env_bindings(obj)), out);
2216       sexp_write_string(ctx, ")", out);
2217       if (sexp_env_parent(obj)) {
2218         sexp_write_string(ctx, " ", out);
2219         sexp_write(ctx, sexp_env_parent(obj), out);
2220       }
2221       sexp_write_string(ctx, ">", out);
2222       break;
2223 #endif
2224     case SEXP_STRING:
2225       sexp_write_char(ctx, '"', out);
2226       i = sexp_string_size(obj);
2227       str = sexp_string_data(obj);
2228       for ( ; i>0; str++, i--) {
2229         switch (str[0]) {
2230         case '\\': sexp_write_string(ctx, "\\\\", out); break;
2231         case '"': sexp_write_string(ctx, "\\\"", out); break;
2232         case '\a': sexp_write_string(ctx, "\\a", out); break;
2233         case '\b': sexp_write_string(ctx, "\\b", out); break;
2234         case '\n': sexp_write_string(ctx, "\\n", out); break;
2235         case '\r': sexp_write_string(ctx, "\\r", out); break;
2236         case '\t': sexp_write_string(ctx, "\\t", out); break;
2237         default:
2238           if (str[0] < ' ' && str[0] >= 0) {
2239             sexp_write_string(ctx, "\\x", out);
2240             sexp_write_char(ctx, hex_digit(str[0]>>4), out);
2241             sexp_write_char(ctx, hex_digit(str[0]&0x0F), out);
2242             sexp_write_char(ctx, ';', out);
2243           } else {
2244             sexp_write_char(ctx, str[0], out);
2245           }
2246         }
2247       }
2248       sexp_write_char(ctx, '"', out);
2249       break;
2250     case SEXP_SYMBOL:
2251       str = sexp_lsymbol_data(obj);
2252       c = (sexp_lsymbol_length(obj) == 0 ||
2253            (sexp_lsymbol_length(obj) == 1 && str[0] == '.') ||
2254            sexp_isdigit((unsigned char)str[0]) ||
2255            (sexp_lsymbol_length(obj) > 1 &&
2256             ((str[0] == '+' || str[0] == '-')
2257              && (sexp_isdigit((unsigned char)str[1]) ||
2258                  str[1] == '.' || str[1] == 'i' ||
2259                  ((sexp_lsymbol_length(obj) > 3) &&
2260                   sexp_tolower((unsigned char)str[1]) == 'n' &&
2261                   sexp_tolower((unsigned char)str[2]) == 'a' &&
2262                   sexp_tolower((unsigned char)str[3]) == 'n')))))
2263         ? '|' : EOF;
2264       for (i=sexp_lsymbol_length(obj)-1; i>=0; i--)
2265         if (str[i] <= ' ' || str[i] == '\\' || str[i] == '|' || str[i] == '#' || sexp_is_separator(str[i]))
2266           c = '|';
2267       if (c!=EOF) sexp_write_char(ctx, c, out);
2268       for (i=sexp_lsymbol_length(obj); i>0; str++, i--) {
2269         if (str[0] == '\\' || str[0] == '|') sexp_write_char(ctx, '\\', out);
2270         sexp_write_char(ctx, str[0], out);
2271       }
2272       if (c!=EOF) sexp_write_char(ctx, c, out);
2273       break;
2274 #if SEXP_USE_BIGNUMS
2275     case SEXP_BIGNUM:
2276       sexp_write_bignum(ctx, obj, out, 10);
2277       break;
2278 #endif
2279 #if SEXP_USE_RATIOS
2280     case SEXP_RATIO:
2281       sexp_write(ctx, sexp_ratio_numerator(obj), out);
2282       sexp_write_char(ctx, '/', out);
2283       sexp_write(ctx, sexp_ratio_denominator(obj), out);
2284       break;
2285 #endif
2286 #if SEXP_USE_COMPLEX
2287     case SEXP_COMPLEX:
2288       sexp_write(ctx, sexp_complex_real(obj), out);
2289       if (!sexp_pedantic_negativep(sexp_complex_imag(obj))
2290           && !sexp_infp(sexp_complex_imag(obj)))
2291         sexp_write_char(ctx, '+', out);
2292       if (sexp_complex_imag(obj) == SEXP_NEG_ONE)
2293         sexp_write_char(ctx, '-', out);
2294       else if (sexp_complex_imag(obj) != SEXP_ONE)
2295         sexp_write(ctx, sexp_complex_imag(obj), out);
2296       sexp_write_char(ctx, 'i', out);
2297       break;
2298 #endif
2299     case SEXP_OPCODE:
2300       sexp_write_string(ctx, "#<opcode ", out);
2301       sexp_write(ctx, sexp_opcode_name(obj), out);
2302       sexp_write_char(ctx, '>', out);
2303       break;
2304 #if SEXP_USE_BYTEVECTOR_LITERALS
2305     case SEXP_BYTES:
2306       sexp_write_string(ctx, "#u8(", out);
2307       str = sexp_bytes_data(obj);
2308       len = sexp_bytes_length(obj);
2309       for (i=0; i<(sexp_sint_t)len; i++) {
2310         if (i!=0) sexp_write_char(ctx, ' ', out);
2311 #if SEXP_BYTEVECTOR_HEX_LITERALS
2312 	if (str[i]) {
2313 	  snprintf(buf, 5, "#x%02hhX", ((unsigned char*) str)[i]);
2314 	  sexp_write_string(ctx, buf, out);
2315 	} else {
2316 	  sexp_write_char (ctx, '0', out);
2317 	}
2318 #else
2319         sexp_write(ctx, sexp_make_fixnum(((unsigned char*)str)[i]), out);
2320 #endif
2321       }
2322       sexp_write_char(ctx, ')', out);
2323       break;
2324 #endif
2325     case SEXP_FILENO:
2326       sexp_write_string(ctx, "#<fileno ", out);
2327       sexp_write(ctx, sexp_make_fixnum(sexp_fileno_fd(obj)), out);
2328       sexp_write_char(ctx, '>', out);
2329       break;
2330     case SEXP_SYNCLO:
2331       sexp_write_string(ctx, "#<SC ", out);
2332       sexp_write(ctx, sexp_make_fixnum(obj), out);
2333       sexp_write_char(ctx, ' ', out);
2334       sexp_write(ctx, sexp_synclo_expr(obj), out);
2335       sexp_write_char(ctx, ' ', out);
2336       sexp_write(ctx, sexp_synclo_rename(obj), out);
2337       sexp_write_char(ctx, '>', out);
2338       break;
2339     default:
2340       i = sexp_pointer_tag(obj);
2341       if (i < 0 || i >= sexp_context_num_types(ctx)) {
2342         sexp_write_string(ctx, "#<invalid type tag: ", out);
2343         sexp_write(ctx, sexp_make_fixnum(i), out);
2344         sexp_write_char(ctx, '>', out);
2345       } else {
2346         x = sexp_type_by_index(ctx, i);
2347 #if 0 && SEXP_USE_TYPE_PRINTERS
2348         if (sexp_type_print(x)) {
2349           x = sexp_apply3(ctx, sexp_type_print(x), obj, SEXP_FALSE, out);
2350           if (sexp_exceptionp(x)) return x;
2351         } else {
2352 #endif
2353           sexp_write_string(ctx, "#<", out);
2354           if (sexp_stringp(sexp_type_name(x)))
2355             sexp_write_string(ctx, sexp_string_data(sexp_type_name(x)), out);
2356           else
2357             sexp_write(ctx, sexp_type_name(x), out);
2358           sexp_write_char(ctx, ' ', out);
2359           sexp_write(ctx, sexp_make_fixnum(obj), out);
2360           sexp_write_char(ctx, '>', out);
2361 #if 0 && SEXP_USE_TYPE_PRINTERS
2362         }
2363 #endif
2364       }
2365       break;
2366     }
2367   } else if (sexp_fixnump(obj)) {
2368     snprintf(numbuf, NUMBUF_LEN, "%" SEXP_PRIdFIXNUM, (sexp_sint_t)sexp_unbox_fixnum(obj));
2369     sexp_write_string(ctx, numbuf, out);
2370 #if SEXP_USE_IMMEDIATE_FLONUMS
2371   } else if (sexp_flonump(obj)) {
2372     f = sexp_flonum_value(obj);
2373 #if SEXP_USE_INFINITIES
2374     if (isinf(f) || isnan(f)) {
2375       numbuf[0] = (isinf(f) && f < 0 ? '-' : '+');
2376       strncpy(numbuf+1, isinf(f) ? "inf.0" : "nan.0", NUMBUF_LEN-1);
2377     } else
2378 #endif
2379     {
2380       i = snprintf(numbuf, NUMBUF_LEN, "%.8g", f);
2381       if (f == trunc(f) && ! strchr(numbuf, '.')) {
2382         numbuf[i++] = '.'; numbuf[i++] = '0'; numbuf[i++] = '\0';
2383       }
2384     }
2385     sexp_write_string(ctx, numbuf, out);
2386 #endif
2387   } else if (sexp_string_cursorp(obj)) {
2388     sexp_write_string(ctx, "{String-Cursor #", out);
2389     sexp_write(ctx, sexp_make_fixnum(SEXP_STRING_CURSOR), out);
2390     sexp_write_char(ctx, ' ', out);
2391     sexp_write(ctx, sexp_make_fixnum(sexp_unbox_string_cursor(obj)), out);
2392     sexp_write_char(ctx, '}', out);
2393   } else if (sexp_charp(obj)) {
2394     sexp_write_string(ctx, "#\\", out);
2395     for (i=0; i < sexp_num_char_names; i++) {
2396       if (sexp_unbox_character(obj) == sexp_char_names[i].ch) {
2397         sexp_write_string(ctx, sexp_char_names[i].name, out);
2398         break;
2399       }
2400     }
2401     if (i >= sexp_num_char_names) {
2402       if ((33 <= sexp_unbox_character(obj))
2403           && (sexp_unbox_character(obj) < 127)) {
2404         sexp_write_char(ctx, sexp_unbox_character(obj), out);
2405       } else {
2406         sexp_write_string(ctx, "x", out);
2407         c = sexp_unbox_character(obj);
2408         if (c >= 0x100) {
2409           if (c >= 0x10000) {
2410             sexp_write_char(ctx, hex_digit((c>>20)&0x0F), out);
2411             sexp_write_char(ctx, hex_digit((c>>16)&0x0F), out);
2412           }
2413           sexp_write_char(ctx, hex_digit((c>>12)&0x0F), out);
2414           sexp_write_char(ctx, hex_digit((c>>8)&0x0F), out);
2415         }
2416         sexp_write_char(ctx, hex_digit((c>>4)&0x0F), out);
2417         sexp_write_char(ctx, hex_digit(c&0x0F), out);
2418       }
2419     }
2420 #if SEXP_USE_HUFF_SYMS
2421   } else if (sexp_isymbolp(obj)) {
2422     if (sexp_isymbolp(obj)) {
2423       c = ((sexp_uint_t)obj)>>SEXP_IMMEDIATE_BITS;
2424       while (c) {
2425 #include "chibi/sexp-unhuff.h"
2426         sexp_write_char(ctx, res, out);
2427       }
2428     }
2429 #endif
2430   } else {
2431     switch ((sexp_uint_t) obj) {
2432     case (sexp_uint_t) SEXP_NULL:
2433       sexp_write_string(ctx, "()", out); break;
2434     case (sexp_uint_t) SEXP_TRUE:
2435       sexp_write_string(ctx, "#t", out); break;
2436     case (sexp_uint_t) SEXP_FALSE:
2437       sexp_write_string(ctx, "#f", out); break;
2438     case (sexp_uint_t) SEXP_EOF:
2439       sexp_write_string(ctx, "#<eof>", out); break;
2440     case (sexp_uint_t) SEXP_UNDEF:
2441     case (sexp_uint_t) SEXP_VOID:
2442       sexp_write_string(ctx, "#<undef>", out); break;
2443     default:
2444       sexp_write_string(ctx, "#<invalid immediate: ", out);
2445       sexp_write(ctx, sexp_make_fixnum(obj), out);
2446       sexp_write_char(ctx, '>', out);
2447     }
2448   }
2449   return SEXP_VOID;
2450 }
2451 
sexp_write_op(sexp ctx,sexp self,sexp_sint_t n,sexp obj,sexp out)2452 sexp sexp_write_op (sexp ctx, sexp self, sexp_sint_t n, sexp obj, sexp out) {
2453   sexp res;
2454   sexp_assert_type(ctx, sexp_oportp, SEXP_OPORT, out);
2455 #if SEXP_USE_GREEN_THREADS
2456   sexp_maybe_block_output_port(ctx, out);
2457 #endif
2458   res = sexp_write_one(ctx, obj, out, 0);
2459 #if SEXP_USE_GREEN_THREADS
2460   sexp_maybe_unblock_port(ctx, out);
2461 #endif
2462   return res;
2463 }
2464 
2465 #if SEXP_USE_UTF8_STRINGS
sexp_write_utf8_char(sexp ctx,int c,sexp out)2466 int sexp_write_utf8_char (sexp ctx, int c, sexp out) {
2467   unsigned char buf[8];
2468   int len = sexp_utf8_char_byte_count(c), i;
2469   sexp_utf8_encode_char(buf, len, c);
2470   buf[len] = 0;
2471   i = sexp_write_char(ctx, buf[0], out);
2472   if (i == EOF) return EOF;
2473   sexp_write_string(ctx, (char*)buf+1, out);
2474   return len;
2475 }
2476 #endif
2477 
sexp_flush_output_op(sexp ctx,sexp self,sexp_sint_t n,sexp out)2478 sexp sexp_flush_output_op (sexp ctx, sexp self, sexp_sint_t n, sexp out) {
2479   int res;
2480   sexp_assert_type(ctx, sexp_oportp, SEXP_OPORT, out);
2481   res = sexp_flush_forced(ctx, out);
2482   if (res == EOF) {
2483 #if SEXP_USE_GREEN_THREADS
2484     if (sexp_port_stream(out) && ferror(sexp_port_stream(out)) && (errno == EAGAIN))
2485       return sexp_global(ctx, SEXP_G_IO_BLOCK_ERROR);
2486 #endif
2487     return SEXP_FALSE;
2488   }
2489   return SEXP_TRUE;
2490 }
2491 
2492 #define INIT_STRING_BUFFER_SIZE 128
2493 
sexp_read_string(sexp ctx,sexp in,int sentinel)2494 sexp sexp_read_string (sexp ctx, sexp in, int sentinel) {
2495 #if SEXP_USE_UTF8_STRINGS
2496   int len;
2497 #endif
2498   int c, i=0;
2499   sexp_sint_t size=INIT_STRING_BUFFER_SIZE;
2500   char initbuf[INIT_STRING_BUFFER_SIZE];
2501   char *buf=initbuf, *tmp;
2502   sexp res = SEXP_FALSE;
2503 
2504   for (c = sexp_read_char(ctx, in); c != sentinel; c = sexp_read_char(ctx, in)) {
2505     if (c == '\\') {
2506       c = sexp_read_char(ctx, in);
2507       switch (c) {
2508       case 'a': c = '\a'; break;
2509       case 'b': c = '\b'; break;
2510       case 'n': c = '\n'; break;
2511       case 'r': c = '\r'; break;
2512       case 't': c = '\t'; break;
2513       case 'x': case 'X':
2514         res = sexp_read_number(ctx, in, 16, 0);
2515         if (sexp_fixnump(res)) {
2516           c = sexp_read_char(ctx, in);
2517           if (c != ';') {
2518 #if SEXP_USE_ESCAPE_REQUIRES_TRAILING_SEMI_COLON
2519             res = sexp_read_error(ctx, "missing ; in \\x escape", SEXP_NULL, in);
2520 #else
2521             sexp_push_char(ctx, c, in);
2522 #endif
2523           }
2524           c = sexp_unbox_fixnum(res);
2525 #if SEXP_USE_UTF8_STRINGS
2526           if ((unsigned)c > 0x80) {
2527             len = sexp_utf8_char_byte_count(c);
2528             sexp_utf8_encode_char((unsigned char*)buf + i, len, c);
2529             i += len;
2530             goto maybe_expand;
2531           }
2532 #endif
2533         }
2534         break;
2535 #if SEXP_USE_ESCAPE_NEWLINE
2536       default:
2537         if (isspace(c)) {
2538           while (c==' ' || c=='\t') c=sexp_read_char(ctx, in);
2539           if (c=='\r') c=sexp_read_char(ctx, in);
2540           if (c=='\n') {
2541             sexp_port_line(in)++;
2542             do {c=sexp_read_char(ctx, in);} while (c==' ' || c=='\t');
2543             sexp_push_char(ctx, c, in);
2544             continue;
2545           }
2546         }
2547 #endif
2548       }
2549       if (sexp_exceptionp(res)) break;
2550     } else if (c == '\n') {
2551       sexp_port_line(in)++;
2552     } else if (c == EOF) {
2553       res = sexp_read_error(ctx, "premature end of string", SEXP_NULL, in);
2554       break;
2555     }
2556     buf[i++] = c;
2557   maybe_expand:
2558     if (i+4 >= size) {       /* expand buffer w/ malloc(), later free() it */
2559       tmp = (char*) sexp_malloc(size*2);
2560       if (!tmp) {res = sexp_global(ctx, SEXP_G_OOM_ERROR); break;}
2561       memcpy(tmp, buf, i);
2562       if (size != INIT_STRING_BUFFER_SIZE) free(buf);
2563       buf = tmp;
2564       size *= 2;
2565     }
2566   }
2567 
2568   if (!sexp_exceptionp(res)) {
2569     buf[i] = '\0';
2570     res = sexp_c_string(ctx, buf, i);
2571   }
2572   if (size != INIT_STRING_BUFFER_SIZE) free(buf);
2573   return res;
2574 }
2575 
sexp_read_symbol(sexp ctx,sexp in,int init,int internp)2576 sexp sexp_read_symbol (sexp ctx, sexp in, int init, int internp) {
2577   int c, i=0, size=INIT_STRING_BUFFER_SIZE;
2578   char initbuf[INIT_STRING_BUFFER_SIZE];
2579   char *buf=initbuf, *tmp;
2580   sexp res=SEXP_VOID;
2581 #if SEXP_USE_FOLD_CASE_SYMS
2582   int foldp = sexp_port_fold_casep(in);
2583   init = (foldp ? sexp_tolower(init) : init);
2584 #endif
2585 
2586   if (init != EOF)
2587     buf[i++] = init;
2588 
2589   for (c = sexp_read_char(ctx, in); ; c = sexp_read_char(ctx, in)) {
2590 #if SEXP_USE_FOLD_CASE_SYMS
2591     if (foldp) c = sexp_tolower(c);
2592 #endif
2593     if (c == '\\') c = sexp_read_char(ctx, in);
2594     if (c == EOF || sexp_is_separator(c)) {
2595       sexp_push_char(ctx, c, in);
2596       break;
2597     }
2598     buf[i++] = c;
2599     if (i >= size) {       /* expand buffer w/ malloc(), later free() it */
2600       tmp = (char*) sexp_malloc(size*2);
2601       if (!tmp) {res = sexp_global(ctx, SEXP_G_OOM_ERROR); break;}
2602       memcpy(tmp, buf, i);
2603       if (size != INIT_STRING_BUFFER_SIZE) free(buf);
2604       buf = tmp;
2605       size *= 2;
2606     }
2607   }
2608 
2609   if (!sexp_exceptionp(res)) {
2610     buf[i] = '\0';
2611     res = (internp ? sexp_intern(ctx, buf, i) : sexp_c_string(ctx, buf, i));
2612   }
2613   if (size != INIT_STRING_BUFFER_SIZE) free(buf);
2614   return res;
2615 }
2616 
2617 #if SEXP_USE_COMPLEX
sexp_make_complex(sexp ctx,sexp real,sexp image)2618 sexp sexp_make_complex (sexp ctx, sexp real, sexp image) {
2619   sexp res = sexp_alloc_type(ctx, complex, SEXP_COMPLEX);
2620   sexp_complex_real(res) = real;
2621   sexp_complex_imag(res) = image;
2622   return res;
2623 }
2624 
sexp_complex_normalize(sexp cpx)2625 sexp sexp_complex_normalize (sexp cpx) {
2626   return sexp_complexp(cpx)
2627     && (sexp_complex_imag(cpx) == SEXP_ZERO
2628         /* Only normalize for an exact zero imaginary part.  */
2629         /* || (sexp_flonump(sexp_complex_imag(cpx)) */
2630         /*     && sexp_flonum_value(sexp_complex_imag(cpx)) == 0.0) */
2631         )
2632     ? sexp_complex_real(cpx) : cpx;
2633 }
2634 
sexp_read_complex_tail(sexp ctx,sexp in,sexp real)2635 sexp sexp_read_complex_tail (sexp ctx, sexp in, sexp real) {
2636   int c = sexp_read_char(ctx, in), c2;
2637   sexp default_real = SEXP_ZERO;
2638   sexp_gc_var1(res);
2639   sexp_gc_preserve1(ctx, res);
2640   res = SEXP_VOID;
2641   if (c=='i' || c=='I') {       /* trailing i, no sign */
2642   trailing_i:
2643     c = sexp_read_char(ctx, in);
2644     if (c=='n' || c=='N') {
2645       res = sexp_read_symbol(ctx, in, c, 1);
2646       if (res == sexp_intern(ctx, "nf.0i", -1))
2647         real = res = sexp_make_flonum(ctx, real == SEXP_ONE ? sexp_pos_infinity : sexp_neg_infinity);
2648       else
2649         goto invalid;
2650     } else if ((c!=EOF) && ! sexp_is_separator(c)) {
2651     invalid:
2652       res = sexp_read_error(ctx, "invalid complex numeric syntax", sexp_make_character(c), in);
2653     } else
2654       sexp_push_char(ctx, c, in);
2655     if (!sexp_exceptionp(res))
2656       res = sexp_make_complex(ctx, default_real, real);  /* NNNNi has 0 real */
2657   } else {                      /* trailing + or - */
2658     c2 = sexp_read_char(ctx, in);
2659     if (c2=='i' || c2=='I') {
2660       default_real = real;
2661       real = (c=='-') ? SEXP_NEG_ONE : SEXP_ONE;
2662       goto trailing_i;
2663     } else {
2664       sexp_push_char(ctx, c2, in);
2665       /* read imaginary part */
2666       if (c=='-') sexp_push_char(ctx, c, in);
2667       res = sexp_read_number(ctx, in, 10, 0);
2668       if (sexp_complexp(res)) {
2669         if (sexp_complex_real(res) == SEXP_ZERO)
2670           sexp_complex_real(res) = real;
2671         else
2672           res = sexp_read_error(ctx, "multiple real parts of complex", res, in);
2673       } else if ((res == SEXP_ZERO)
2674                  || (sexp_flonump(res) && sexp_flonum_value(res) == 0.0)) {
2675         res = sexp_make_complex(ctx, real, res);
2676       } else {                    /* found trailing +/-NNNN with no i */
2677         res = sexp_exceptionp(res) ? res
2678           : sexp_read_error(ctx, "missing imaginary part of complex", res, in);
2679       }
2680     }
2681   }
2682   sexp_gc_release1(ctx);
2683   return sexp_complex_normalize(res);
2684 }
2685 
2686 #if SEXP_USE_MATH
sexp_read_polar_tail(sexp ctx,sexp in,sexp magnitude)2687 sexp sexp_read_polar_tail (sexp ctx, sexp in, sexp magnitude) {
2688   sexp_gc_var2(res, theta);
2689   sexp_gc_preserve2(ctx, res, theta);
2690   theta = sexp_read_number(ctx, in, 10, 0);
2691   if (sexp_exceptionp(theta)) {
2692     res = theta;
2693   } else if (sexp_complexp(theta) || !sexp_numberp(theta)) {
2694     res = sexp_read_error(ctx, "invalid polar numeric syntax", theta, in);
2695   } else if (theta == SEXP_ZERO) {
2696     res = magnitude;
2697   } else {
2698     res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ZERO);
2699     sexp_complex_real(res) = sexp_cos(ctx, NULL, 1, theta);
2700     sexp_complex_real(res) = sexp_mul(ctx, magnitude, sexp_complex_real(res));
2701     sexp_complex_imag(res) = sexp_sin(ctx, NULL, 1, theta);
2702     sexp_complex_imag(res) = sexp_mul(ctx, magnitude, sexp_complex_imag(res));
2703     if (sexp_exceptionp(sexp_complex_real(res))) res = sexp_complex_real(res);
2704     if (sexp_exceptionp(sexp_complex_imag(res))) res = sexp_complex_imag(res);
2705   }
2706   sexp_gc_release2(ctx);
2707   return sexp_complex_normalize(res);
2708 }
2709 #endif
2710 #endif
2711 
sexp_read_float_tail(sexp ctx,sexp in,double whole,int negp)2712 sexp sexp_read_float_tail (sexp ctx, sexp in, double whole, int negp) {
2713   int c, c2;
2714   sexp exponent=SEXP_VOID;
2715   long double val=0.0, scale=10, e=0.0;
2716   sexp_gc_var1(res);
2717   sexp_gc_preserve1(ctx, res);
2718   for (c=sexp_read_char(ctx, in); sexp_isdigit(c);
2719        c=sexp_read_char(ctx, in), val*=10, scale*=10)
2720     val += digit_value(c);
2721 #if SEXP_USE_PLACEHOLDER_DIGITS
2722   for (; c==SEXP_PLACEHOLDER_DIGIT;
2723        c=sexp_read_char(ctx, in), val*=10, scale*=10)
2724     val += sexp_placeholder_digit_value(10);
2725 #endif
2726   val /= scale;
2727   val += whole;
2728   if (negp) val *= -1;
2729   if (is_precision_indicator(c)) {
2730     c2 = sexp_read_char(ctx, in);
2731     if (c2 != '+') sexp_push_char(ctx, c2, in);
2732     exponent = sexp_read_number(ctx, in, 10, 0);
2733     if (sexp_exceptionp(exponent)) {
2734       sexp_gc_release1(ctx);
2735       return exponent;
2736     }
2737 #if SEXP_USE_COMPLEX
2738     if (sexp_complexp(exponent)) {
2739       res = exponent;
2740       exponent = (sexp_complex_real(res) == SEXP_ZERO ? sexp_complex_imag(res) : sexp_complex_real(res));
2741     }
2742 #endif
2743     e = (sexp_fixnump(exponent) ? sexp_unbox_fixnum(exponent)
2744          : sexp_flonump(exponent) ? sexp_flonum_value(exponent) : 0.0);
2745 #if SEXP_USE_COMPLEX
2746     if (sexp_complexp(res)) {
2747       if (sexp_complex_real(res) == SEXP_ZERO) {
2748         sexp_complex_imag(res) = sexp_make_flonum(ctx, val * pow(10, e));
2749       } else {
2750         sexp_complex_real(res) = sexp_make_flonum(ctx, val * pow(10, e));
2751       }
2752       sexp_gc_release1(ctx);
2753       return res;
2754     }
2755 #endif
2756   }
2757   if (e != 0.0)
2758     val = fabsl(e) > 320 ? exp(log(val) + e*M_LN10) : val * pow(10, e);
2759 #if SEXP_USE_FLONUMS
2760   res = sexp_make_flonum(ctx, val);
2761 #else
2762   res = sexp_make_fixnum((sexp_uint_t)val);
2763 #endif
2764   if (!is_precision_indicator(c)) {
2765 #if SEXP_USE_COMPLEX
2766     if (c=='i' || c=='I' || c=='+' || c=='-') {
2767       sexp_push_char(ctx, c, in);
2768       res = sexp_read_complex_tail(ctx, in, res);
2769 #if SEXP_USE_MATH
2770     } else if (c=='@') {
2771       return sexp_read_polar_tail(ctx, in, res);
2772 #endif
2773     } else
2774 #endif
2775     if ((c!=EOF) && ! sexp_is_separator(c))
2776       res = sexp_read_error(ctx, "invalid numeric syntax",
2777                             sexp_make_character(c), in);
2778     else
2779       sexp_push_char(ctx, c, in);
2780   }
2781   sexp_gc_release1(ctx);
2782   return res;
2783 }
2784 
2785 #if SEXP_USE_RATIOS
sexp_make_ratio(sexp ctx,sexp num,sexp den)2786 sexp sexp_make_ratio (sexp ctx, sexp num, sexp den) {
2787   sexp res = sexp_alloc_type(ctx, ratio, SEXP_RATIO);
2788   sexp_ratio_numerator(res) = num;
2789   sexp_ratio_denominator(res) = den;
2790   return res;
2791 }
2792 
sexp_ratio_normalize(sexp ctx,sexp rat,sexp in)2793 sexp sexp_ratio_normalize (sexp ctx, sexp rat, sexp in) {
2794   sexp tmp;
2795   sexp_gc_var2(num, den);
2796   num = sexp_ratio_numerator(rat), den = sexp_ratio_denominator(rat);
2797   if (den == SEXP_ZERO)
2798     return sexp_read_error(ctx, "zero denominator in ratio", rat, in);
2799   else if (num == SEXP_ZERO)
2800     return SEXP_ZERO;
2801   sexp_gc_preserve2(ctx, num, den);
2802   while (den != SEXP_ZERO) {
2803     tmp = sexp_remainder(ctx, num, den);
2804     if (sexp_exceptionp(tmp)) {
2805       sexp_gc_release2(ctx);
2806       return tmp;
2807     }
2808     num = den, den = tmp;
2809   }
2810   sexp_ratio_denominator(rat)
2811     = den = sexp_quotient(ctx, sexp_ratio_denominator(rat), num);
2812   sexp_ratio_numerator(rat)
2813     = sexp_quotient(ctx, sexp_ratio_numerator(rat), num);
2814   if (sexp_exact_negativep(sexp_ratio_denominator(rat))) {
2815     sexp_negate(sexp_ratio_numerator(rat));
2816     sexp_negate(sexp_ratio_denominator(rat));
2817   }
2818   sexp_ratio_numerator(rat) = sexp_bignum_normalize(sexp_ratio_numerator(rat));
2819   sexp_ratio_denominator(rat) = sexp_bignum_normalize(sexp_ratio_denominator(rat));
2820   sexp_gc_release2(ctx);
2821   return (sexp_ratio_denominator(rat) == SEXP_ONE) ? sexp_ratio_numerator(rat)
2822     : rat;
2823 }
2824 #endif
2825 
sexp_read_number(sexp ctx,sexp in,int base,int exactp)2826 sexp sexp_read_number (sexp ctx, sexp in, int base, int exactp) {
2827   sexp_sint_t val = 0, tmp = -1;
2828   int c, digit, negativep = 0, inexactp = 0;
2829 #if SEXP_USE_PLACEHOLDER_DIGITS
2830   double whole = 0.0, scale = 0.1;
2831 #endif
2832 #if SEXP_USE_COMPLEX && SEXP_USE_MATH
2833   double rho, theta;
2834 #endif
2835   sexp_gc_var2(res, den);
2836 
2837   c = sexp_read_char(ctx, in);
2838   if (c == '#') {
2839     switch ((c = sexp_tolower(sexp_read_char(ctx, in)))) {
2840       case 'b': base = 2; break;   case 'o': base = 8; break;
2841       case 'd': base = 10; break;  case 'x': base = 16; break;
2842       case 'i': inexactp = 1; break; case 'e': exactp = 1; break;
2843       default: return sexp_read_error(ctx, "unexpected numeric # code", sexp_make_character(c), in);
2844     }
2845     c = sexp_read_char(ctx, in);
2846   }
2847   if (c == '-') {
2848     negativep = 1;
2849     c = sexp_read_char(ctx, in);
2850   } else if (c == '+') {
2851     c = sexp_read_char(ctx, in);
2852   }
2853 
2854 #if SEXP_USE_COMPLEX
2855   if (c == 'i' || c == 'I') val = 1;
2856 #endif
2857 
2858   for ( ; sexp_isxdigit(c); c=sexp_read_char(ctx, in)) {
2859     digit = digit_value(c);
2860     if ((digit < 0) || (digit >= base))
2861       break;
2862     tmp = val * base + digit;
2863 #if SEXP_USE_BIGNUMS
2864     if ((SEXP_MAX_FIXNUM / base < val) ||
2865         (tmp < val) || (tmp > SEXP_MAX_FIXNUM)) {
2866       sexp_push_char(ctx, c, in);
2867       return sexp_read_bignum(ctx, in, val, (negativep ? -1 : 1), base);
2868     }
2869 #endif
2870     val = tmp;
2871   }
2872 
2873 #if SEXP_USE_PLACEHOLDER_DIGITS
2874   if (sexp_placeholder_digit_p(c) && tmp >= 0) {
2875     whole = val;
2876     for ( ; sexp_placeholder_digit_p(c); c=sexp_read_char(ctx, in))
2877       whole = whole*10 + sexp_placeholder_digit_value(base);
2878     if ((c=='.' || is_precision_indicator(c)) && (base != 10))
2879       return sexp_read_error(ctx, "found non-base 10 float", SEXP_NULL, in);
2880     if (c=='.')
2881       for (c=sexp_read_char(ctx, in); sexp_placeholder_digit_p(c);
2882            c=sexp_read_char(ctx, in), scale*=0.1)
2883         whole += sexp_placeholder_digit_value(10)*scale;
2884     if (is_precision_indicator(c)) {
2885       sexp_push_char(ctx, c, in);
2886       return sexp_read_float_tail(ctx, in, whole, negativep);
2887     } else if ((c!=EOF) && !sexp_is_separator(c)) {
2888       return sexp_read_error(ctx, "invalid numeric syntax after placeholders",
2889                              sexp_make_character(c), in);
2890     }
2891     sexp_push_char(ctx, c, in);
2892     return sexp_make_flonum(ctx, (negativep ? -whole : whole));
2893   }
2894 #endif
2895 
2896   if (exactp && is_precision_indicator(c)) {
2897     sexp_gc_preserve2(ctx, res, den);
2898     res = sexp_make_fixnum(negativep ? -val : val);
2899     den = sexp_read_number(ctx, in, base, 0);
2900     if (sexp_exceptionp(den)) {
2901       res = den;
2902     } else {
2903       if (sexp_flonump(den)) den = sexp_make_fixnum(sexp_flonum_value(den));
2904       if (sexp_complexp(den)) {
2905         if (sexp_flonump(sexp_complex_real(den)))
2906           sexp_complex_real(den) = sexp_make_fixnum(sexp_flonum_value(sexp_complex_real(den)));
2907         sexp_complex_real(den) = sexp_expt(ctx, SEXP_TEN, sexp_complex_real(den));
2908         sexp_complex_real(den) = sexp_mul(ctx, res, sexp_complex_real(den));
2909         res = den;
2910       } else {
2911         den = sexp_expt(ctx, SEXP_TEN, den);
2912         res = sexp_mul(ctx, res, den);
2913       }
2914     }
2915     sexp_gc_release2(ctx);
2916     return res;
2917   } else if (c=='.' || is_precision_indicator(c)) {
2918     if (base != 10)
2919       return sexp_read_error(ctx, "found non-base 10 float", SEXP_NULL, in);
2920     if (c!='.') sexp_push_char(ctx, c, in);
2921     return sexp_read_float_tail(ctx, in, val, negativep);
2922   } else if (c=='/') {
2923     sexp_gc_preserve2(ctx, res, den);
2924     den = sexp_read_number(ctx, in, base, exactp);
2925     if (! (sexp_fixnump(den) || sexp_bignump(den) || sexp_complexp(den)))
2926       res = (sexp_exceptionp(den)
2927              ? den : sexp_read_error(ctx, "invalid rational syntax", den, in));
2928     else {
2929 #if SEXP_USE_RATIOS
2930 #if SEXP_USE_COMPLEX
2931     if (sexp_complexp(den)) {
2932       res = sexp_make_fixnum(negativep ? -val : val);
2933       if (sexp_complex_real(den) == SEXP_ZERO) {
2934         res = sexp_make_ratio(ctx, res, sexp_complex_imag(den));
2935         res = sexp_ratio_normalize(ctx, res, in);
2936         sexp_complex_imag(den) = res;
2937 #if SEXP_USE_MATH
2938       } else if (sexp_flonump(sexp_complex_real(den))) { /* assume polar */
2939         rho = sqrt(sexp_flonum_value(sexp_complex_real(den)) *
2940                    sexp_flonum_value(sexp_complex_real(den)) +
2941                    sexp_to_double(ctx, sexp_complex_imag(den)) +
2942                    sexp_to_double(ctx, sexp_complex_imag(den)));
2943         theta = atan(sexp_to_double(ctx, sexp_complex_imag(den)) /
2944                      sexp_flonum_value(sexp_complex_real(den)));
2945         rho = sexp_to_double(ctx, sexp_div(ctx, res, sexp_make_fixnum((sexp_sint_t)round(rho))));
2946         sexp_complex_real(den) = sexp_make_flonum(ctx, rho * cos(theta));
2947         sexp_complex_imag(den) = sexp_make_flonum(ctx, rho * sin(theta));
2948 #endif
2949       } else {
2950         res = sexp_make_ratio(ctx, res, sexp_complex_real(den));
2951         res = sexp_ratio_normalize(ctx, res, in);
2952         sexp_complex_real(den) = res;
2953       }
2954       if (!sexp_exceptionp(res))
2955         res = den;
2956     } else
2957 #endif
2958       do {
2959     res = sexp_make_ratio(ctx, sexp_make_fixnum(negativep ? -val : val), den);
2960     res = sexp_ratio_normalize(ctx, res, in);
2961       } while (0);
2962 #else
2963     if (!sexp_exceptionp(res))
2964       res = sexp_make_flonum(ctx, (double)(negativep ? -val : val)
2965                              / (double)sexp_unbox_fixnum(den));
2966 #endif
2967     }
2968     if (inexactp)
2969       res = sexp_exact_to_inexact(ctx, NULL, 2, res);
2970     sexp_gc_release2(ctx);
2971     return res;
2972 #if SEXP_USE_COMPLEX
2973   } else if (c=='i' || c=='I' || c=='+' || c=='-' || c=='@') {
2974     if (base != 10)
2975       return sexp_read_error(ctx, "found non-base 10 complex", SEXP_NULL, in);
2976 #if SEXP_USE_MATH
2977     if (c=='@')
2978       return sexp_read_polar_tail(ctx, in, sexp_make_fixnum(negativep ? -val : val));
2979 #endif
2980     sexp_push_char(ctx, c, in);
2981     return sexp_read_complex_tail(ctx, in, sexp_make_fixnum(negativep ? -val : val));
2982 #endif
2983   } else {
2984     if ((c!=EOF) && ! sexp_is_separator(c))
2985       return sexp_read_error(ctx, "invalid numeric syntax",
2986                              sexp_make_character(c), in);
2987     else if (tmp < 0)
2988       return sexp_read_error(ctx, "digitless numeric literal", SEXP_NULL, in);
2989     sexp_push_char(ctx, c, in);
2990   }
2991 
2992   return inexactp ? sexp_make_flonum(ctx, negativep ? -val : val)
2993     : sexp_make_fixnum(negativep ? -val : val);
2994 }
2995 
2996 #if SEXP_USE_UTF8_STRINGS
sexp_decode_utf8_char(const unsigned char * s)2997 static int sexp_decode_utf8_char(const unsigned char* s) {
2998   int i = s[0], len = strlen((const char*)s);
2999   if ((i >= 0xC0) && (i <= 0xF7) && (s[1]>>6 == 2)) {
3000     if ((i < 0xE0) && (len == 2)) {
3001       return ((i&0x3F)<<6) + (s[1]&0x3F);
3002     } else if ((i < 0xF0) && (len == 3) && (s[2]>>6 == 2)) {
3003       return ((i&0x1F)<<12) + ((s[1]&0x3F)<<6) + (s[2]&0x3F);
3004     } else if ((len == 4) && (s[2]>>6 == 2) && (s[3]>>6 == 2)) {
3005       return ((i&0x0F)<<16) + ((s[1]&0x3F)<<6) + ((s[2]&0x3F)<<6) + (s[3]&0x3F);
3006     }
3007   }
3008   return -1;
3009 }
3010 #endif
3011 
3012 #if SEXP_USE_READER_LABELS
sexp_fill_reader_labels(sexp ctx,sexp x,sexp shares,int state)3013 static sexp sexp_fill_reader_labels(sexp ctx, sexp x, sexp shares, int state) {
3014   sexp t, *p, *q;
3015   if (sexp_reader_labelp(x))
3016     return sexp_vector_data(shares)[sexp_unbox_reader_label(x)];
3017   if (!x || !sexp_pointerp(x) || sexp_markedp(x) == state)
3018     return x;
3019   sexp_markedp(x) = state;
3020   t = sexp_object_type(ctx, x);
3021   p = (sexp*) (((char*)x) + sexp_type_field_base(t));
3022   q = p + sexp_type_num_slots_of_object(t, x);
3023   for ( ; p < q; ++p)
3024     *p = sexp_fill_reader_labels(ctx, *p, shares, state);
3025   return x;
3026 }
3027 #endif
3028 
sexp_peek_char(sexp ctx,sexp in)3029 static int sexp_peek_char(sexp ctx, sexp in) {
3030   int c = sexp_read_char(ctx, in);
3031   if (c != EOF) sexp_push_char(ctx, c, in);
3032   return c;
3033 }
3034 
3035 #if SEXP_USE_UNIFORM_VECTOR_LITERALS
sexp_resolve_uniform_type(int c,sexp len)3036 static int sexp_resolve_uniform_type(int c, sexp len) {
3037   switch (sexp_fixnump(len) ? sexp_unbox_fixnum(len) : 0) {
3038     case 1: if (c=='u') return SEXP_U1; break;
3039     case 8: if (c=='u') return SEXP_U8; if (c=='s') return SEXP_S8; break;
3040     case 16: if (c=='u') return SEXP_U16; if (c=='s') return SEXP_S16; break;
3041     case 32: if (c=='u') return SEXP_U32; if (c=='s') return SEXP_S32; if (c=='f') return SEXP_F32; break;
3042     case 64: if (c=='u') return SEXP_U64; if (c=='s') return SEXP_S64; if (c=='f') return SEXP_F64; if (c=='c') return SEXP_C64; break;
3043     case 128: if (c=='c') return SEXP_C128; break;
3044   }
3045   return SEXP_NOT_A_UNIFORM_TYPE;
3046 }
3047 #else
3048 #define sexp_resolve_uniform_type(c, len) SEXP_U8
3049 #endif
3050 
sexp_list_to_uvector_op(sexp ctx,sexp self,sexp_sint_t n,sexp etype,sexp ls)3051 sexp sexp_list_to_uvector_op(sexp ctx, sexp self, sexp_sint_t n, sexp etype, sexp ls) {
3052   long et, i;
3053   long long min;
3054   unsigned long long max;
3055   sexp ls2, tmp;
3056   sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, etype);
3057   sexp_gc_var1(res);
3058   if (!sexp_listp(ctx, ls)) {
3059     res = sexp_exceptionp(ls) ? ls
3060       : sexp_xtype_exception(ctx, self, "list->uvector expected a list", ls);
3061   } else {
3062     sexp_gc_preserve1(ctx, res);
3063     et = sexp_unbox_fixnum(etype);
3064     res = et == SEXP_U8 ? sexp_make_bytes(ctx, sexp_length(ctx, ls), SEXP_VOID) : sexp_make_uvector(ctx, etype, sexp_length(ctx, ls));
3065     if (sexp_uvector_prefix(et) == 's') {
3066       min = (-1LL << (sexp_uvector_element_size(et)-1));
3067       max = (1LL << (sexp_uvector_element_size(et)-1)) - 1LL;
3068     } else {
3069       min = 0;
3070       max = sexp_uvector_element_size(et) == 64 ? -1 :
3071         (1uLL << sexp_uvector_element_size(et)) - 1LL;
3072     }
3073     for (ls2=ls; sexp_pairp(ls2); ls2=sexp_cdr(ls2)) {
3074       tmp = sexp_car(ls2);
3075       if (
3076 #if SEXP_USE_UNIFORM_VECTOR_LITERALS
3077           ((sexp_uvector_prefix(et) == 'u') || (sexp_uvector_prefix(et) == 's')) ?
3078 #endif
3079           !((min == 0 && sexp_bignump(tmp) ? sexp_bignum_sign(tmp) > 0 : sexp_exact_integerp(tmp) && sexp_sint_value(tmp) >= min)
3080             && (sexp_sint_value(tmp) < 0 || sexp_uint_value(tmp) <= max))
3081 #if SEXP_USE_UNIFORM_VECTOR_LITERALS
3082           : ((sexp_uvector_prefix(et) == 'c') ? !sexp_numberp(tmp) :
3083           !(sexp_exact_integerp(tmp) || sexp_realp(tmp)))
3084 #endif
3085           ) {
3086         res = sexp_cons(ctx, SEXP_FALSE, SEXP_FALSE);
3087         sexp_car(res) = sexp_make_integer(ctx, min);
3088         sexp_cdr(res) = sexp_make_integer(ctx, max);
3089         res = sexp_list2(ctx, res, tmp);
3090         res = sexp_xtype_exception(ctx, self, "invalid uniform vector value", res);
3091         break;
3092       }
3093     }
3094     if (!sexp_exceptionp(res)) {
3095       for (i=0; sexp_pairp(ls); ls=sexp_cdr(ls), i++) {
3096 #if SEXP_USE_UNIFORM_VECTOR_LITERALS
3097         switch (et) {
3098         case SEXP_U1:
3099           sexp_bit_set(res, i, sexp_unbox_fixnum(sexp_car(ls))); break;
3100         case SEXP_S8:
3101           ((signed char*)sexp_uvector_data(res))[i] = sexp_unbox_fixnum(sexp_car(ls)); break;
3102         case SEXP_U8:
3103 #endif
3104           sexp_bytes_set(res, sexp_make_fixnum(i), sexp_car(ls));
3105 #if SEXP_USE_UNIFORM_VECTOR_LITERALS
3106           break;
3107         case SEXP_S16:
3108           ((signed short*)sexp_uvector_data(res))[i] = sexp_unbox_fixnum(sexp_car(ls)); break;
3109         case SEXP_U16:
3110           ((unsigned short*)sexp_uvector_data(res))[i] = sexp_unbox_fixnum(sexp_car(ls)); break;
3111         case SEXP_S32:
3112           ((int32_t*)sexp_uvector_data(res))[i] = sexp_sint_value(sexp_car(ls)); break;
3113         case SEXP_U32:
3114           ((uint32_t*)sexp_uvector_data(res))[i] = sexp_uint_value(sexp_car(ls)); break;
3115         case SEXP_S64:
3116           ((int64_t*)sexp_uvector_data(res))[i] = sexp_sint_value(sexp_car(ls)); break;
3117         case SEXP_U64:
3118           ((uint64_t*)sexp_uvector_data(res))[i] = sexp_uint_value(sexp_car(ls)); break;
3119 #if SEXP_USE_FLONUMS
3120         case SEXP_F32:
3121           ((float*)sexp_uvector_data(res))[i] = sexp_to_double(ctx, sexp_car(ls)); break;
3122         case SEXP_F64:
3123           ((double*)sexp_uvector_data(res))[i] = sexp_to_double(ctx, sexp_car(ls)); break;
3124 #endif
3125 #if SEXP_USE_COMPLEX
3126         case SEXP_C64:
3127           ((float*)sexp_uvector_data(res))[i*2] =
3128             sexp_to_double(ctx, sexp_real_part(sexp_car(ls)));
3129           ((float*)sexp_uvector_data(res))[i*2 + 1] =
3130             sexp_to_double(ctx, sexp_imag_part(sexp_car(ls)));
3131           break;
3132         case SEXP_C128:
3133           ((double*)sexp_uvector_data(res))[i*2] =
3134             sexp_to_double(ctx, sexp_real_part(sexp_car(ls)));
3135           ((double*)sexp_uvector_data(res))[i*2 + 1] =
3136             sexp_to_double(ctx, sexp_imag_part(sexp_car(ls)));
3137           break;
3138 #endif
3139         }
3140 #endif  /* SEXP_USE_UNIFORM_VECTOR_LITERALS */
3141       }
3142     }
3143     sexp_gc_release1(ctx);
3144   }
3145   return res;
3146 }
3147 
3148 sexp sexp_read_one (sexp ctx, sexp in, sexp *shares);
3149 
sexp_read_raw(sexp ctx,sexp in,sexp * shares)3150 sexp sexp_read_raw (sexp ctx, sexp in, sexp *shares) {
3151   char *str;
3152   int c1, c2, line;
3153   sexp tmp2;
3154   sexp_gc_var2(res, tmp);
3155   sexp_gc_preserve2(ctx, res, tmp);
3156 
3157  scan_loop:
3158   switch (c1 = sexp_read_char(ctx, in)) {
3159   case EOF:
3160     res = SEXP_EOF;
3161     break;
3162   case ';':
3163     while ((c1 = sexp_read_char(ctx, in)) != EOF)
3164       if (c1 == '\n')
3165         break;
3166     /* ... FALLTHROUGH ... */
3167   case '\n':
3168     sexp_port_line(in)++;
3169     goto scan_loop;
3170   case ' ':
3171   case '\t':
3172   case '\f':
3173   case '\r':
3174     goto scan_loop;
3175   case '\'':
3176     res = sexp_read_one(ctx, in, shares);
3177     if (! sexp_exceptionp(res))
3178       res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_QUOTE_SYMBOL), res);
3179     break;
3180   case '`':
3181     res = sexp_read_one(ctx, in, shares);
3182     if (! sexp_exceptionp(res))
3183       res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_QUASIQUOTE_SYMBOL), res);
3184     break;
3185   case ',':
3186     if ((c1 = sexp_read_char(ctx, in)) == '@') {
3187       res = sexp_read_one(ctx, in, shares);
3188       if (! sexp_exceptionp(res))
3189         res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_UNQUOTE_SPLICING_SYMBOL), res);
3190     } else {
3191       sexp_push_char(ctx, c1, in);
3192       res = sexp_read_one(ctx, in, shares);
3193       if (! sexp_exceptionp(res))
3194         res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_UNQUOTE_SYMBOL), res);
3195     }
3196     break;
3197   case '"':
3198     res = sexp_read_string(ctx, in, '"');
3199     break;
3200   case '(':
3201     line = (sexp_port_sourcep(in) ? sexp_port_line(in) : -1);
3202     res = SEXP_NULL;
3203     tmp = sexp_read_raw(ctx, in, shares);
3204     while ((tmp != SEXP_EOF) && (tmp != SEXP_CLOSE) && (tmp != SEXP_RAWDOT)) {
3205       if (sexp_exceptionp(tmp)) {
3206         res = tmp;
3207         break;
3208       }
3209       res = sexp_cons(ctx, tmp, res);
3210       if (sexp_port_sourcep(in) && (line >= 0))
3211         sexp_pair_source(res)
3212           = sexp_cons(ctx, sexp_port_name(in), sexp_make_fixnum(line));
3213       tmp = sexp_read_raw(ctx, in, shares);
3214     }
3215     if (! sexp_exceptionp(res)) {
3216       if (tmp == SEXP_RAWDOT) { /* dotted list */
3217         if (res == SEXP_NULL) {
3218           res = sexp_read_error(ctx, "dot before any elements in list",
3219                                 SEXP_NULL, in);
3220         } else {
3221           tmp = sexp_read_raw(ctx, in, shares);
3222           if (sexp_exceptionp(tmp)) {
3223             res = tmp;
3224           } else if (tmp == SEXP_CLOSE) {
3225             res = sexp_read_error(ctx, "no final element in list after dot",
3226                                   SEXP_NULL, in);
3227           } else if (sexp_read_raw(ctx, in, shares) != SEXP_CLOSE) {
3228             res = sexp_read_error(ctx, "multiple tokens in dotted tail",
3229                                   SEXP_NULL, in);
3230           } else if (tmp == SEXP_RAWDOT) {
3231             res = sexp_read_error(ctx, "multiple dots in list",
3232                                   SEXP_NULL, in);
3233           } else {
3234             tmp2 = res;
3235             res = sexp_nreverse(ctx, res);
3236             sexp_cdr(tmp2) = tmp;
3237           }
3238         }
3239       } else if (tmp == SEXP_CLOSE) {
3240         res = (sexp_pairp(res) ? sexp_nreverse(ctx, res) : res);
3241       } else {
3242         res = sexp_read_error(ctx, "missing trailing ')' started on line",
3243                               sexp_make_fixnum(line), in);
3244       }
3245     }
3246     if ((line >= 0) && sexp_pairp(res)) {
3247       sexp_pair_source(res)
3248         = sexp_cons(ctx, sexp_port_name(in), sexp_make_fixnum(line));
3249       for (tmp=sexp_cdr(res); sexp_pairp(tmp); tmp=sexp_cdr(tmp))
3250         sexp_pair_source(tmp) = sexp_pair_source(res);
3251     }
3252     if (sexp_port_sourcep(in))
3253       for (tmp=res; sexp_pairp(tmp); tmp=sexp_cdr(tmp))
3254         sexp_immutablep(tmp) = 1;
3255     break;
3256 #if SEXP_USE_OBJECT_BRACE_LITERALS
3257   case '{':
3258     res = sexp_read_symbol(ctx, in, EOF, 0);
3259     if (!sexp_exceptionp(res)) {
3260       for (c1=' '; isspace(c1); c1=sexp_read_char(ctx, in))
3261         ;
3262       if (c1=='#') {
3263         tmp = sexp_read_one(ctx, in, shares);
3264         if (sexp_symbolp(tmp) && tmp == sexp_intern(ctx, "t", 1))
3265           tmp = SEXP_TRUE;
3266         else if (!sexp_fixnump(tmp))
3267           tmp = sexp_read_error(ctx, "invalid type identifier", tmp, in);
3268       } else if (c1=='"') {
3269         tmp = sexp_read_string(ctx, in, '"');
3270       } else {
3271         tmp = sexp_read_error(ctx, "brace literal missing type identifier", sexp_make_character(c1), in);
3272       }
3273       if (!sexp_exceptionp(tmp)) tmp = sexp_lookup_type(ctx, res, tmp);
3274       if (tmp && sexp_typep(tmp) && sexp_type_tag(tmp) == SEXP_STRING_CURSOR) {
3275         res = sexp_make_string_cursor(sexp_unbox_fixnum(sexp_read_raw(ctx, in, shares)));
3276         tmp2 = sexp_read_raw(ctx, in, shares);
3277         if (tmp2 != SEXP_CLOSE_BRACE)
3278           res = sexp_read_error(ctx, "expected closing brace in string-cursor, got", tmp2, in);
3279       } else if (tmp && sexp_typep(tmp) && sexp_type_print(tmp)
3280           && sexp_opcodep(sexp_type_print(tmp))
3281           && sexp_opcode_func(sexp_type_print(tmp)) == (sexp_proc1)sexp_write_simple_object) {
3282         res = sexp_alloc_tagged(ctx, sexp_type_size_base(tmp), sexp_type_tag(tmp));
3283         for (c1=0; ; c1++) {
3284           tmp2 = sexp_read_raw(ctx, in, shares);
3285           if (sexp_exceptionp(tmp2)) {
3286             res = tmp2;
3287             break;
3288           } else if (tmp2 == SEXP_CLOSE_BRACE) {
3289             break;
3290           } else if (c1 >= sexp_type_field_len_base(tmp)) {
3291             res = sexp_read_error(ctx, "too many slots in object literal", res, in);
3292             break;
3293           } else {
3294             sexp_slot_set(res, c1, tmp2);
3295           }
3296         }
3297       } else {
3298         res = sexp_exceptionp(tmp) ? tmp : sexp_read_error(ctx, "invalid type for brace literals", tmp, in);
3299       }
3300     }
3301     break;
3302 #endif
3303   case '#':
3304     switch (c1=sexp_read_char(ctx, in)) {
3305     case 'b': case 'B':
3306       res = sexp_read_number(ctx, in, 2, 0); break;
3307     case 'o': case 'O':
3308       res = sexp_read_number(ctx, in, 8, 0); break;
3309     case 'd': case 'D':
3310       res = sexp_read_number(ctx, in, 10, 0); break;
3311     case 'x': case 'X':
3312       res = sexp_read_number(ctx, in, 16, 0); break;
3313     case 'e': case 'E':
3314       res = sexp_read_number(ctx, in, 10, 1);
3315 #if SEXP_USE_INFINITIES
3316       if (sexp_flonump(res)
3317           && (isnan(sexp_flonum_value(res)) || isinf(sexp_flonum_value(res))))
3318         res = sexp_read_error(ctx, "can't convert non-finite flonum to exact", res, in);
3319       else
3320 #endif
3321 #if SEXP_USE_COMPLEX
3322       if (sexp_complexp(res))
3323         res = sexp_inexact_to_exact(ctx, NULL, 1, res);
3324       else
3325 #endif
3326       if (sexp_flonump(res))
3327 #if SEXP_USE_RATIOS
3328         res = sexp_double_to_ratio(ctx, sexp_flonum_value(res));
3329 #elif SEXP_USE_BIGNUMS
3330         res = sexp_bignum_normalize(sexp_double_to_bignum(ctx, sexp_flonum_value(res)));
3331 #else
3332         res = sexp_make_fixnum(sexp_flonum_value(res));
3333 #endif
3334       break;
3335     case 'i': case 'I':
3336       res = sexp_read(ctx, in);
3337       if (sexp_exact_integerp(res))
3338         res = sexp_make_flonum(ctx, sexp_unbox_fixnum(res));
3339 #if SEXP_USE_RATIOS
3340       else if (sexp_ratiop(res))
3341         res = sexp_make_flonum(ctx, sexp_ratio_to_double(ctx, res));
3342 #endif
3343       break;
3344     case 'f': case 'F':
3345     case 't': case 'T':
3346       c2 = sexp_read_char(ctx, in);
3347       if (c2 == EOF || sexp_is_separator(c2)) {
3348         res = (sexp_tolower(c1) == 't' ? SEXP_TRUE : SEXP_FALSE);
3349         sexp_push_char(ctx, c2, in);
3350 #if SEXP_USE_UNIFORM_VECTOR_LITERALS
3351       } else if (sexp_isdigit(c2)) {
3352         sexp_push_char(ctx, c2, in);
3353         goto read_uvector;
3354 #endif
3355       } else {
3356         sexp_push_char(ctx, c2, in);
3357         res = sexp_read_symbol(ctx, in, c1, 0);
3358         if (!sexp_exceptionp(res)) {
3359           if (strcasecmp("true", sexp_string_data(res)) == 0)
3360             res = SEXP_TRUE;
3361           else if (strcasecmp("false", sexp_string_data(res)) == 0)
3362             res = SEXP_FALSE;
3363           else
3364             res = sexp_read_error(ctx, "invalid # syntax", res, in);
3365         }
3366       }
3367       break;
3368 #if SEXP_USE_BYTEVECTOR_LITERALS
3369     case 'v': case 'V':
3370       c1 = sexp_read_char(ctx, in);
3371       if (!(c1=='u'||c1=='U')) {
3372         res = sexp_read_error(ctx, "invalid syntax #v%c", sexp_make_character(c1), in);
3373         break;
3374       }
3375       /* ... FALLTHROUGH ... */
3376     case 'u': case 'U':
3377 #if SEXP_USE_UNIFORM_VECTOR_LITERALS
3378     case 's': case 'S':
3379     case 'c': case 'C':
3380     read_uvector:
3381 #endif
3382       res = sexp_read_number(ctx, in, 10, 1);
3383       c2 = sexp_resolve_uniform_type(sexp_tolower(c1), res);
3384       if (sexp_exceptionp(res)) {
3385       } else if (c2 != SEXP_NOT_A_UNIFORM_TYPE) {
3386         tmp = sexp_read_one(ctx, in, shares);
3387         res = sexp_list_to_uvector(ctx, sexp_make_fixnum(c2), tmp);
3388       } else {
3389         tmp = sexp_list2(ctx, sexp_make_character(c1), res);
3390         res = sexp_read_error(ctx, "invalid uniform vector syntax #%c%c", tmp, in);
3391       }
3392       break;
3393 #endif
3394 #if SEXP_USE_READER_LABELS
3395     case '0': case '1': case '2': case '3': case '4':
3396     case '5': case '6': case '7': case '8': case '9':
3397       c2 = digit_value(c1);
3398       while (isdigit(c1=sexp_read_char(ctx, in)))
3399         c2 = c2 * 10 + digit_value(c1);
3400       tmp = sexp_make_fixnum(c2);
3401       if (c1 == '#') {
3402         if (!sexp_vectorp(*shares) ||
3403             tmp > sexp_vector_data(*shares)[sexp_vector_length(*shares)-1] ||
3404             sexp_vector_data(*shares)[c2] == SEXP_VOID) {
3405           res = sexp_read_error(ctx, "unknown reader label", tmp, in);
3406         }
3407         else
3408           res = sexp_vector_data(*shares)[c2];
3409       } else if (c1 == '=') {
3410         if (!sexp_vectorp(*shares)) {
3411           *shares = sexp_make_vector(ctx, sexp_make_fixnum(24), SEXP_VOID);
3412           sexp_vector_data(*shares)[23] = SEXP_ZERO;
3413         }
3414         if (tmp >
3415             sexp_fx_add(sexp_vector_data(*shares)[sexp_vector_length(*shares)-1],
3416                         sexp_make_fixnum(16))) {
3417           res = sexp_read_error(ctx, "reader label out of order", tmp, in);
3418         } else {
3419           if (c2 + 1 >= (int)sexp_vector_length(*shares)) {
3420             tmp2 = sexp_make_vector(ctx, sexp_make_fixnum(sexp_vector_length(*shares)*2), SEXP_VOID);
3421             memcpy(sexp_vector_data(tmp2), sexp_vector_data(*shares), (sexp_vector_length(*shares)-1)*sizeof(sexp));
3422             *shares = tmp2;
3423           }
3424           sexp_vector_data(*shares)[c2] = sexp_make_reader_label(c2);
3425           if (tmp > sexp_vector_data(*shares)[sexp_vector_length(*shares)-1])
3426             sexp_vector_data(*shares)[sexp_vector_length(*shares)-1] = tmp;
3427           res = sexp_read_one(ctx, in, shares);
3428           sexp_vector_data(*shares)[c2] = res;
3429           if (sexp_reader_labelp(res))
3430             res = sexp_read_error(ctx, "self reader label reference", tmp, in);
3431           else
3432             sexp_vector_data(*shares)[c2] = res;
3433         }
3434       } else {
3435         res = sexp_read_error(ctx, "expected # or = after #<n>", sexp_make_character(c1), in);
3436       }
3437       break;
3438 #endif
3439     case ';':
3440       tmp = sexp_read_one(ctx, in, shares);   /* discard */
3441       if (sexp_exceptionp(tmp))
3442         res = tmp;
3443       else
3444         goto scan_loop;
3445       break;
3446     case '|':
3447       for (c2 = 1; c2 > 0 && c1 != EOF; ) {
3448         c1 = sexp_read_char(ctx, in);
3449         if (c1 == '#') {
3450           while ((c1 = sexp_read_char(ctx, in)) == '#')
3451             ;
3452           if (c1 == '|') c2++;
3453         } else if (c1 == '|') {
3454           while ((c1 = sexp_read_char(ctx, in)) == '|')
3455             ;
3456           if (c1 == '#') c2--;
3457         } else if (c1 == '\n') {
3458           sexp_port_line(in)++;
3459         }
3460       }
3461       if (c1 == EOF)
3462         res = sexp_read_error(ctx, "unterminated #| comment", SEXP_NULL, in);
3463       else
3464         goto scan_loop;
3465       break;
3466     case '!':
3467       c1 = sexp_read_char(ctx, in);
3468       if (isspace(c1) || c1 == '/') {
3469         while ((c1 = sexp_read_char(ctx, in)) != EOF)
3470           if (c1 == '\n')
3471             break;
3472         sexp_port_line(in)++;
3473         res = SEXP_VOID;
3474       } else {
3475         sexp_push_char(ctx, c1, in);
3476         res = sexp_read_symbol(ctx, in, '!', 0);
3477         if (SEXP_USE_FOLD_CASE_SYMS && sexp_stringp(res)
3478             && strcasecmp("!fold-case", sexp_string_data(res)) == 0) {
3479           sexp_port_fold_casep(in) = 1;
3480         } else if (SEXP_USE_FOLD_CASE_SYMS && sexp_stringp(res)
3481                    && strcasecmp("!no-fold-case", sexp_string_data(res)) == 0) {
3482           sexp_port_fold_casep(in) = 0;
3483         } else {
3484           res = sexp_read_error(ctx, "unknown #! symbol", res, in);
3485         }
3486       }
3487       if (!sexp_exceptionp(res))
3488         goto scan_loop;
3489       break;
3490     case '\\':
3491       c1 = sexp_read_char(ctx, in);
3492       c2 = sexp_read_char(ctx, in);
3493       sexp_push_char(ctx, c2, in);
3494       if ((c1 == 'x' || c1 == 'X') && (sexp_isxdigit(c2))) {
3495         res = sexp_read_number(ctx, in, 16, 0);
3496         if (sexp_fixnump(res) && sexp_unbox_fixnum(res) >= 0 && sexp_unbox_fixnum(res) <= 0x10FFFF)
3497           res = sexp_make_character(sexp_unbox_fixnum(res));
3498         else if (!sexp_exceptionp(res))
3499           res = sexp_read_error(ctx, "bad character #\\x literal", res, in);
3500       } else {
3501         res = sexp_read_symbol(ctx, in, c1, 0);
3502         if (sexp_stringp(res)) {
3503           str = sexp_string_data(res);
3504           if (sexp_string_size(res) == 0)
3505             res =
3506               sexp_read_error(ctx, "unexpected end of character literal",
3507                               SEXP_NULL, in);
3508           if (sexp_string_size(res) == 1) {
3509             res = sexp_make_character(c1);
3510           } else {
3511             res = 0;
3512             for (c2=0; c2 < sexp_num_char_names; c2++) {
3513               if ((sexp_port_fold_casep(in) ? strcasecmp : strcmp)(str, sexp_char_names[c2].name) == 0) {
3514                 res = sexp_make_character(sexp_char_names[c2].ch);
3515                 break;
3516               }
3517             }
3518             if (!res) {
3519 #if SEXP_USE_UTF8_STRINGS
3520               if ((c1=sexp_decode_utf8_char((unsigned char*)str)) > 0) {
3521                 res = sexp_make_character(c1);
3522                 break;
3523               }
3524 #endif
3525               tmp = sexp_c_string(ctx, str, -1);
3526               res = sexp_read_error(ctx, "unknown character name", tmp, in);
3527             }
3528           }
3529         }
3530       }
3531       break;
3532     case '(':
3533       sexp_push_char(ctx, c1, in);
3534       res = sexp_read_one(ctx, in, shares);
3535       if (sexp_not(sexp_listp(ctx, res))) {
3536         if (! sexp_exceptionp(res)) {
3537           res = sexp_read_error(ctx, "dotted list not allowed in vector syntax",
3538                                 SEXP_NULL,
3539                                 in);
3540         }
3541       } else {
3542         res = sexp_list_to_vector(ctx, res);
3543       }
3544       break;
3545     case '\'':
3546       res = sexp_read_one(ctx, in, shares);
3547       if (! sexp_exceptionp(res))
3548 	res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_SYNTAX_SYMBOL), res);
3549       break;
3550     case '`':
3551       res = sexp_read_one(ctx, in, shares);
3552       if (! sexp_exceptionp(res))
3553 	res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_QUASISYNTAX_SYMBOL), res);
3554       break;
3555     case ',':
3556       if ((c1 = sexp_read_char(ctx, in)) == '@') {
3557 	res = sexp_read_one(ctx, in, shares);
3558 	if (! sexp_exceptionp(res))
3559 	  res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_UNSYNTAX_SPLICING_SYMBOL), res);
3560       } else {
3561 	sexp_push_char(ctx, c1, in);
3562 	res = sexp_read_one(ctx, in, shares);
3563 	if (! sexp_exceptionp(res))
3564 	  res = sexp_list2(ctx, sexp_global(ctx, SEXP_G_UNSYNTAX_SYMBOL), res);
3565       }
3566       break;
3567     default:
3568       res = sexp_read_error(ctx, "invalid char following '#'",
3569                             c1 == EOF ? SEXP_EOF : sexp_make_character(c1), in);
3570     }
3571     break;
3572   case '.':
3573     c1 = sexp_read_char(ctx, in);
3574     sexp_push_char(ctx, c1, in);
3575     if (c1 == EOF || sexp_is_separator(c1)) {
3576       res = SEXP_RAWDOT;
3577     } else if (sexp_isdigit(c1)) {
3578       res = sexp_read_float_tail(ctx, in, 0, 0);
3579     } else {
3580       res = sexp_read_symbol(ctx, in, '.', 1);
3581     }
3582     break;
3583   case ')':
3584     res = SEXP_CLOSE;
3585     break;
3586 #if SEXP_USE_OBJECT_BRACE_LITERALS
3587   case '}':
3588     res = SEXP_CLOSE_BRACE;
3589     break;
3590 #endif
3591   case '|':
3592     res = sexp_read_string(ctx, in, '|');
3593     if (sexp_stringp(res))
3594       res = sexp_intern(ctx, sexp_string_data(res), sexp_string_size(res));
3595     break;
3596   case '+':
3597   case '-':
3598     c2 = sexp_read_char(ctx, in);
3599     if ((c2 == '.' && sexp_isdigit(sexp_peek_char(ctx, in)))
3600         || sexp_isdigit(c2)) {
3601       sexp_push_char(ctx, c2, in);
3602       res = sexp_read_number(ctx, in, 10, 0);
3603       if ((c1 == '-') && ! sexp_exceptionp(res)) {
3604 #if SEXP_USE_FLONUMS
3605         if (sexp_flonump(res))
3606 #if SEXP_USE_IMMEDIATE_FLONUMS
3607           res = sexp_make_flonum(ctx, -1 * sexp_flonum_value(res));
3608 #else
3609           sexp_flonum_value(res) = -1 * sexp_flonum_value(res);
3610 #endif
3611         else
3612 #endif
3613 #if SEXP_USE_BIGNUMS
3614           if (sexp_bignump(res)) {
3615             if ((sexp_bignum_hi(res) == 1)
3616                 && (sexp_bignum_data(res)[0] == (SEXP_MAX_FIXNUM+1)))
3617               res = sexp_make_fixnum(-sexp_bignum_data(res)[0]);
3618             else
3619               sexp_bignum_sign(res) = -sexp_bignum_sign(res);
3620           } else
3621 #endif
3622 #if SEXP_USE_RATIOS
3623           if (sexp_ratiop(res)) {
3624             sexp_negate(sexp_ratio_numerator(res));
3625           } else
3626 #endif
3627 #if SEXP_USE_COMPLEX
3628           if (sexp_complexp(res)) {
3629             if (sexp_complex_real(res) == SEXP_ZERO) {
3630               sexp_negate(sexp_complex_imag(res));
3631             } else {
3632               sexp_negate(sexp_complex_real(res));
3633             }
3634           } else
3635 #endif
3636             res = sexp_fx_mul(res, SEXP_NEG_ONE);
3637       }
3638     } else {
3639       sexp_push_char(ctx, c2, in);
3640       res = sexp_read_symbol(ctx, in, c1, !SEXP_USE_INFINITIES);
3641 #if SEXP_USE_INFINITIES
3642       if (sexp_stringp(res)) {
3643         str = sexp_string_data(res);
3644         if (strcasecmp(str, "+inf.0") == 0)
3645           res = sexp_make_flonum(ctx, sexp_pos_infinity);
3646         else if (strcasecmp(str, "-inf.0") == 0)
3647           res = sexp_make_flonum(ctx, sexp_neg_infinity);
3648         else if (strcasecmp(str+1, "nan.0") == 0)
3649           res = sexp_make_flonum(ctx, sexp_nan);
3650 #if SEXP_USE_COMPLEX
3651         else if (strncasecmp(str+1, "inf.0", 5) == 0) {
3652           tmp = sexp_make_flonum(ctx, c1 == '+' ? sexp_pos_infinity : sexp_neg_infinity);
3653           if (str[6] == 0) {
3654             res = tmp;
3655           } else if ((str[6] == 'i' || str[6] == 'I') && str[7] == 0) {
3656             res = sexp_make_complex(ctx, SEXP_ZERO, tmp);
3657 #if SEXP_USE_MATH
3658           } else if (str[6] == '@') {
3659             res = sexp_substring_cursor(ctx, res, sexp_make_string_cursor(6), SEXP_FALSE);
3660             res = sexp_open_input_string(ctx, res);
3661             res = sexp_read_polar_tail(ctx, res, tmp);
3662 #endif
3663           } else if (str[6] == '+' || str[6] == '-') {
3664             res = sexp_substring_cursor(ctx, res, sexp_make_string_cursor(6), SEXP_FALSE);
3665             res = sexp_string_to_number(ctx, res, SEXP_TEN);
3666             if (sexp_complexp(res) && (sexp_complex_real(res) == SEXP_ZERO))
3667               sexp_complex_real(res) = tmp;
3668             else if (res == SEXP_ZERO)
3669               res = tmp;
3670             else if (!sexp_exceptionp(res))
3671               res = sexp_read_error(ctx, "invalid complex infinity", res, in);
3672           } else {
3673             res = sexp_read_error(ctx, "invalid infinity", res, in);
3674           }
3675         }
3676 #endif
3677         else
3678           res = sexp_intern(ctx, str, sexp_string_size(res));
3679       }
3680 #endif
3681 #if SEXP_USE_COMPLEX
3682       if (res == sexp_intern(ctx, "+i", -1))
3683         res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_ONE);
3684       else if (res == sexp_intern(ctx, "-i", -1))
3685         res = sexp_make_complex(ctx, SEXP_ZERO, SEXP_NEG_ONE);
3686 #endif
3687     }
3688     break;
3689   case '0': case '1': case '2': case '3': case '4':
3690   case '5': case '6': case '7': case '8': case '9':
3691     sexp_push_char(ctx, c1, in);
3692     res = sexp_read_number(ctx, in, 10, 0);
3693     break;
3694   default:
3695     res = sexp_read_symbol(ctx, in, c1, 1);
3696     break;
3697   }
3698 
3699   if (sexp_port_sourcep(in) && sexp_pointerp(res))
3700     sexp_immutablep(res) = 1;
3701   sexp_gc_release2(ctx);
3702   return res;
3703 }
3704 
sexp_read_one(sexp ctx,sexp in,sexp * shares)3705 sexp sexp_read_one (sexp ctx, sexp in, sexp *shares) {
3706   sexp res = sexp_read_raw(ctx, in, shares);
3707   if (res == SEXP_CLOSE)
3708     res = sexp_read_error(ctx, "too many ')'s", SEXP_NULL, in);
3709 #if SEXP_USE_OBJECT_BRACE_LITERALS
3710   else if (res == SEXP_CLOSE_BRACE)
3711     res = sexp_read_error(ctx, "too many '}'s", SEXP_NULL, in);
3712 #endif
3713   else if (res == SEXP_RAWDOT)
3714     res = sexp_read_error(ctx, "unexpected '.'", SEXP_NULL, in);
3715   return res;
3716 }
3717 
sexp_read_op(sexp ctx,sexp self,sexp_sint_t n,sexp in)3718 sexp sexp_read_op (sexp ctx, sexp self, sexp_sint_t n, sexp in) {
3719   sexp res;
3720   sexp_gc_var1(shares);
3721   sexp_assert_type(ctx, sexp_iportp, SEXP_IPORT, in);
3722   sexp_check_block_port(ctx, in, 0);
3723   sexp_gc_preserve1(ctx, shares);
3724   res = sexp_read_one(ctx, in, &shares);
3725 #if SEXP_USE_READER_LABELS
3726   if (!sexp_exceptionp(res) && sexp_vectorp(shares)) {
3727     res = sexp_fill_reader_labels(ctx, res, shares, 1);  /* mark=1 */
3728     res = sexp_fill_reader_labels(ctx, res, shares, 0);  /* mark=0 */
3729   }
3730 #endif
3731   sexp_maybe_unblock_port(ctx, in);
3732   sexp_gc_release1(ctx);
3733   return res;
3734 }
3735 
sexp_read_from_string(sexp ctx,const char * str,sexp_sint_t len)3736 sexp sexp_read_from_string (sexp ctx, const char *str, sexp_sint_t len) {
3737   sexp res;
3738   sexp_gc_var2(s, in);
3739   sexp_gc_preserve2(ctx, s, in);
3740   s = sexp_c_string(ctx, str, len);
3741   in = sexp_open_input_string(ctx, s);
3742   res = sexp_read(ctx, in);
3743   sexp_gc_release2(ctx);
3744   return res;
3745 }
3746 
sexp_string_to_number_op(sexp ctx,sexp self,sexp_sint_t n,sexp str,sexp b)3747 sexp sexp_string_to_number_op (sexp ctx, sexp self, sexp_sint_t n, sexp str, sexp b) {
3748   int base;
3749   sexp_gc_var1(in);
3750   sexp_assert_type(ctx, sexp_stringp, SEXP_STRING, str);
3751   sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, b);
3752   if (((base=sexp_unbox_fixnum(b)) < 2) || (base > 36))
3753     return sexp_user_exception(ctx, self, "invalid numeric base", b);
3754   if (sexp_string_data(str)[0]=='\0'
3755       || (sexp_string_data(str)[1]=='\0' && !sexp_isxdigit((unsigned char)(sexp_string_data(str)[0]))))
3756     return SEXP_FALSE;
3757   sexp_gc_preserve1(ctx, in);
3758   in = sexp_open_input_string(ctx, str);
3759   if (sexp_string_data(str)[0] == '+') {
3760     if (sexp_isdigit((unsigned char)(sexp_string_data(str)[1]))
3761         || sexp_string_data(str)[1] == '.' || sexp_string_data(str)[1] == '#')
3762       sexp_read_char(ctx, in);
3763   }
3764   in = ((sexp_string_data(str)[0] == '#' &&
3765          sexp_tolower((unsigned char)sexp_string_data(str)[1]) != 'e' &&
3766          sexp_tolower((unsigned char)sexp_string_data(str)[1]) != 'i')
3767         || base == 10 ? sexp_read(ctx, in) :
3768         sexp_read_number(ctx, in, base, 0));
3769   sexp_gc_release1(ctx);
3770   return sexp_numberp(in) ? in : SEXP_FALSE;
3771 }
3772 
sexp_write_to_string(sexp ctx,sexp obj)3773 sexp sexp_write_to_string (sexp ctx, sexp obj) {
3774   sexp str;
3775   sexp_gc_var1(out);
3776   sexp_gc_preserve1(ctx, out);
3777   out = sexp_open_output_string(ctx);
3778   str = sexp_write(ctx, obj, out);
3779   if (! sexp_exceptionp(str))
3780     str = sexp_get_output_string(ctx, out);
3781   sexp_gc_release1(ctx);
3782   return str;
3783 }
3784 
sexp_symbol_to_string_op(sexp ctx,sexp self,sexp_sint_t n,sexp sym)3785 sexp sexp_symbol_to_string_op (sexp ctx, sexp self, sexp_sint_t n, sexp sym) {
3786 #if SEXP_USE_HUFF_SYMS
3787   if (sexp_isymbolp(sym)) return sexp_write_to_string(ctx, sym);
3788 #endif
3789   sexp_assert_type(ctx, sexp_lsymbolp, SEXP_SYMBOL, sym);
3790   return sexp_c_string(ctx, sexp_lsymbol_data(sym), sexp_lsymbol_length(sym));
3791 }
3792 
sexp_init(void)3793 void sexp_init (void) {
3794 #if SEXP_USE_GLOBAL_SYMBOLS
3795   int i;
3796 #endif
3797   if (! sexp_initialized_p) {
3798     sexp_initialized_p = 1;
3799 #if SEXP_USE_BOEHM
3800     GC_init();
3801 #if SEXP_USE_GLOBAL_SYMBOLS
3802     GC_add_roots((char*)&sexp_symbol_table,
3803                  ((char*)&sexp_symbol_table)+sizeof(sexp_symbol_table)+1);
3804 #endif
3805 #elif ! SEXP_USE_MALLOC
3806     sexp_gc_init();
3807 #endif
3808 #if SEXP_USE_GLOBAL_SYMBOLS
3809     for (i=0; i<SEXP_SYMBOL_TABLE_SIZE; i++)
3810       sexp_symbol_table[i] = SEXP_NULL;
3811 #endif
3812   }
3813 }
3814