write.scm 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
  2. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  3. ; This is file write.scm.
  4. ;;;; WRITE
  5. ; To use this with some Scheme other than Scheme 48, do the following:
  6. ; 1. Copy the definition of output-port-option from port.scm
  7. ; 2. Define write-string as appropriate (as a write-char loop)
  8. ; 3. (define (disclose x) #f)
  9. (define (write obj . port-option)
  10. (let ((port (output-port-option port-option)))
  11. (if (and (output-port? port)
  12. (open-output-port? port))
  13. (let recur ((obj obj))
  14. (recurring-write obj port recur))
  15. (call-error "invalid port argument" write port))))
  16. (define (recurring-write obj port recur)
  17. (cond ((null? obj) (write-string "()" port))
  18. ((pair? obj) (write-list obj port recur))
  19. ((eq? obj #t) (write-boolean 't port))
  20. ((eq? obj #f) (write-boolean 'f port))
  21. ((symbol? obj) (write-string (symbol->string obj) port))
  22. ((number? obj) (write-number obj port))
  23. ((string? obj) (write-string-literal obj port))
  24. ((char? obj) (write-char-literal obj port))
  25. (else (write-other obj port recur))))
  26. (define (write-boolean mumble port)
  27. (write-char #\# port)
  28. (write mumble port))
  29. (define (write-number n port)
  30. (write-string (number->string n 10) port))
  31. (define (write-char-literal obj port)
  32. (let ((probe (character-name obj)))
  33. (write-string "#\\" port)
  34. (if probe
  35. (write probe port)
  36. (write-char obj port))))
  37. ; These are from Matthew Flatt's Unicode proposal for R6RS
  38. ; See read.scm.
  39. ; Don't use non-R5RS char literals to avoid bootstrap circularities
  40. (define *nul* (scalar-value->char 0))
  41. (define *alarm* (scalar-value->char 7))
  42. (define *backspace* (scalar-value->char 8))
  43. (define *tab* (scalar-value->char 9))
  44. (define *linefeed* (scalar-value->char 10))
  45. (define *vtab* (scalar-value->char 11))
  46. (define *page* (scalar-value->char 12))
  47. (define *return* (scalar-value->char 13))
  48. (define *escape* (scalar-value->char 27))
  49. (define *rubout* (scalar-value->char 127))
  50. (define *char-name-table*
  51. (list
  52. (cons #\space 'space)
  53. (cons #\newline 'newline)
  54. (cons *nul* 'nul)
  55. (cons *alarm* 'alarm)
  56. (cons *backspace* 'backspace)
  57. (cons *tab* 'tab)
  58. (cons *linefeed* 'linefeed)
  59. (cons *vtab* 'vtab)
  60. (cons *page* 'page)
  61. (cons *return* 'return)
  62. (cons *escape* 'escape)
  63. (cons *rubout* 'rubout)))
  64. (define (character-name char)
  65. (cond ((assq char *char-name-table*)
  66. => cdr)
  67. (else #f)))
  68. (define (write-string-literal obj port)
  69. (write-char #\" port)
  70. (let ((len (string-length obj)))
  71. (do ((i 0 (+ i 1)))
  72. ((= i len) (write-char #\" port))
  73. (let ((c (string-ref obj i)))
  74. (cond
  75. ((or (char=? c #\\) (char=? c #\")
  76. (char=? c #\') (char=? c #\newline)) ; proposed for R6RS
  77. (write-char #\\ port)
  78. (write-char c port))
  79. ;; the following were all proposed for R6RS
  80. ((char=? c *alarm*) (write-string "\\a" port))
  81. ((char=? c *backspace*) (write-string "\\b" port))
  82. ((char=? c *tab*) (write-string "\\t" port))
  83. ((char=? c *linefeed*) (write-string "\\n" port))
  84. ((char=? c *vtab*) (write-string "\\v" port))
  85. ((char=? c *page*) (write-string "\\f" port))
  86. ((char=? c *return*) (write-string "\\r" port))
  87. ((char=? c *escape*) (write-string "\\e" port))
  88. (else
  89. (write-char c port)))))))
  90. (define (write-list obj port recur)
  91. (cond ((quotation? obj)
  92. (write-char #\' port)
  93. (recur (cadr obj)))
  94. (else
  95. (write-char #\( port)
  96. (recur (car obj))
  97. (let loop ((l (cdr obj))
  98. (n 1))
  99. (cond ((not (pair? l))
  100. (cond ((not (null? l))
  101. (write-string " . " port)
  102. (recur l))))
  103. (else
  104. (write-char #\space port)
  105. (recur (car l))
  106. (loop (cdr l) (+ n 1)))))
  107. (write-char #\) port))))
  108. (define (quotation? obj)
  109. (and (pair? obj)
  110. (eq? (car obj) 'quote)
  111. (pair? (cdr obj))
  112. (null? (cddr obj))))
  113. (define (write-vector obj port recur)
  114. (write-string "#(" port)
  115. (let ((z (vector-length obj)))
  116. (cond ((> z 0)
  117. (recur (vector-ref obj 0))
  118. (let loop ((i 1))
  119. (cond ((>= i z))
  120. (else
  121. (write-char #\space port)
  122. (recur (vector-ref obj i))
  123. (loop (+ i 1))))))))
  124. (write-char #\) port))
  125. ; The vector case goes last just so that this version of WRITE can be
  126. ; used in Scheme implementations in which records, ports, or
  127. ; procedures are represented as vectors. (Scheme 48 doesn't have this
  128. ; property.)
  129. (define (write-other obj port recur)
  130. (cond ((disclose obj)
  131. => (lambda (l)
  132. (write-string "#{" port)
  133. (display-type-name (car l) port)
  134. (for-each (lambda (x)
  135. (write-char #\space port)
  136. (recur x))
  137. (cdr l))
  138. (write-string "}" port)))
  139. ((eof-object? obj) (write-string "#{End-of-file}" port))
  140. ((vector? obj) (write-vector obj port recur))
  141. ((procedure? obj) (write-string "#{Procedure}" port))
  142. ((code-vector? obj)
  143. (write-string "#{Byte-vector}" port))
  144. ((channel? obj)
  145. (write-string "#{Channel " port)
  146. (display (channel-id obj) port)
  147. (write-string "}" port))
  148. ((eq? obj (if #f #f)) (write-string "#{Unspecific}" port))
  149. (else
  150. (write-string "#{Random object}" port))))
  151. ; Display the symbol WHO-CARES as Who-cares.
  152. (define (display-type-name name port)
  153. (if (symbol? name)
  154. (let* ((s (symbol->string name))
  155. (len (string-length s)))
  156. (if (and (> len 0)
  157. (char-alphabetic? (string-ref s 0)))
  158. (begin (write-char (char-upcase (string-ref s 0)) port)
  159. (do ((i 1 (+ i 1)))
  160. ((>= i len))
  161. (write-char (char-downcase (string-ref s i)) port)))
  162. (display name port)))
  163. (display name port)))
  164. ;(define (write-string s port)
  165. ; (do ((i 0 (+ i 1)))
  166. ; ((= i (string-length s)))
  167. ; (write-char (string-ref s i) port)))
  168. ; DISPLAY
  169. (define (display obj . port-option)
  170. (let ((port (output-port-option port-option)))
  171. (if (and (output-port? port)
  172. (open-output-port? port))
  173. (let recur ((obj obj))
  174. (cond ((string? obj) (write-string obj port))
  175. ((char? obj) (write-char obj port))
  176. (else
  177. (recurring-write obj port recur))))
  178. (call-error "invalid port argument" display port))))