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