1dcbc4b24fdf0577e09f2e81f064dae83b251367
[mes.git] / module / mes / display.mes
1 ;;; -*-scheme-*-
2
3 ;;; Mes --- Maxwell Equations of Software
4 ;;; Copyright © 2016,2017 Jan Nieuwenhuizen <janneke@gnu.org>
5 ;;;
6 ;;; This file is part of Mes.
7 ;;;
8 ;;; Mes is free software; you can redistribute it and/or modify it
9 ;;; under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 3 of the License, or (at
11 ;;; your option) any later version.
12 ;;;
13 ;;; Mes is distributed in the hope that it will be useful, but
14 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;;; GNU General Public License for more details.
17 ;;;
18 ;;; You should have received a copy of the GNU General Public License
19 ;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
20
21 ;;; Commentary:
22
23 ;;; Code:
24
25 (mes-use-module (mes scm))
26 ;;(mes-use-module (mes srfi srfi-1))
27
28 (define (srfi-1:member x lst eq)
29   (if (null? lst) #f
30       (if (eq x (car lst)) lst
31           (srfi-1:member x (cdr lst) eq))))
32
33 (define (next-xassq x a)
34   (and=> (srfi-1:member x a (lambda (x e) (eq? x (cdr e))))
35          (lambda (a) (xassq x (cdr a)))))
36
37 (define (next-xassq2 x a)
38   (and=> (srfi-1:member x a (lambda (x e) (eq? x (cdr e))))
39          (lambda (a)
40            (and=> (srfi-1:member x (cdr a) (lambda (x e) (eq? x (cdr e))))
41                   (lambda (a) (xassq x (cdr a)))))))
42
43 (define (display x . rest)
44   (let* ((port (if (null? rest) (current-output-port) (car rest)))
45          (write? (and (pair? rest) (pair? (cdr rest)) (cadr rest))))
46
47     (define-macro (cut f slot n1)
48       `(lambda (slot) (,f slot ,n1)))
49
50     (define-macro (cut2 f slot n1 n2)
51       `(lambda (slot) (,f slot ,n1 ,n2)))
52
53     (define (display-char x port write?)
54       (cond ((and write? (or (eq? x #\") (eq? x #\\)))
55              (write-char #\\ port)
56              (write-char x port))
57             ((and write? (eq? x #\newline))
58              (write-char #\\ port)
59              (write-char #\n port))
60             (#t (write-char x port))))
61
62     (define (d x cont? sep)
63       (for-each (cut write-char <> port) (string->list sep))
64       (cond
65        ((char? x)
66         (if (not write?) (write-char x port)
67             (let ((name (and=> (assq x '((#\*eof* . *eof*)
68                                          (#\nul . nul)
69                                          (#\alarm . alarm)
70                                          (#\backspace . backspace)
71                                          (#\tab . tab)
72                                          (#\newline . newline)
73                                          (#\vtab . vtab)
74                                          (#\page . page)
75                                          (#\return . return)
76                                          (#\space . space)))
77                                cdr)))
78               (write-char #\# port)
79               (write-char #\\ port)
80               (if name (display name port)
81                   (write-char x port)))))
82        ((closure? x)
83         (display "#<procedure " port)
84         (let ((name (and=> (next-xassq2 x (current-module)) car)))
85           (display name port))
86         (display " " port)
87         (display (cadr (core:cdr x)) port)
88         (display ">" port))
89        ((continuation? x)
90         (display "#<continuation " port)
91         (display (core:car x) port)
92         (display ">" port))
93        ((macro? x)
94         (display "#<macro " port)
95         (display (core:cdr x) port)
96         (display ">" port))
97        ((number? x)
98         (display (number->string x) port))
99        ((pair? x)
100         (if (not cont?) (write-char #\( port))
101         (cond ((eq? (car x) '*circular*)
102                (display "*circ* . #-1#)" port))
103               ((eq? (car x) '*closure*)
104                (display "*closure* . #-1#)" port))
105               (#t
106                (display (car x) port write?)
107                (if (pair? (cdr x)) (d (cdr x) #t " ")
108                    (if (and (cdr x) (not (null? (cdr x))))
109                        (begin
110                          (display " . " port)
111                          (display (cdr x) port write?))))))
112         (if (not cont?) (write-char #\) port)))
113        ((or (keyword? x) (special? x) (string? x) (symbol? x))
114         (if (and (string? x) write?) (write-char #\" port))
115         (if (keyword? x) (display "#:" port))
116         (for-each (cut2 display-char <> port write?) (string->list x))
117         (if (and (string? x) write?) (write-char #\" port)))
118        ((vector? x)
119         (display "#(" port)
120         (for-each (lambda (i)
121                     (let ((x (vector-ref x i)))
122                       (if (vector? x)
123                           (begin
124                             (display (if (= i 0) "" " ") port)
125                             (display "#(...)" port))
126                           (d x #f (if (= i 0) "" " ")))))
127                   (iota (vector-length x)))
128         (display ")" port))
129        ((function? x)
130         (display "#<procedure " port)
131         (display (core:car x) port)
132         (display " " port)
133         (display
134          (case (core:arity x)
135            ((-1) "_")
136            ((0) "()")
137            ((1) "(_)")
138            ((2) "(_ _)")
139            ((3) "(_ _ _)"))
140          port)
141         (display ">" port))
142        ((broken-heart? x)
143         (display "<3" port))
144        (#t
145         (display "TODO type=") (display (cell:type-name x)) (newline)))
146       *unspecified*)
147     (d x #f "")))
148
149 (define (write-char x . rest)
150   (apply write-byte (cons (char->integer x) rest)))
151
152 (define (write x . rest)
153   (let ((port (if (null? rest) (current-output-port) (car rest))))
154     (display x port #t)))
155
156 (define (newline . rest)
157   (apply display (cons "\n" rest)))
158
159 (define (with-output-to-string thunk)
160   (define save-write-byte write-byte)
161   (let ((stdout '()))
162     (set! write-byte
163           (lambda (x . rest)
164             (let ((out? (or (null? rest) (eq? (car rest) (current-output-port)))))
165               (if (not out?) (apply save-write-byte (cons x rest))
166                   (begin
167                     (set! stdout (append stdout (list (integer->char x))))
168                     x)))))
169     (thunk)
170     (let ((r (apply string stdout)))
171       (set! write-byte save-write-byte)
172       r)))
173
174 (define (simple-format destination format . rest)
175   (let ((port (if (boolean? destination) (current-output-port) destination))
176         (lst (string->list format)))
177     (define (simple-format lst args)
178       (if (pair? lst)
179           (let ((c (car lst)))
180             (if (not (eq? c #\~)) (begin (write-char (car lst) port)
181                                          (simple-format (cdr lst) args))
182                 (let ((c (cadr lst)))
183                   (case c
184                     ((#\a) (display (car args) port))
185                     ((#\s) (write (car args) port)))
186                   (simple-format (cddr lst) (cdr args)))))))
187     
188     (if destination (simple-format lst rest)
189         (with-output-to-string
190           (lambda () (simple-format lst rest))))))
191 (define format simple-format)