Branch data Line data Source code
1 : : extern void *memrchr(const void *s, int c, size_t n);
2 : :
3 : 600 : static void outc(fl_context_t *fl_ctx, char c, ios_t *f)
4 : : {
5 : 600 : ios_putc(c, f);
6 [ - + ]: 600 : if (c == '\n')
7 : 0 : fl_ctx->HPOS = 0;
8 : : else
9 : 600 : fl_ctx->HPOS++;
10 : 600 : }
11 : 1769974 : static void outs(fl_context_t *fl_ctx, const char *s, ios_t *f)
12 : : {
13 : 1769974 : ios_puts(s, f);
14 : 1769974 : fl_ctx->HPOS += u8_strwidth(s);
15 : 1769974 : }
16 : 0 : static void outsn(fl_context_t *fl_ctx, const char *s, ios_t *f, size_t n)
17 : : {
18 : 0 : ios_write(f, s, n);
19 : 0 : fl_ctx->HPOS += u8_strwidth(s);
20 : 0 : }
21 : 0 : static int outindent(fl_context_t *fl_ctx, int n, ios_t *f)
22 : : {
23 : : // move back to left margin if we get too indented
24 [ # # ]: 0 : if (n > fl_ctx->SCR_WIDTH-12)
25 : 0 : n = 2;
26 : 0 : int n0 = n;
27 : 0 : ios_putc('\n', f);
28 : 0 : fl_ctx->VPOS++;
29 : 0 : fl_ctx->HPOS = n;
30 [ # # ]: 0 : while (n >= 8) {
31 : 0 : ios_putc('\t', f);
32 : 0 : n -= 8;
33 : : }
34 [ # # ]: 0 : while (n) {
35 : 0 : ios_putc(' ', f);
36 : 0 : n--;
37 : : }
38 : 0 : return n0;
39 : : }
40 : :
41 : 0 : void fl_print_chr(fl_context_t *fl_ctx, char c, ios_t *f)
42 : : {
43 : 0 : outc(fl_ctx, c, f);
44 : 0 : }
45 : :
46 : 0 : void fl_print_str(fl_context_t *fl_ctx, const char *s, ios_t *f)
47 : : {
48 : 0 : outs(fl_ctx, s, f);
49 : 0 : }
50 : :
51 : 2436440 : void print_traverse(fl_context_t *fl_ctx, value_t v)
52 : : {
53 : : value_t *bp;
54 [ + + ]: 2436860 : while (iscons(v)) {
55 [ - + ]: 432 : if (ismarked(fl_ctx, v)) {
56 : 0 : bp = (value_t*)ptrhash_bp(&fl_ctx->printconses, (void*)v);
57 [ # # ]: 0 : if (*bp == (value_t)HT_NOTFOUND)
58 : 0 : *bp = fixnum(fl_ctx->printlabel++);
59 : 0 : return;
60 : : }
61 : 432 : mark_cons(fl_ctx, v);
62 : 432 : print_traverse(fl_ctx, car_(v));
63 : 432 : v = cdr_(v);
64 : : }
65 [ + + + - : 2436440 : if (!ismanaged(fl_ctx, v) || issymbol(v))
- + ]
66 : 186178 : return;
67 [ - + ]: 2250260 : if (ismarked(fl_ctx, v)) {
68 : 0 : bp = (value_t*)ptrhash_bp(&fl_ctx->printconses, (void*)v);
69 [ # # ]: 0 : if (*bp == (value_t)HT_NOTFOUND)
70 : 0 : *bp = fixnum(fl_ctx->printlabel++);
71 : 0 : return;
72 : : }
73 [ - + ]: 2250260 : if (isvector(v)) {
74 [ # # ]: 0 : if (vector_size(v) > 0)
75 : 0 : mark_cons(fl_ctx, v);
76 : : unsigned int i;
77 [ # # ]: 0 : for(i=0; i < vector_size(v); i++)
78 : 0 : print_traverse(fl_ctx, vector_elt(v,i));
79 : : }
80 [ + + ]: 2250260 : else if (iscprim(v)) {
81 : 1583964 : mark_cons(fl_ctx, v);
82 : : }
83 [ - + - - ]: 666288 : else if (isclosure(v)) {
84 : 0 : mark_cons(fl_ctx, v);
85 : 0 : function_t *f = (function_t*)ptr(v);
86 : 0 : print_traverse(fl_ctx, f->bcode);
87 : 0 : print_traverse(fl_ctx, f->vals);
88 : 0 : print_traverse(fl_ctx, f->env);
89 : : }
90 : : else {
91 [ - + ]: 666288 : assert(iscvalue(v));
92 : 666288 : cvalue_t *cv = (cvalue_t*)ptr(v);
93 : : // don't consider shared references to ""
94 [ + + + + ]: 666288 : if (!cv_isstr(fl_ctx, cv) || cv_len(cv)!=0)
95 : 653398 : mark_cons(fl_ctx, v);
96 : 666288 : fltype_t *t = cv_class(cv);
97 [ - + - - ]: 666288 : if (t->vtable != NULL && t->vtable->print_traverse != NULL)
98 : 0 : t->vtable->print_traverse(fl_ctx, v);
99 : : }
100 : : }
101 : :
102 : 0 : static void print_symbol_name(fl_context_t *fl_ctx, ios_t *f, char *name)
103 : : {
104 : 0 : int i, escape=0, charescape=0;
105 : :
106 [ # # ]: 0 : if ((name[0] == '\0') ||
107 [ # # # # ]: 0 : (name[0] == '.' && name[1] == '\0') ||
108 [ # # # # ]: 0 : (name[0] == '#') ||
109 : 0 : isnumtok(fl_ctx, name, NULL))
110 : 0 : escape = 1;
111 : 0 : i=0;
112 [ # # ]: 0 : while (name[i]) {
113 [ # # ]: 0 : if (!symchar(name[i])) {
114 : 0 : escape = 1;
115 [ # # # # ]: 0 : if (name[i]=='|' || name[i]=='\\') {
116 : 0 : charescape = 1;
117 : 0 : break;
118 : : }
119 : : }
120 : 0 : i++;
121 : : }
122 [ # # ]: 0 : if (escape) {
123 [ # # ]: 0 : if (charescape) {
124 : 0 : outc(fl_ctx, '|', f);
125 : 0 : i=0;
126 [ # # ]: 0 : while (name[i]) {
127 [ # # # # ]: 0 : if (name[i]=='|' || name[i]=='\\')
128 : 0 : outc(fl_ctx, '\\', f);
129 : 0 : outc(fl_ctx, name[i], f);
130 : 0 : i++;
131 : : }
132 : 0 : outc(fl_ctx, '|', f);
133 : : }
134 : : else {
135 : 0 : outc(fl_ctx, '|', f);
136 : 0 : outs(fl_ctx, name, f);
137 : 0 : outc(fl_ctx, '|', f);
138 : : }
139 : : }
140 : : else {
141 : 0 : outs(fl_ctx, name, f);
142 : : }
143 : 0 : }
144 : :
145 : : /*
146 : : The following implements a simple pretty-printing algorithm. This is
147 : : an unlimited-width approach that doesn't require an extra pass.
148 : : It uses some heuristics to guess whether an expression is "small",
149 : : and avoids wrapping symbols across lines. The result is high
150 : : performance and nice output for typical code. Quality is poor for
151 : : pathological or deeply-nested expressions, but those are difficult
152 : : to print anyway.
153 : : */
154 : : #define SMALL_STR_LEN 20
155 : 600 : static inline int tinyp(fl_context_t *fl_ctx, value_t v)
156 : : {
157 [ + + ]: 600 : if (issymbol(v))
158 : 408 : return (u8_strwidth(symbol_name(fl_ctx, v)) < SMALL_STR_LEN);
159 [ - + ]: 192 : if (fl_isstring(fl_ctx, v))
160 : 0 : return (cv_len((cvalue_t*)ptr(v)) < SMALL_STR_LEN);
161 [ + - - + : 384 : return (isfixnum(v) || isbuiltin(v) || v==fl_ctx->F || v==fl_ctx->T || v==fl_ctx->NIL ||
- - + - +
- + - ]
162 [ - + ]: 192 : v == fl_ctx->FL_EOF);
163 : : }
164 : :
165 : 384 : static int smallp(fl_context_t *fl_ctx, value_t v)
166 : : {
167 [ + + ]: 384 : if (tinyp(fl_ctx, v)) return 1;
168 [ - + ]: 96 : if (fl_isnumber(fl_ctx, v)) return 1;
169 [ + + ]: 96 : if (iscons(v)) {
170 [ + - + - ]: 72 : if (tinyp(fl_ctx, car_(v)) && (tinyp(fl_ctx, cdr_(v)) ||
171 [ + - + + ]: 72 : (iscons(cdr_(v)) && tinyp(fl_ctx, car_(cdr_(v))) &&
172 [ + - ]: 48 : cdr_(cdr_(v))==fl_ctx->NIL)))
173 : 48 : return 1;
174 : 24 : return 0;
175 : : }
176 [ - + ]: 24 : if (isvector(v)) {
177 : 0 : size_t s = vector_size(v);
178 [ # # # # : 0 : return (s == 0 || (tinyp(fl_ctx, vector_elt(v,0)) &&
# # ]
179 [ # # # # ]: 0 : (s == 1 || (s == 2 &&
180 : 0 : tinyp(fl_ctx, vector_elt(v,1))))));
181 : : }
182 : 24 : return 0;
183 : : }
184 : :
185 : 168 : static int specialindent(fl_context_t *fl_ctx, value_t head)
186 : : {
187 : : // indent these forms 2 spaces, not lined up with the first argument
188 [ + - + - : 168 : if (head == fl_ctx->LAMBDA || head == fl_ctx->TRYCATCH || head == fl_ctx->definesym ||
+ - ]
189 [ + - - + ]: 168 : head == fl_ctx->defmacrosym || head == fl_ctx->forsym)
190 : 0 : return 2;
191 : 168 : return -1;
192 : : }
193 : :
194 : 0 : static int lengthestimate(fl_context_t *fl_ctx, value_t v)
195 : : {
196 : : // get the width of an expression if we can do so cheaply
197 [ # # ]: 0 : if (issymbol(v))
198 : 0 : return u8_strwidth(symbol_name(fl_ctx, v));
199 : 0 : return -1;
200 : : }
201 : :
202 : 168 : static int allsmallp(fl_context_t *fl_ctx, value_t v)
203 : : {
204 : 168 : int n = 1;
205 [ + + ]: 504 : while (iscons(v)) {
206 [ + + ]: 384 : if (!smallp(fl_ctx, car_(v)))
207 : 48 : return 0;
208 : 336 : v = cdr_(v);
209 : 336 : n++;
210 [ - + ]: 336 : if (n > 25)
211 : 0 : return n;
212 : : }
213 : 120 : return n;
214 : : }
215 : :
216 : 168 : static int indentafter3(fl_context_t *fl_ctx, value_t head, value_t v)
217 : : {
218 : : // for certain X always indent (X a b c) after b
219 [ - + - - ]: 168 : return ((head == fl_ctx->forsym) && !allsmallp(fl_ctx, cdr_(v)));
220 : : }
221 : :
222 : 168 : static int indentafter2(fl_context_t *fl_ctx, value_t head, value_t v)
223 : : {
224 : : // for certain X always indent (X a b) after a
225 [ + - - + : 168 : return ((head == fl_ctx->definesym || head == fl_ctx->defmacrosym) &&
- - ]
226 : 0 : !allsmallp(fl_ctx, cdr_(v)));
227 : : }
228 : :
229 : 168 : static int indentevery(fl_context_t *fl_ctx, value_t v)
230 : : {
231 : : // indent before every subform of a special form, unless every
232 : : // subform is "small"
233 : 168 : value_t c = car_(v);
234 [ + - - + ]: 168 : if (c == fl_ctx->LAMBDA || c == fl_ctx->setqsym)
235 : 0 : return 0;
236 [ - + ]: 168 : if (c == fl_ctx->IF) // TODO: others
237 : 0 : return !allsmallp(fl_ctx, cdr_(v));
238 : 168 : return 0;
239 : : }
240 : :
241 : 168 : static int blockindent(fl_context_t *fl_ctx, value_t v)
242 : : {
243 : : // in this case we switch to block indent mode, where the head
244 : : // is no longer considered special:
245 : : // (a b c d e
246 : : // f g h i j)
247 : 168 : return (allsmallp(fl_ctx, v) > 9);
248 : : }
249 : :
250 : 168 : static void print_pair(fl_context_t *fl_ctx, ios_t *f, value_t v)
251 : : {
252 : : value_t cd;
253 : 168 : char *op = NULL;
254 [ + - + + : 240 : if (iscons(cdr_(v)) && cdr_(cdr_(v)) == fl_ctx->NIL &&
+ - ]
255 : 72 : !ptrhash_has(&fl_ctx->printconses, (void*)cdr_(v)) &&
256 [ - + ]: 72 : (((car_(v) == fl_ctx->QUOTE) && (op = "'")) ||
257 [ - + ]: 72 : ((car_(v) == fl_ctx->BACKQUOTE) && (op = "`")) ||
258 [ - + ]: 72 : ((car_(v) == fl_ctx->COMMA) && (op = ",")) ||
259 [ - + ]: 72 : ((car_(v) == fl_ctx->COMMAAT) && (op = ",@")) ||
260 [ - + ]: 72 : ((car_(v) == fl_ctx->COMMADOT) && (op = ",.")))) {
261 : : // special prefix syntax
262 : 0 : unmark_cons(fl_ctx, v);
263 : 0 : unmark_cons(fl_ctx, cdr_(v));
264 : 0 : outs(fl_ctx, op, f);
265 : 0 : fl_print_child(fl_ctx, f, car_(cdr_(v)));
266 : 0 : return;
267 : : }
268 : 168 : int startpos = fl_ctx->HPOS;
269 : 168 : outc(fl_ctx, '(', f);
270 : 168 : int newindent=fl_ctx->HPOS, blk=blockindent(fl_ctx, v);
271 : 168 : int lastv, n=0, si, ind=0, est, always=0, nextsmall, thistiny;
272 [ + - ]: 168 : if (!blk) always = indentevery(fl_ctx, v);
273 : 168 : value_t head = car_(v);
274 : 168 : int after3 = indentafter3(fl_ctx, head, v);
275 : 168 : int after2 = indentafter2(fl_ctx, head, v);
276 : 168 : int n_unindented = 1;
277 : : while (1) {
278 : 432 : cd = cdr_(v);
279 [ - + - - : 432 : if (fl_ctx->print_length >= 0 && n >= fl_ctx->print_length && cd!=fl_ctx->NIL) {
- - ]
280 : 0 : outsn(fl_ctx, "...)", f, 4);
281 : 0 : break;
282 : : }
283 : 432 : lastv = fl_ctx->VPOS;
284 : 432 : unmark_cons(fl_ctx, v);
285 : 432 : fl_print_child(fl_ctx, f, car_(v));
286 [ + + - + ]: 432 : if (!iscons(cd) || ptrhash_has(&fl_ctx->printconses, (void*)cd)) {
287 [ - + ]: 168 : if (cd != fl_ctx->NIL) {
288 : 0 : outsn(fl_ctx, " . ", f, 3);
289 : 0 : fl_print_child(fl_ctx, f, cd);
290 : : }
291 : 168 : outc(fl_ctx, ')', f);
292 : 168 : break;
293 : : }
294 : :
295 [ - + ]: 264 : if (!fl_ctx->print_pretty ||
296 [ # # # # ]: 0 : ((head == fl_ctx->LAMBDA) && n == 0)) {
297 : : // never break line before lambda-list
298 : 264 : ind = 0;
299 : : }
300 : : else {
301 : 0 : est = lengthestimate(fl_ctx, car_(cd));
302 : 0 : nextsmall = smallp(fl_ctx, car_(cd));
303 : 0 : thistiny = tinyp(fl_ctx, car_(v));
304 : 0 : ind = (((fl_ctx->VPOS > lastv) ||
305 [ # # # # : 0 : (fl_ctx->HPOS>fl_ctx->SCR_WIDTH/2 && !nextsmall && !thistiny && n>0)) ||
# # # # ]
306 : :
307 [ # # # # ]: 0 : (fl_ctx->HPOS > fl_ctx->SCR_WIDTH-4) ||
308 : :
309 [ # # ]: 0 : (est!=-1 && (fl_ctx->HPOS+est > fl_ctx->SCR_WIDTH-2)) ||
310 : :
311 [ # # # # : 0 : ((head == fl_ctx->LAMBDA) && !nextsmall) ||
# # ]
312 : :
313 [ # # # # ]: 0 : (n > 0 && always) ||
314 : :
315 [ # # # # ]: 0 : (n == 2 && after3) ||
316 [ # # # # ]: 0 : (n == 1 && after2) ||
317 : :
318 [ # # # # : 0 : (n_unindented >= 3 && !nextsmall) ||
# # ]
319 : :
320 [ # # ]: 0 : (n == 0 && !smallp(fl_ctx, head)));
321 : : }
322 : :
323 [ - + ]: 264 : if (ind) {
324 : 0 : newindent = outindent(fl_ctx, newindent, f);
325 : 0 : n_unindented = 1;
326 : : }
327 : : else {
328 : 264 : n_unindented++;
329 : 264 : outc(fl_ctx, ' ', f);
330 [ + + ]: 264 : if (n==0) {
331 : : // set indent level after printing head
332 : 168 : si = specialindent(fl_ctx, head);
333 [ - + ]: 168 : if (si != -1)
334 : 0 : newindent = startpos + si;
335 [ + - ]: 168 : else if (!blk)
336 : 168 : newindent = fl_ctx->HPOS;
337 : : }
338 : : }
339 : 264 : n++;
340 : 264 : v = cd;
341 : : }
342 : : }
343 : :
344 : : static void cvalue_print(fl_context_t *fl_ctx, ios_t *f, value_t v);
345 : :
346 : 2250420 : static int print_circle_prefix(fl_context_t *fl_ctx, ios_t *f, value_t v)
347 : : {
348 : : value_t label;
349 : : char buf[64];
350 : : char *str;
351 [ - + ]: 2250420 : if ((label=(value_t)ptrhash_get(&fl_ctx->printconses, (void*)v)) !=
352 : : (value_t)HT_NOTFOUND) {
353 [ # # ]: 0 : if (!ismarked(fl_ctx, v)) {
354 : : //fl_ctx->HPOS+=ios_printf(f, "#%ld#", numval(label));
355 : 0 : outc(fl_ctx, '#', f);
356 : 0 : str = uint2str(buf, sizeof(buf)-1, numval(label), 10);
357 : 0 : outs(fl_ctx, str, f);
358 : 0 : outc(fl_ctx, '#', f);
359 : 0 : return 1;
360 : : }
361 : : //fl_ctx->HPOS+=ios_printf(f, "#%ld=", numval(label));
362 : 0 : outc(fl_ctx, '#', f);
363 : 0 : str = uint2str(buf, sizeof(buf)-1, numval(label), 10);
364 : 0 : outs(fl_ctx, str, f);
365 : 0 : outc(fl_ctx, '=', f);
366 : : }
367 [ + - + - ]: 2250420 : if (ismanaged(fl_ctx, v))
368 : 2250420 : unmark_cons(fl_ctx, v);
369 : 2250420 : return 0;
370 : : }
371 : :
372 : 2436440 : void fl_print_child(fl_context_t *fl_ctx, ios_t *f, value_t v)
373 : : {
374 : : char *name, *str;
375 : : char buf[64];
376 [ - + - - ]: 2436440 : if (fl_ctx->print_level >= 0 && fl_ctx->P_LEVEL >= fl_ctx->print_level &&
377 [ # # # # : 0 : (iscons(v) || isvector(v) || isclosure(v))) {
# # # # ]
378 : 0 : outc(fl_ctx, '#', f);
379 : 0 : return;
380 : : }
381 : 2436440 : fl_ctx->P_LEVEL++;
382 : :
383 [ + + - + : 2436440 : switch (tag(v)) {
+ - ]
384 : 61106 : case TAG_NUM :
385 : : case TAG_NUM1: //fl_ctx->HPOS+=ios_printf(f, "%ld", numval(v)); break;
386 : 61106 : str = uint2str(&buf[1], sizeof(buf)-1, labs(numval(v)), 10);
387 [ - + ]: 61106 : if (numval(v)<0)
388 : 0 : *(--str) = '-';
389 : 61106 : outs(fl_ctx, str, f);
390 : 61106 : break;
391 : 124904 : case TAG_SYM:
392 : 124904 : name = symbol_name(fl_ctx, v);
393 [ + - ]: 124904 : if (fl_ctx->print_princ)
394 : 124904 : outs(fl_ctx, name, f);
395 [ # # # # ]: 0 : else if (ismanaged(fl_ctx, v)) {
396 : 0 : outsn(fl_ctx, "#:", f, 2);
397 : 0 : outs(fl_ctx, name, f);
398 : : }
399 : : else
400 : 0 : print_symbol_name(fl_ctx, f, name);
401 : 124904 : break;
402 : 0 : case TAG_FUNCTION:
403 [ # # ]: 0 : if (v == fl_ctx->T) {
404 : 0 : outsn(fl_ctx, "#t", f, 2);
405 : : }
406 [ # # ]: 0 : else if (v == fl_ctx->F) {
407 : 0 : outsn(fl_ctx, "#f", f, 2);
408 : : }
409 [ # # ]: 0 : else if (v == fl_ctx->NIL) {
410 : 0 : outsn(fl_ctx, "()", f, 2);
411 : : }
412 [ # # ]: 0 : else if (v == fl_ctx->FL_EOF) {
413 : 0 : outsn(fl_ctx, "#<eof>", f, 6);
414 : : }
415 [ # # # # ]: 0 : else if (isbuiltin(v)) {
416 [ # # ]: 0 : if (!fl_ctx->print_princ)
417 : 0 : outsn(fl_ctx, "#.", f, 2);
418 : 0 : outs(fl_ctx, builtin_names[uintval(v)], f);
419 : : }
420 : : else {
421 [ # # # # ]: 0 : assert(isclosure(v));
422 [ # # ]: 0 : if (!fl_ctx->print_princ) {
423 [ # # ]: 0 : if (print_circle_prefix(fl_ctx, f, v)) break;
424 : 0 : function_t *fn = (function_t*)ptr(v);
425 : 0 : outs(fl_ctx, "#fn(", f);
426 : 0 : char *data = (char*)cvalue_data(fn->bcode);
427 : 0 : size_t i, sz = cvalue_len(fn->bcode);
428 [ # # ]: 0 : for(i=0; i < sz; i++) data[i] += 48;
429 : 0 : fl_print_child(fl_ctx, f, fn->bcode);
430 [ # # ]: 0 : for(i=0; i < sz; i++) data[i] -= 48;
431 : 0 : outc(fl_ctx, ' ', f);
432 : 0 : fl_print_child(fl_ctx, f, fn->vals);
433 [ # # ]: 0 : if (fn->env != fl_ctx->NIL) {
434 : 0 : outc(fl_ctx, ' ', f);
435 : 0 : fl_print_child(fl_ctx, f, fn->env);
436 : : }
437 [ # # ]: 0 : if (fn->name != fl_ctx->LAMBDA) {
438 : 0 : outc(fl_ctx, ' ', f);
439 : 0 : fl_print_child(fl_ctx, f, fn->name);
440 : : }
441 : 0 : outc(fl_ctx, ')', f);
442 : : }
443 : : else {
444 : 0 : outs(fl_ctx, "#<function>", f);
445 : : }
446 : : }
447 : 0 : break;
448 : 2250260 : case TAG_CVALUE:
449 : : case TAG_CPRIM:
450 [ - + ]: 2250260 : if (v == UNBOUND) { outs(fl_ctx, "#<undefined>", f); break; }
451 : : JL_FALLTHROUGH;
452 : : case TAG_VECTOR:
453 : : case TAG_CONS:
454 [ - + ]: 2250420 : if (print_circle_prefix(fl_ctx, f, v)) break;
455 [ - + ]: 2250420 : if (isvector(v)) {
456 : 0 : outc(fl_ctx, '[', f);
457 : 0 : int newindent = fl_ctx->HPOS, est;
458 : 0 : int i, sz = vector_size(v);
459 [ # # ]: 0 : for(i=0; i < sz; i++) {
460 [ # # # # : 0 : if (fl_ctx->print_length >= 0 && i >= fl_ctx->print_length && i < sz-1) {
# # ]
461 : 0 : outsn(fl_ctx, "...", f, 3);
462 : 0 : break;
463 : : }
464 : 0 : fl_print_child(fl_ctx, f, vector_elt(v,i));
465 [ # # ]: 0 : if (i < sz-1) {
466 [ # # ]: 0 : if (!fl_ctx->print_pretty) {
467 : 0 : outc(fl_ctx, ' ', f);
468 : : }
469 : : else {
470 : 0 : est = lengthestimate(fl_ctx, vector_elt(v,i+1));
471 [ # # # # ]: 0 : if (fl_ctx->HPOS > fl_ctx->SCR_WIDTH-4 ||
472 [ # # ]: 0 : (est!=-1 && (fl_ctx->HPOS+est > fl_ctx->SCR_WIDTH-2)) ||
473 [ # # # # ]: 0 : (fl_ctx->HPOS > fl_ctx->SCR_WIDTH/2 &&
474 [ # # ]: 0 : !smallp(fl_ctx, vector_elt(v,i+1)) &&
475 : 0 : !tinyp(fl_ctx, vector_elt(v,i))))
476 : 0 : newindent = outindent(fl_ctx, newindent, f);
477 : : else
478 : 0 : outc(fl_ctx, ' ', f);
479 : : }
480 : : }
481 : : }
482 : 0 : outc(fl_ctx, ']', f);
483 : 0 : break;
484 : : }
485 [ + + + + ]: 2250420 : if (iscvalue(v) || iscprim(v))
486 : 2250260 : cvalue_print(fl_ctx, f, v);
487 : : else
488 : 168 : print_pair(fl_ctx, f, v);
489 : 2250420 : break;
490 : : }
491 : 2436440 : fl_ctx->P_LEVEL--;
492 : : }
493 : :
494 : 0 : static void print_string(fl_context_t *fl_ctx, ios_t *f, char *str, size_t sz)
495 : : {
496 : : char buf[512];
497 : 0 : size_t i = 0;
498 : : uint8_t c;
499 : : static const char hexdig[] = "0123456789abcdef";
500 : :
501 : 0 : outc(fl_ctx, '"', f);
502 [ # # ]: 0 : if (!u8_isvalid(str, sz)) {
503 : : // alternate print algorithm that preserves data if it's not UTF-8
504 [ # # ]: 0 : for(i=0; i < sz; i++) {
505 : 0 : c = str[i];
506 [ # # ]: 0 : if (c == '\\')
507 : 0 : outsn(fl_ctx, "\\\\", f, 2);
508 [ # # ]: 0 : else if (c == '"')
509 : 0 : outsn(fl_ctx, "\\\"", f, 2);
510 [ # # # # ]: 0 : else if (c >= 32 && c < 0x7f)
511 : 0 : outc(fl_ctx, c, f);
512 : : else {
513 : 0 : outsn(fl_ctx, "\\x", f, 2);
514 : 0 : outc(fl_ctx, hexdig[c>>4], f);
515 : 0 : outc(fl_ctx, hexdig[c&0xf], f);
516 : : }
517 : : }
518 : : }
519 : : else {
520 [ # # ]: 0 : while (i < sz) {
521 : 0 : size_t n = u8_escape(buf, sizeof(buf), str, &i, sz, 1, 0);
522 : 0 : outsn(fl_ctx, buf, f, n-1);
523 : : }
524 : : }
525 : 0 : outc(fl_ctx, '"', f);
526 : 0 : }
527 : :
528 : : static numerictype_t sym_to_numtype(fl_context_t *fl_ctx, value_t type);
529 : : #ifndef _OS_WINDOWS_
530 : : #define __USE_GNU
531 : : #include <dlfcn.h>
532 : : #undef __USE_GNU
533 : : #endif
534 : :
535 : : #define sign_bit(r) ((*(int64_t*)&(r)) & BIT63)
536 : : #define DFINITE(d) (((*(int64_t*)&(d))&0x7ff0000000000000LL)!=0x7ff0000000000000LL)
537 : :
538 : : // 'weak' means we don't need to accurately reproduce the type, so
539 : : // for example #int32(0) can be printed as just 0. this is used
540 : : // printing in a context where a type is already implied, e.g. inside
541 : : // an array.
542 : 2250260 : static void cvalue_printdata(fl_context_t *fl_ctx, ios_t *f, void *data,
543 : : size_t len, value_t type, int weak)
544 : : {
545 [ - + ]: 2250260 : if (type == fl_ctx->bytesym) {
546 : 0 : unsigned char ch = *(unsigned char*)data;
547 [ # # ]: 0 : if (fl_ctx->print_princ)
548 : 0 : outc(fl_ctx, ch, f);
549 [ # # ]: 0 : else if (weak)
550 : 0 : fl_ctx->HPOS+=ios_printf(f, "0x%hhx", ch);
551 : : else
552 : 0 : fl_ctx->HPOS+=ios_printf(f, "#byte(0x%hhx)", ch);
553 : : }
554 [ + + ]: 2250260 : else if (type == fl_ctx->wcharsym) {
555 : 1583964 : uint32_t wc = *(uint32_t*)data;
556 : : char seq[8];
557 : 1583964 : size_t nb = u8_toutf8(seq, sizeof(seq), &wc, 1);
558 : 1583964 : seq[nb] = '\0';
559 [ + - ]: 1583964 : if (fl_ctx->print_princ) {
560 : : // TODO: better multibyte handling
561 : 1583964 : outs(fl_ctx, seq, f);
562 : : }
563 : : else {
564 : 0 : outsn(fl_ctx, "#\\", f, 2);
565 [ # # ]: 0 : if (wc == 0x00) outsn(fl_ctx, "nul", f, 3);
566 [ # # ]: 0 : else if (wc == 0x07) outsn(fl_ctx, "alarm", f, 5);
567 [ # # ]: 0 : else if (wc == 0x08) outsn(fl_ctx, "backspace", f, 9);
568 [ # # ]: 0 : else if (wc == 0x09) outsn(fl_ctx, "tab", f, 3);
569 [ # # ]: 0 : else if (wc == 0x0A) outsn(fl_ctx, "linefeed", f, 8);
570 : : //else if (wc == 0x0A) outsn(fl_ctx, "newline", f, 7);
571 [ # # ]: 0 : else if (wc == 0x0B) outsn(fl_ctx, "vtab", f, 4);
572 [ # # ]: 0 : else if (wc == 0x0C) outsn(fl_ctx, "page", f, 4);
573 [ # # ]: 0 : else if (wc == 0x0D) outsn(fl_ctx, "return", f, 6);
574 [ # # ]: 0 : else if (wc == 0x1B) outsn(fl_ctx, "esc", f, 3);
575 [ # # ]: 0 : else if (wc == 0x20) outsn(fl_ctx, "space", f, 5);
576 [ # # ]: 0 : else if (wc == 0x7F) outsn(fl_ctx, "delete", f, 6);
577 [ # # ]: 0 : else if (iswprint(wc)) outs(fl_ctx, seq, f);
578 : 0 : else fl_ctx->HPOS+=ios_printf(f, "x%04x", (int)wc);
579 : : }
580 : : }
581 [ + - - + ]: 666288 : else if (type == fl_ctx->floatsym || type == fl_ctx->doublesym) {
582 : : char buf[64];
583 : : double d;
584 [ # # ]: 0 : if (type == fl_ctx->floatsym) { d = (double)*(float*)data; }
585 : 0 : else { d = *(double*)data; }
586 [ # # ]: 0 : if (!DFINITE(d)) {
587 : : char *rep;
588 [ # # ]: 0 : if (d != d)
589 [ # # ]: 0 : rep = (char*)(sign_bit(d) ? "-nan.0" : "+nan.0");
590 : : else
591 [ # # ]: 0 : rep = (char*)(sign_bit(d) ? "-inf.0" : "+inf.0");
592 [ # # # # : 0 : if (type == fl_ctx->floatsym && !fl_ctx->print_princ && !weak)
# # ]
593 : 0 : fl_ctx->HPOS+=ios_printf(f, "#%s(%s)", symbol_name(fl_ctx, type), rep);
594 : : else
595 : 0 : outs(fl_ctx, rep, f);
596 : : }
597 [ # # ]: 0 : else if (d == 0) {
598 [ # # ]: 0 : if (sign_bit(d))
599 : 0 : outsn(fl_ctx, "-0.0", f, 4);
600 : : else
601 : 0 : outsn(fl_ctx, "0.0", f, 3);
602 [ # # # # : 0 : if (type == fl_ctx->floatsym && !fl_ctx->print_princ && !weak)
# # ]
603 : 0 : outc(fl_ctx, 'f', f);
604 : : }
605 : : else {
606 [ # # ]: 0 : double ad = d < 0 ? -d : d;
607 [ # # # # : 0 : if ((long)d == d && ad < 1e6 && ad >= 1e-4) {
# # ]
608 : 0 : snprintf(buf, sizeof(buf), "%g", d);
609 : : }
610 : : else {
611 [ # # ]: 0 : if (type == fl_ctx->floatsym)
612 : 0 : snprintf(buf, sizeof(buf), "%.8g", d);
613 : : else
614 : 0 : snprintf(buf, sizeof(buf), "%.16g", d);
615 : : }
616 : 0 : int hasdec = (strpbrk(buf, ".eE") != NULL);
617 : 0 : outs(fl_ctx, buf, f);
618 [ # # ]: 0 : if (!hasdec) outsn(fl_ctx, ".0", f, 2);
619 [ # # # # : 0 : if (type == fl_ctx->floatsym && !fl_ctx->print_princ && !weak)
# # ]
620 : 0 : outc(fl_ctx, 'f', f);
621 : : }
622 : : }
623 [ + - ]: 666288 : else if (type == fl_ctx->uint64sym
624 : : #ifdef _P64
625 [ - + ]: 666288 : || type == fl_ctx->sizesym
626 : : #endif
627 : 0 : ) {
628 : 0 : uint64_t ui64 = *(uint64_t*)data;
629 [ # # # # ]: 0 : if (weak || fl_ctx->print_princ)
630 : 0 : fl_ctx->HPOS += ios_printf(f, "%llu", ui64);
631 : : else
632 : 0 : fl_ctx->HPOS += ios_printf(f, "#%s(%llu)", symbol_name(fl_ctx, type), ui64);
633 : : }
634 [ + + ]: 666288 : else if (issymbol(type)) {
635 : : // handle other integer prims. we know it's smaller than uint64
636 : : // at this point, so int64 is big enough to capture everything.
637 : 24 : numerictype_t nt = sym_to_numtype(fl_ctx, type);
638 [ + - ]: 24 : if (nt == N_NUMTYPES) {
639 : : // These states should be context independent.
640 : : static size_t (*volatile jl_static_print)(ios_t*, void*) = NULL;
641 : : static volatile int init = 0;
642 : : // XXX: use uv_once
643 [ + + ]: 24 : if (init == 0) {
644 : : #if defined(RTLD_SELF)
645 : : jl_static_print = (size_t (*)(ios_t*, void*))
646 : : (uintptr_t)dlsym(RTLD_SELF, "ijl_static_show");
647 : : #elif defined(RTLD_DEFAULT)
648 : 4 : jl_static_print = (size_t (*)(ios_t*, void*))
649 : 4 : (uintptr_t)dlsym(RTLD_DEFAULT, "ijl_static_show");
650 : : #elif defined(_OS_WINDOWS_)
651 : : HMODULE handle;
652 : : if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
653 : : GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
654 : : (LPCWSTR)(&cvalue_printdata),
655 : : &handle)) {
656 : : jl_static_print = (size_t (*)(ios_t*, void*))
657 : : (uintptr_t)GetProcAddress(handle, "ijl_static_show");
658 : : }
659 : : #endif
660 : 4 : init = 1;
661 : : }
662 [ + - + - ]: 24 : if (jl_static_print != NULL && fl_ctx->jl_sym == type) {
663 : 24 : fl_ctx->HPOS += ios_printf(f, "#<julia: ");
664 : 24 : fl_ctx->HPOS += jl_static_print(f, *(void**)data);
665 : 24 : fl_ctx->HPOS += ios_printf(f, ">");
666 : : }
667 : : else
668 : 0 : fl_ctx->HPOS += ios_printf(f, "#<%s>", symbol_name(fl_ctx, type));
669 : : }
670 : : else {
671 : 0 : int64_t i64 = conv_to_int64(data, nt);
672 [ # # # # ]: 0 : if (weak || fl_ctx->print_princ)
673 : 0 : fl_ctx->HPOS += ios_printf(f, "%lld", i64);
674 : : else
675 : 0 : fl_ctx->HPOS += ios_printf(f, "#%s(%lld)", symbol_name(fl_ctx, type), i64);
676 : : }
677 : : }
678 [ + - ]: 666264 : else if (iscons(type)) {
679 [ + - ]: 666264 : if (car_(type) == fl_ctx->arraysym) {
680 : 666264 : value_t eltype = car(fl_ctx, cdr_(type));
681 : : size_t cnt, elsize;
682 [ - + ]: 666264 : if (iscons(cdr_(cdr_(type)))) {
683 : 0 : cnt = tosize(fl_ctx, car_(cdr_(cdr_(type))), "length");
684 [ # # ]: 0 : elsize = cnt ? len/cnt : 0;
685 : : }
686 : : else {
687 : : // incomplete array type
688 : : int junk;
689 : 666264 : elsize = ctype_sizeof(fl_ctx, eltype, &junk);
690 [ + - ]: 666264 : cnt = elsize ? len/elsize : 0;
691 : : }
692 [ + - ]: 666264 : if (eltype == fl_ctx->bytesym) {
693 [ + - ]: 666264 : if (fl_ctx->print_princ) {
694 : 666264 : ios_write(f, (char*)data, len);
695 : : /*
696 : : char *nl = memrchr(data, '\n', len);
697 : : if (nl)
698 : : fl_ctx->HPOS = u8_strwidth(nl+1);
699 : : else
700 : : fl_ctx->HPOS += u8_strwidth(data);
701 : : */
702 : : }
703 : : else {
704 : 0 : print_string(fl_ctx, f, (char*)data, len);
705 : : }
706 : 666264 : return;
707 : : }
708 : 0 : else if (eltype == fl_ctx->wcharsym) {
709 : : // TODO wchar
710 : : }
711 : : else {
712 : : }
713 : : size_t i;
714 [ # # ]: 0 : if (!weak) {
715 [ # # ]: 0 : if (eltype == fl_ctx->uint8sym) {
716 : 0 : outsn(fl_ctx, "#vu8(", f, 5);
717 : : }
718 : : else {
719 : 0 : outsn(fl_ctx, "#array(", f, 7);
720 : 0 : fl_print_child(fl_ctx, f, eltype);
721 [ # # ]: 0 : if (cnt > 0)
722 : 0 : outc(fl_ctx, ' ', f);
723 : : }
724 : : }
725 : : else {
726 : 0 : outc(fl_ctx, '[', f);
727 : : }
728 [ # # ]: 0 : for(i=0; i < cnt; i++) {
729 [ # # ]: 0 : if (i > 0)
730 : 0 : outc(fl_ctx, ' ', f);
731 : 0 : cvalue_printdata(fl_ctx, f, data, elsize, eltype, 1);
732 : 0 : data = (char *)data + elsize;
733 : : }
734 [ # # ]: 0 : if (!weak)
735 : 0 : outc(fl_ctx, ')', f);
736 : : else
737 : 0 : outc(fl_ctx, ']', f);
738 : : }
739 : : }
740 : : }
741 : :
742 : 2250260 : static void cvalue_print(fl_context_t *fl_ctx, ios_t *f, value_t v)
743 : : {
744 : 2250260 : cvalue_t *cv = (cvalue_t*)ptr(v);
745 [ + + ]: 2250260 : void *data = cptr(v);
746 : : value_t label;
747 : :
748 [ - + ]: 2250260 : if (cv_class(cv) == fl_ctx->builtintype) {
749 : 0 : void *fptr = *(void**)data;
750 : 0 : label = (value_t)ptrhash_get(&fl_ctx->reverse_dlsym_lookup_table, cv);
751 [ # # ]: 0 : if (label == (value_t)HT_NOTFOUND) {
752 : 0 : fl_ctx->HPOS += ios_printf(f, "#<builtin @0x%08zx>", (size_t)fptr);
753 : : }
754 : : else {
755 [ # # ]: 0 : if (fl_ctx->print_princ) {
756 : 0 : outs(fl_ctx, symbol_name(fl_ctx, label), f);
757 : : }
758 : : else {
759 : 0 : outsn(fl_ctx, "#fn(", f, 4);
760 : 0 : outs(fl_ctx, symbol_name(fl_ctx, label), f);
761 : 0 : outc(fl_ctx, ')', f);
762 : : }
763 : : }
764 : : }
765 [ - + ]: 2250260 : else if (cv_class(cv)->vtable != NULL &&
766 [ # # ]: 0 : cv_class(cv)->vtable->print != NULL) {
767 : 0 : cv_class(cv)->vtable->print(fl_ctx, v, f);
768 : : }
769 : : else {
770 : 2250260 : value_t type = cv_type(cv);
771 [ + + ]: 2250260 : size_t len = iscprim(v) ? cv_class(cv)->size : cv_len(cv);
772 : 2250260 : cvalue_printdata(fl_ctx, f, data, len, type, 0);
773 : : }
774 : 2250260 : }
775 : :
776 : 115360 : static void set_print_width(fl_context_t *fl_ctx)
777 : : {
778 : 115360 : value_t pw = symbol_value(fl_ctx->printwidthsym);
779 [ - + ]: 115360 : if (!isfixnum(pw)) return;
780 : 115360 : fl_ctx->SCR_WIDTH = numval(pw);
781 : : }
782 : :
783 : 2436000 : void fl_print(fl_context_t *fl_ctx, ios_t *f, value_t v)
784 : : {
785 : 2436000 : fl_ctx->print_pretty = (symbol_value(fl_ctx->printprettysym) != fl_ctx->F);
786 [ + + ]: 2436000 : if (fl_ctx->print_pretty)
787 : 115360 : set_print_width(fl_ctx);
788 : 2436000 : fl_ctx->print_princ = (symbol_value(fl_ctx->printreadablysym) == fl_ctx->F);
789 : :
790 : 2436000 : value_t pl = symbol_value(fl_ctx->printlengthsym);
791 [ - + ]: 2436000 : if (isfixnum(pl)) fl_ctx->print_length = numval(pl);
792 : 2436000 : else fl_ctx->print_length = -1;
793 : 2436000 : pl = symbol_value(fl_ctx->printlevelsym);
794 [ - + ]: 2436000 : if (isfixnum(pl)) fl_ctx->print_level = numval(pl);
795 : 2436000 : else fl_ctx->print_level = -1;
796 : 2436000 : fl_ctx->P_LEVEL = 0;
797 : :
798 : 2436000 : fl_ctx->printlabel = 0;
799 : 2436000 : print_traverse(fl_ctx, v);
800 : 2436000 : fl_ctx->HPOS = fl_ctx->VPOS = 0;
801 : :
802 : 2436000 : fl_print_child(fl_ctx, f, v);
803 : :
804 [ + - - + ]: 2436000 : if (fl_ctx->print_level >= 0 || fl_ctx->print_length >= 0) {
805 : 0 : memset(fl_ctx->consflags, 0, 4*bitvector_nwords(fl_ctx->heapsize/sizeof(cons_t)));
806 : : }
807 : :
808 [ + + + - : 3102340 : if ((iscons(v) || isvector(v) || isfunction(v) || iscvalue(v)) &&
- + - - +
+ + + ]
809 [ + - + - : 666408 : !fl_isstring(fl_ctx, v) && v!=fl_ctx->T && v!=fl_ctx->F && v!=fl_ctx->NIL) {
+ - ]
810 : 72 : htable_reset(&fl_ctx->printconses, 32);
811 : : }
812 : 2436000 : }
813 : :
814 : 30 : void fl_print_init(fl_context_t *fl_ctx)
815 : : {
816 : 30 : htable_new(&fl_ctx->printconses, 32);
817 : 30 : fl_ctx->SCR_WIDTH = 80;
818 : 30 : fl_ctx->HPOS = 0;
819 : 30 : }
|