1 /* Copyright (C) 1995,1996,1997 Free Software Foundation, Inc.
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
47 #include "mbstrings.h"
60 /* {Names of immediate symbols}
62 * This table must agree with the declarations in scm.h: {Immediate Symbols}.
65 char *scm_isymnames
[] =
67 /* This table must agree with the declarations */
83 "#@literal-variable-ref",
84 "#@literal-variable-set!",
87 "#@call-with-current-continuation",
89 /* user visible ISYMS */
101 scm_option scm_print_opts
[] = {
102 { SCM_OPTION_SCM
, "closure-hook", SCM_BOOL_F
,
103 "Hook for printing closures." },
104 { SCM_OPTION_BOOLEAN
, "source", 0,
105 "Print closures with source." }
108 SCM_PROC (s_print_options
, "print-options-interface", 0, 1, 0, scm_print_options
);
111 scm_print_options (setting
)
114 SCM ans
= scm_options (setting
,
122 /* {Printing of Scheme Objects}
125 /* Detection of circular references.
127 * Due to other constraints in the implementation, this code has bad
128 * time complexity (O (depth * N)), The printer code will be
129 * completely rewritten before next release of Guile. The new code
132 #define PUSH_REF(pstate, obj) \
134 pstate->ref_stack[pstate->top++] = (obj); \
135 if (pstate->top == pstate->ceiling) \
136 grow_ref_stack (pstate); \
139 #define ENTER_NESTED_DATA(pstate, obj, label) \
142 for (i = 0; i < pstate->top; ++i) \
143 if (pstate->ref_stack[i] == (obj)) \
145 if (pstate->fancyp) \
147 if (pstate->top - pstate->list_offset >= pstate->level) \
149 scm_gen_putc ('#', port); \
153 PUSH_REF(pstate, obj); \
156 #define EXIT_NESTED_DATA(pstate) { --pstate->top; }
158 SCM scm_print_state_vtable
;
160 static SCM print_state_pool
;
162 #ifdef GUILE_DEBUG /* Used for debugging purposes */
163 SCM_PROC(s_current_pstate
, "current-pstate", 0, 0, 0, scm_current_pstate
);
166 scm_current_pstate ()
168 return SCM_CADR (print_state_pool
);
172 #define PSTATE_SIZE 50L
174 static SCM make_print_state
SCM_P ((void));
179 SCM print_state
= scm_make_struct (SCM_CAR (print_state_pool
), /* pstate type */
182 scm_print_state
*pstate
= SCM_PRINT_STATE (print_state
);
183 pstate
->ref_vect
= scm_make_vector (SCM_MAKINUM (PSTATE_SIZE
),
186 pstate
->ref_stack
= SCM_VELTS (pstate
->ref_vect
);
187 pstate
->ceiling
= SCM_LENGTH (pstate
->ref_vect
);
192 scm_make_print_state ()
196 /* First try to allocate a print state from the pool */
198 if (SCM_NNULLP (SCM_CDR (print_state_pool
)))
200 answer
= SCM_CADR (print_state_pool
);
201 SCM_SETCDR (print_state_pool
, SCM_CDDR (print_state_pool
));
205 return answer
? answer
: make_print_state ();
209 scm_free_print_state (print_state
)
213 scm_print_state
*pstate
= SCM_PRINT_STATE (print_state
);
214 /* Cleanup before returning print state to pool.
215 * It is better to do it here. Doing it in scm_prin1
216 * would cost more since that function is called much more
220 pstate
->revealed
= 0;
221 SCM_NEWCELL (handle
);
223 SCM_SETCAR (handle
, print_state
);
224 SCM_SETCDR (handle
, SCM_CDR (print_state_pool
));
225 SCM_SETCDR (print_state_pool
, handle
);
229 static void grow_ref_stack
SCM_P ((scm_print_state
*pstate
));
232 grow_ref_stack (pstate
)
233 scm_print_state
*pstate
;
235 int new_size
= 2 * pstate
->ceiling
;
236 scm_vector_set_length_x (pstate
->ref_vect
, SCM_MAKINUM (new_size
));
237 pstate
->ref_stack
= SCM_VELTS (pstate
->ref_vect
);
238 pstate
->ceiling
= new_size
;
242 static void print_circref
SCM_P ((SCM port
, scm_print_state
*pstate
, SCM ref
));
245 print_circref (port
, pstate
, ref
)
247 scm_print_state
*pstate
;
251 int self
= pstate
->top
- 1;
253 if (SCM_CONSP (pstate
->ref_stack
[i
]))
257 if (SCM_NCONSP (pstate
->ref_stack
[i
- 1])
258 || SCM_CDR (pstate
->ref_stack
[i
- 1]) != pstate
->ref_stack
[i
])
264 for (i
= pstate
->top
- 1; 1; --i
)
265 if (pstate
->ref_stack
[i
] == ref
)
267 scm_gen_putc ('#', port
);
268 scm_intprint (i
- self
, 10, port
);
269 scm_gen_putc ('#', port
);
272 /* Print generally. Handles both write and display according to PSTATE.
277 scm_iprin1 (exp
, port
, pstate
)
280 scm_print_state
*pstate
;
284 switch (7 & (int) exp
)
288 scm_intprint (SCM_INUM (exp
), 10, port
);
294 scm_put_wchar (i
, port
, SCM_WRITINGP (pstate
));
297 else if (SCM_IFLAGP (exp
)
298 && (SCM_ISYMNUM (exp
) < (sizeof scm_isymnames
/ sizeof (char *))))
299 scm_gen_puts (scm_regular_string
, SCM_ISYMCHARS (exp
), port
);
300 else if (SCM_ILOCP (exp
))
302 scm_gen_puts (scm_regular_string
, "#@", port
);
303 scm_intprint ((long) SCM_IFRAME (exp
), 10, port
);
304 scm_gen_putc (SCM_ICDRP (exp
) ? '-' : '+', port
);
305 scm_intprint ((long) SCM_IDIST (exp
), 10, port
);
312 scm_gen_puts (scm_regular_string
, "#@", port
);
313 exp
= SCM_CAR (exp
- 1);
317 scm_ipruk ("immediate", exp
, port
);
320 switch (SCM_TYP7 (exp
))
322 case scm_tcs_cons_gloc
:
324 if (SCM_CDR (SCM_CAR (exp
) - 1L) == 0)
326 ENTER_NESTED_DATA (pstate
, exp
, circref
);
327 scm_print_struct (exp
, port
, pstate
);
328 EXIT_NESTED_DATA (pstate
);
332 case scm_tcs_cons_imcar
:
333 case scm_tcs_cons_nimcar
:
334 ENTER_NESTED_DATA (pstate
, exp
, circref
);
335 scm_iprlist ("(", exp
, ')', port
, pstate
);
336 EXIT_NESTED_DATA (pstate
);
339 print_circref (port
, pstate
, exp
);
342 if (!SCM_CLOSUREP (SCM_CDR (exp
)))
344 case scm_tcs_closures
:
345 /* The user supplied print closure procedure must handle
346 macro closures as well. */
347 if (SCM_FALSEP (scm_procedure_p (SCM_PRINT_CLOSURE
))
348 || SCM_FALSEP (scm_printer_apply (SCM_PRINT_CLOSURE
,
349 exp
, port
, pstate
)));
352 if (SCM_TYP16 (exp
) == scm_tc16_macro
)
354 /* Printing a macro. */
356 name
= scm_macro_name (exp
);
357 if (!SCM_CLOSUREP (SCM_CDR (exp
)))
360 scm_gen_puts (scm_regular_string
, "#<primitive-",
365 code
= SCM_CODE (SCM_CDR (exp
));
366 scm_gen_puts (scm_regular_string
, "#<", port
);
368 if (SCM_CAR (exp
) & (3L << 16))
369 scm_gen_puts (scm_regular_string
, "macro", port
);
371 scm_gen_puts (scm_regular_string
, "syntax", port
);
372 if (SCM_CAR (exp
) & (2L << 16))
373 scm_gen_putc ('!', port
);
377 /* Printing a closure. */
378 name
= scm_procedure_name (exp
);
379 code
= SCM_CODE (exp
);
380 scm_gen_puts (scm_regular_string
, "#<procedure",
383 if (SCM_NIMP (name
) && SCM_ROSTRINGP (name
))
385 scm_gen_putc (' ', port
);
386 scm_gen_puts (scm_regular_string
, SCM_ROCHARS (name
), port
);
390 scm_gen_putc (' ', port
);
391 scm_iprin1 (SCM_CAR (code
), port
, pstate
);
393 if (code
&& SCM_PRINT_SOURCE_P
)
395 code
= scm_unmemocopy (SCM_CDR (code
),
396 SCM_EXTEND_ENV (SCM_CAR (code
),
399 ENTER_NESTED_DATA (pstate
, exp
, circref
);
400 scm_iprlist (" ", code
, '>', port
, pstate
);
401 EXIT_NESTED_DATA (pstate
);
404 scm_gen_putc ('>', port
);
407 case scm_tc7_mb_string
:
408 case scm_tc7_mb_substring
:
409 scm_print_mb_string (exp
, port
, SCM_WRITINGP (pstate
));
411 case scm_tc7_substring
:
413 if (SCM_WRITINGP (pstate
))
415 scm_gen_putc ('"', port
);
416 for (i
= 0; i
< SCM_ROLENGTH (exp
); ++i
)
417 switch (SCM_ROCHARS (exp
)[i
])
421 scm_gen_putc ('\\', port
);
423 scm_gen_putc (SCM_ROCHARS (exp
)[i
], port
);
425 scm_gen_putc ('"', port
);
429 scm_gen_write (scm_regular_string
, SCM_ROCHARS (exp
),
430 (scm_sizet
) SCM_ROLENGTH (exp
),
433 case scm_tcs_symbols
:
434 if (SCM_MB_STRINGP (exp
))
436 scm_print_mb_symbol (exp
, port
);
449 len
= SCM_LENGTH (exp
);
450 str
= SCM_CHARS (exp
);
457 scm_gen_write (scm_regular_string
, "#{}#", 4, port
);
459 for (end
= pos
; end
< len
; ++end
)
462 #ifdef BRACKETS_AS_PARENS
470 case SCM_WHITE_SPACES
:
471 case SCM_LINE_INCREMENTORS
:
480 scm_gen_write (scm_regular_string
, "#{", 2, port
);
485 scm_gen_write (scm_regular_string
, str
+ pos
, end
- pos
, port
);
491 scm_gen_write (scm_regular_string
, buf
, 2, port
);
513 scm_gen_write (scm_regular_string
, str
+ pos
, end
- pos
, port
);
515 scm_gen_write (scm_regular_string
, "}#", 2, port
);
519 ENTER_NESTED_DATA (pstate
, exp
, circref
);
520 if (SCM_IS_WHVEC (exp
))
521 scm_gen_puts (scm_regular_string
, "#wh(", port
);
523 scm_gen_puts (scm_regular_string
, "#w(", port
);
524 goto common_vector_printer
;
527 ENTER_NESTED_DATA (pstate
, exp
, circref
);
528 scm_gen_puts (scm_regular_string
, "#(", port
);
529 common_vector_printer
:
531 int last
= SCM_LENGTH (exp
) - 1;
533 if (pstate
->fancyp
&& SCM_LENGTH (exp
) > pstate
->length
)
535 last
= pstate
->length
- 1;
538 for (i
= 0; i
< last
; ++i
)
541 scm_iprin1 (SCM_VELTS (exp
)[i
], port
, pstate
);
542 scm_gen_putc (' ', port
);
547 scm_iprin1 (SCM_VELTS (exp
)[i
], port
, pstate
);
550 scm_gen_puts (scm_regular_string
, " ...", port
);
551 scm_gen_putc (')', port
);
553 EXIT_NESTED_DATA (pstate
);
566 scm_raprin1 (exp
, port
, pstate
);
569 scm_gen_puts (scm_regular_string
, "#<primitive-procedure ", port
);
570 scm_gen_puts ((SCM_MB_STRINGP (SCM_SNAME(exp
))
572 : scm_regular_string
),
573 SCM_CHARS (SCM_SNAME (exp
)), port
);
574 scm_gen_putc ('>', port
);
578 scm_gen_puts (scm_regular_string
, "#<compiled-closure ", port
);
579 scm_iprin1 (SCM_CCLO_SUBR (exp
), port
, pstate
);
580 scm_gen_putc ('>', port
);
584 scm_gen_puts (scm_regular_string
, "#<continuation ", port
);
585 scm_intprint (SCM_LENGTH (exp
), 10, port
);
586 scm_gen_puts (scm_regular_string
, " @ ", port
);
587 scm_intprint ((long) SCM_CHARS (exp
), 16, port
);
588 scm_gen_putc ('>', port
);
591 i
= SCM_PTOBNUM (exp
);
593 && scm_ptobs
[i
].print
594 && (scm_ptobs
[i
].print
) (exp
, port
, pstate
))
598 ENTER_NESTED_DATA (pstate
, exp
, circref
);
599 i
= SCM_SMOBNUM (exp
);
600 if (i
< scm_numsmob
&& scm_smobs
[i
].print
601 && (scm_smobs
[i
].print
) (exp
, port
, pstate
))
603 EXIT_NESTED_DATA (pstate
);
606 EXIT_NESTED_DATA (pstate
);
607 /* Macros have their print field set to NULL. They are
608 handled at the same place as closures in order to achieve
609 non-redundancy. Placing the condition here won't slow
610 down printing of other smobs. */
611 if (SCM_TYP16 (exp
) == scm_tc16_macro
)
615 scm_ipruk ("type", exp
, port
);
620 /* Print states are necessary for circular reference safe printing.
621 * They are also expensive to allocate. Therefore print states are
622 * kept in a pool so that they can be reused.
625 /* The PORT argument can also be a print-state/port pair, which will
626 * then be used instead of allocating a new print state. This is
627 * useful for continuing a chain of print calls from Scheme. */
630 scm_prin1 (exp
, port
, writingp
)
635 SCM handle
= SCM_BOOL_F
; /* Will GC protect the handle whilst unlinked */
637 scm_print_state
*pstate
;
639 /* If PORT is a print-state/port pair, use that. Else create a new
642 if (SCM_NIMP (port
) && SCM_CONSP (port
))
644 pstate_scm
= SCM_CDR (port
);
645 port
= SCM_CAR (port
);
649 /* First try to allocate a print state from the pool */
651 if (SCM_NNULLP (SCM_CDR (print_state_pool
)))
653 handle
= SCM_CDR (print_state_pool
);
654 SCM_SETCDR (print_state_pool
, SCM_CDDR (print_state_pool
));
657 if (handle
== SCM_BOOL_F
)
658 handle
= scm_cons (make_print_state (), SCM_EOL
);
659 pstate_scm
= SCM_CAR (handle
);
662 pstate
= SCM_PRINT_STATE (pstate_scm
);
663 pstate
->writingp
= writingp
;
664 scm_iprin1 (exp
, port
, pstate
);
666 /* Return print state to pool if it has been created above and
667 hasn't escaped to Scheme. */
669 if (handle
!= SCM_BOOL_F
&& !pstate
->revealed
)
672 SCM_SETCDR (handle
, SCM_CDR (print_state_pool
));
673 SCM_SETCDR (print_state_pool
, handle
);
683 scm_intprint (n
, radix
, port
)
688 char num_buf
[SCM_INTBUFLEN
];
689 scm_gen_write (scm_regular_string
, num_buf
, scm_iint2str (n
, radix
, num_buf
), port
);
692 /* Print an object of unrecognized type.
696 scm_ipruk (hdr
, ptr
, port
)
701 scm_gen_puts (scm_regular_string
, "#<unknown-", port
);
702 scm_gen_puts (scm_regular_string
, hdr
, port
);
705 scm_gen_puts (scm_regular_string
, " (0x", port
);
706 scm_intprint (SCM_CAR (ptr
), 16, port
);
707 scm_gen_puts (scm_regular_string
, " . 0x", port
);
708 scm_intprint (SCM_CDR (ptr
), 16, port
);
709 scm_gen_puts (scm_regular_string
, ") @", port
);
711 scm_gen_puts (scm_regular_string
, " 0x", port
);
712 scm_intprint (ptr
, 16, port
);
713 scm_gen_putc ('>', port
);
721 scm_iprlist (hdr
, exp
, tlr
, port
, pstate
)
726 scm_print_state
*pstate
;
729 register SCM hare
, tortoise
;
730 int floor
= pstate
->top
- 2;
731 scm_gen_puts (scm_regular_string
, hdr
, port
);
736 /* Run a hare and tortoise so that total time complexity will be
737 O(depth * N) instead of O(N^2). */
738 hare
= SCM_CDR (exp
);
740 while (SCM_NIMP (hare
) && SCM_ECONSP (hare
))
742 if (hare
== tortoise
)
744 hare
= SCM_CDR (hare
);
745 if (SCM_IMP (hare
) || SCM_NECONSP (hare
))
747 hare
= SCM_CDR (hare
);
748 tortoise
= SCM_CDR (tortoise
);
751 /* No cdr cycles intrinsic to this list */
752 scm_iprin1 (SCM_CAR (exp
), port
, pstate
);
754 for (; SCM_NIMP (exp
); exp
= SCM_CDR (exp
))
756 if (SCM_NECONSP (exp
))
758 for (i
= floor
; i
>= 0; --i
)
759 if (pstate
->ref_stack
[i
] == exp
)
761 PUSH_REF (pstate
, exp
);
762 scm_gen_putc (' ', port
);
764 scm_iprin1 (SCM_CAR (exp
), port
, pstate
);
766 if (SCM_NNULLP (exp
))
768 scm_gen_puts (scm_regular_string
, " . ", port
);
769 scm_iprin1 (exp
, port
, pstate
);
773 scm_gen_putc (tlr
, port
);
774 pstate
->top
= floor
+ 2;
779 int n
= pstate
->length
;
781 scm_iprin1 (SCM_CAR (exp
), port
, pstate
);
782 exp
= SCM_CDR (exp
); --n
;
783 for (; SCM_NIMP (exp
); exp
= SCM_CDR (exp
))
785 if (SCM_NECONSP (exp
))
787 for (i
= 0; i
< pstate
->top
; ++i
)
788 if (pstate
->ref_stack
[i
] == exp
)
794 scm_gen_puts (scm_regular_string
, " ...", port
);
800 PUSH_REF(pstate
, exp
);
801 ++pstate
->list_offset
;
802 scm_gen_putc (' ', port
);
804 scm_iprin1 (SCM_CAR (exp
), port
, pstate
);
807 if (SCM_NNULLP (exp
))
809 scm_gen_puts (scm_regular_string
, " . ", port
);
810 scm_iprin1 (exp
, port
, pstate
);
813 pstate
->list_offset
-= pstate
->top
- floor
- 2;
817 pstate
->list_offset
-= pstate
->top
- floor
- 2;
820 scm_gen_puts (scm_regular_string
, " . ", port
);
821 print_circref (port
, pstate
, exp
);
828 scm_valid_oport_value_p (SCM val
)
830 return SCM_NIMP (val
) &&
831 (SCM_OPOUTPORTP (val
) || (SCM_CONSP (val
) && SCM_NIMP (SCM_CAR (val
)) &&
832 SCM_OPOUTPORTP (SCM_CAR (val
)) &&
833 SCM_PRINT_STATE_P (SCM_CDR (val
))));
836 SCM_PROC(s_write
, "write", 1, 1, 0, scm_write
);
839 scm_write (obj
, port
)
843 if (SCM_UNBNDP (port
))
846 SCM_ASSERT (scm_valid_oport_value_p (port
), port
, SCM_ARG2
, s_write
);
848 scm_prin1 (obj
, port
, 1);
852 scm_close_port (port
);
855 return SCM_UNSPECIFIED
;
859 SCM_PROC(s_display
, "display", 1, 1, 0, scm_display
);
862 scm_display (obj
, port
)
866 if (SCM_UNBNDP (port
))
869 SCM_ASSERT (scm_valid_oport_value_p (port
), port
, SCM_ARG2
, s_display
);
871 scm_prin1 (obj
, port
, 0);
875 scm_close_port (port
);
878 return SCM_UNSPECIFIED
;
881 SCM_PROC(s_newline
, "newline", 0, 1, 0, scm_newline
);
887 if (SCM_UNBNDP (port
))
890 SCM_ASSERT (scm_valid_oport_value_p (port
), port
, SCM_ARG1
, s_newline
);
892 scm_gen_putc ('\n', SCM_COERCE_OPORT (port
));
896 scm_close_port (port
);
900 if (port
== scm_cur_outp
)
902 return SCM_UNSPECIFIED
;
905 SCM_PROC(s_write_char
, "write-char", 1, 1, 0, scm_write_char
);
908 scm_write_char (chr
, port
)
912 if (SCM_UNBNDP (port
))
915 SCM_ASSERT (scm_valid_oport_value_p (port
), port
, SCM_ARG2
, s_write_char
);
917 SCM_ASSERT (SCM_ICHRP (chr
), chr
, SCM_ARG1
, s_write_char
);
918 scm_gen_putc ((int) SCM_ICHR (chr
), SCM_COERCE_OPORT (port
));
922 scm_close_port (port
);
925 return SCM_UNSPECIFIED
;
930 /* Call back to Scheme code to do the printing of special objects
931 (like structs). SCM_PRINTER_APPLY applies PROC to EXP and a pair
932 containing PORT and PSTATE. This pair can be used as the port for
933 display/write etc to continue the current print chain. The REVEALED
934 field of PSTATE is set to true to indicate that the print state has
935 escaped to Scheme and thus has to be freed by the GC. */
938 scm_printer_apply (proc
, exp
, port
, pstate
)
940 scm_print_state
*pstate
;
942 SCM pair
= scm_cons (port
, pstate
->handle
);
943 pstate
->revealed
= 1;
944 return scm_apply (proc
, exp
, scm_cons (pair
, scm_listofnull
));
954 scm_init_opts (scm_print_options
, scm_print_opts
, SCM_N_PRINT_OPTIONS
);
955 vtable
= scm_make_vtable_vtable (scm_make_struct_layout (scm_nullstr
), SCM_INUM0
, SCM_EOL
);
956 type
= scm_make_struct (vtable
,
958 scm_cons (scm_make_struct_layout (scm_makfrom0str (SCM_PRINT_STATE_LAYOUT
)),
960 print_state_pool
= scm_permanent_object (scm_cons (type
, SCM_EOL
));
962 scm_print_state_vtable
= type
;