1(library (yuni transformer cirs writer)
2         (export cirs-write)
3         (import (rnrs)
4                 (srfi :8)
5                 (shorten))
6
7(define (cirs-write obj p)
8  (define (cirs-exp->string obj)
9
10    (define binops ;; (OP X Y Z ...)
11      ;; * / % + - << >> bit-xor bit-and bit-or and or =
12      ;; (* X Y Z ...) => (X * Y * Z)
13      ;; (pref X Y Z ...) => X->Y->Z ..
14      ;; (fref X Y Z ...) => X.Y.Z
15      '((* . " * ") (/ . " / ") (% . " % ") (+ . " + ")
16                    (- . " - ") (<< . " << ") (>> . " >> ") (bit-xor . " ^ ")
17                    (bit-and . " & ") (bit-or . " | ") (and . " && ")
18                    (or . " || ") (= . " = ")
19                    (pref . "->") (fref . ".")))
20
21    (define compops ;; (OP X Y)
22      ;; < > <= >= == !=
23      ;; *= /= %= add= sub= <<= >>= bit-and= bit-xor= bit-or=
24      ;; (< X Y) => (X < Y)
25      '((< . " < ") (> . " > ") (<= . " <= ") (>= . " >= ") (== . " == ")
26                    (!= . " != ") (*= . " *= ") (/= . " /= ") (%= . " %= ") (add= . " += ")
27                    (sub= . " -= ") (<<= . " <<= ") (>>= . " >>= ") (bit-xor= . " ^= ")
28                    (bit-and= . " &= ") (bit-or= . " |= ")))
29
30    ;; inc dec ++ -- not bit-not
31    ;; (inc X) => X++
32    ;; FIXME: (++ X) => ++X
33    ;; (mref X) => (*(X))
34    ;; (ptr X) => (&(X))
35    (define uniops/pre
36      '(
37        #| ;; we cannot do this in R6RS...
38        (++ . "++")
39        (-- . "--")
40        |#
41        (mref . "*")
42        (ptr . "&")))
43    (define uniops/post
44      '((inc . "++")
45        (dec . "--")))
46    (define (output-op l p)
47      (define (fold-ops str rest*)
48        (define (itr rest)
49          (when (pair? rest)
50            (display str p)
51            (display (car rest) p)
52            (itr (cdr rest))))
53        (cond
54          ((pair? rest*)
55           (display "(" p)
56           (display (car rest*) p)
57           (itr (cdr rest*))
58           (display ")" p))
59          (else
60            (display "()" p))))
61      (let ((op (car l))
62            (rest (cdr l)))
63        (cond
64          ((assoc op binops)
65           => (^x (let ((str (cdr x)))
66                    (fold-ops
67                      str
68                      (map cirs-exp->string rest)))))
69          ((assoc op compops)
70           => (^x (let ((str (cdr x)))
71                    ;; FIXME: check op length here..
72                    (fold-ops
73                      str
74                      (map cirs-exp->string rest)))))
75          ((assoc op uniops/pre)
76           => (^x (let ((str (cdr x)))
77                    (display str p)
78                    (display (cirs-exp->string (car rest)) p))))
79          ((assoc op uniops/post)
80           => (^x (let ((str (cdr x)))
81                    (display (cirs-exp->string (car rest)) p)
82                    (display str p))))
83          ;; ((quote X) Y Z ...) => X(Y, Z); // function call
84          ((and (list? op) (eq? 'quote (car op)))
85           (let ((name (cirs-exp->string (cadr op)))
86                 (args rest))
87             (display name p)
88             (fold-ops ", " (map cirs-exp->string args))))
89          (else
90            (case op
91              ;; (comment X) => /* X */
92              ((comment)
93               (display " /* " p)
94               (display (car rest) p)
95               (display " */ " p))
96              ;; (aref X Y Z ...) => (X)[Y][Z]
97              ((aref)
98               (let ((X (cirs-exp->string (car rest)))
99                     (refs (map (^e (string-append "[" e "]"))
100                                (map cirs-exp->string (cdr rest)))))
101                 (display (string-append X refs) p)))
102              ;; (seq X Y Z ...) => X , Y , Z
103              ((seq)
104               (fold-ops ", " (map cirs-exp->string rest)))
105              ;; (? X Y Z) => X ? Y : Z
106              ((?)
107               (let ((X (cirs-exp->string (car rest)))
108                     (Y (cirs-exp->string (cadr rest)))
109                     (Z (cirs-exp->string (caddr rest))))
110                 (display (string-append "(" X " ? " Y " : " Z ")") p)))
111              ;; (sizeof X) => (sizeof(X))
112              ((sizeof)
113               (display op p)
114               (display (string-append "(" (cirs-exp->string (car rest)) ")") p))
115              ;; (cast X Y) => ((X)Y)
116              ;; (cast (X Y Z) W) => ((X Y Z) W)
117              ((cast)
118               (let ((type (car rest))
119                     (value (cirs-exp->string (cadr rest))))
120                 (display "((" p)
121                 (cond
122                   ((list? type)
123                    (for-each (^e (display e p))
124                              (map cirs-exp->string type)))
125                   (else
126                     (display (cirs-exp->string type))))
127                 (display ") " p)
128                 (display value p)
129                 (display ") " p)))
130              (else
131                (assertion-violation 'cirs-exp->string "invalid op" op)))))))
132
133    (receive (p str) (open-string-output-port)
134      ;; write
135      (cond
136        ((string? obj)
137         (write obj p))
138        ((or (symbol? obj) (number? obj))
139         (display obj p))
140        ((list? obj)
141         (output-op obj p))
142        (else
143          (assertion-violation 'cirs-exp->string "invalid datum" obj)))
144      ;; output
145      (let ((out (str)))
146        (close-port p)
147        out)))
148  (let ((current-indent 0))
149    (define (indent+) (set! current-indent (+ 1 current-indent)))
150    (define (indent-) (set! current-indent (- current-indent 1)))
151    (define (out str)
152      (display str p))
153    (define (indent)
154      (define (itr rest)
155        (unless (= rest 0)
156          (out "    ")
157          (itr (- rest 1))))
158      (itr current-indent))
159    (define (outi str)
160      (indent)
161      (out str))
162    (define (line str)
163      (indent)
164      (out str)
165      (out "\n"))
166    (define (out-exp obj)
167      (out (cirs-exp->string obj)))
168    (define (emit-block body-k)
169      (out " {\n")
170      (indent+)
171      (body-k)
172      (indent-)
173      (indent)
174      (out "} "))
175    (define (put-form l)
176      ;; struct/union members
177      ;; (name type)
178      ;; (name type ... (init value))
179      ;; (name (bit pos) type ...)
180      ;; (name (bit pos) type ... (init value))
181      (define (emit-members m)
182        (define (emit-member x)
183          (indent)
184          (let ((name (car x))
185                (args (cdr x))
186                (init #f)
187                (bit #f))
188            ;; consume args
189            (for-each (^e
190                        (cond
191                          ((symbol? e)
192                           (out (symbol->string e))
193                           (out " "))
194                          ((list? e)
195                           (let ((op (car e))
196                                 (arg (cadr e)))
197                             (case op
198                               ((bit)
199                                (set! bit arg))
200                               ((init)
201                                (set! init arg))
202                               (else
203                                 (assertion-violation 'emit-members "invalid op"
204                                                      e)))))))
205                      args)
206            ;; emit name
207            (out (symbol->string name))
208            ;; emit bit
209            (when bit
210              (out ":")
211              (out (number->string bit)))
212            ;; emit init
213            (when init
214              (out " = ")
215              (put-form init))
216            (out ";\n")))
217        (for-each emit-member m))
218      (define (put-begin obj)
219        (for-each put-form obj))
220      (define (complain x)
221        (assertion-violation 'put-form "invalid form" x))
222      (if (pair? l)
223        (let ((op (car l))
224              (rest (cdr l)))
225          (case op
226            ((if)
227             (outi "if (")
228             (out-exp (car rest))
229             (out ")")
230             (case (length rest)
231               ;; (if P X) => if (P) { X }
232               ((2)
233                (emit-block (^[] (put-form (cadr rest)))))
234               ;; (if P X Y) => if (P) { X } else { Y }
235               ((3)
236                (emit-block (^[] (put-form (cadr rest))))
237                (out " else ")
238                (emit-block (^[] (put-form (caddr rest)))))
239               (else (complain l))))
240            ((begin)
241             (put-begin rest))
242
243            ;; (cond (P X) (P Y) ... (else Z))
244            ((cond)
245             (for-each (^e
246                         (if (list? e)
247                           (let ((op (car e))
248                                 (code (cdr e)))
249                             (cond
250                               ((eq? op 'else)
251                                (out " else ")
252                                (emit-block (^[] (put-begin code))))
253                               (else
254                                 (out " else if (")
255                                 (out-exp op)
256                                 (out ")")
257                                 (emit-block (^[] (put-begin code))))))
258                           (complain e)))
259                       rest))
260
261            ;; (switch P (X Y ...) (X Y ...) ... (default Y ...))
262            ;;   => switch (P) { case X: Y ,,, ... default: Y ,,, }
263            ((switch)
264             (let ((pred (car rest))
265                   (cases (cdr rest)))
266               (outi "switch (")
267               (out-exp pred)
268               (out ")")
269               (emit-block (^[]
270                             (for-each (^e (if (list? e)
271                                             (let ((op (car e))
272                                                   (code (cdr e)))
273                                               (if (eq? op 'default)
274                                                 (line "default:")
275                                                 (line (string-append
276                                                         (cirs-exp->string op)
277                                                         ":")))
278                                               (put-begin code))
279                                             (complain e)))
280                                       cases)))))
281
282            ;; (while P ...) => while (P) { ... }
283            ((while)
284             (outi "while (")
285             (out-exp (car rest))
286             (out ")")
287             (emit-block (^[] (put-begin (cdr rest)))))
288
289            ;; (do-while P ...) => do { ... } while (P) ;
290            ((do-while)
291             (outi "do ")
292             (emit-block (^[] (put-begin (cdr rest))))
293             (out " while (")
294             (out-exp (car rest))
295             (out ");\n"))
296
297            ;; (for (X Y Z) ...) => for ( X ; Y ; Z ) { ... }
298            ;; (for (#f #f #f) ...) => for ( ;; ) { ... }
299            ((for)
300             (let ((cntl (car rest))
301                   (code (cdr rest)))
302               (if (= (length cntl) 3)
303                 (let ((x (car cntl))
304                       (y (cadr cntl))
305                       (z (caddr cntl)))
306                   (outi "for (")
307                   (when x (out-exp x))
308                   (out " ; ")
309                   (when y (out-exp y))
310                   (out " ; ")
311                   (when z (out-exp z))
312                   (out ")")
313                   (emit-block (^[] (put-begin code))))
314                 (complain cntl))))
315
316            ;; (goto X) => goto X;
317            ((goto)
318             (outi "goto ")
319             (out-exp (car rest))
320             (out ";\n"))
321
322            ;; (continue) => continue;
323            ((continue)
324             (outi "continue;\n"))
325
326            ;; (break) => break;
327            ((break)
328             (outi "break;\n"))
329
330            ;; (return) => return;
331            ;; (return X) => return(X);
332            ((return)
333             (cond
334               ((null? rest)
335                (outi "return;\n"))
336               (else
337                 (outi "return ")
338                 (out-exp (car rest))
339                 (out ";\n"))))
340
341            ;; (label X) => X:
342            ((label)
343             ;; labels won't be indented
344             (out-exp (car rest))
345             (out " :\n"))
346
347            ;; struct / union
348            ;; FIXME: (struct TAG (DECL ...) MEMBER ...)
349            ;; (struct TAG DECL MEMBER ...)
350            ;;  => struct TAG { ... } DECL ... ;
351            ((struct union)
352             (let ((name op)
353                   (tag (car rest))
354                   (decl (cadr rest))
355                   (members (cddr rest)))
356               (case name
357                 ((struct)
358                  (outi "struct "))
359                 ((union)
360                  (outi "union ")))
361               (emit-block (^[] (emit-members members)))
362               (out-exp decl)
363               (out "; \n")))
364
365            ;; (def NAME DEF attribute ...)
366            ;; (def NAME DEF attribute ... (init x))
367            ;; (decl NAME DEF attribute ...)
368            ;; (decl NAME struct attribute ...)
369            ;; (decl NAME union attribute ...)
370            ((def decl)
371             (let ((definition (cadr rest))
372                   (name (car rest))
373                   (body (cddr rest)))
374               (cond
375                 ((symbol? definition)
376                  ;; forward definition of union/struct cannot contain any
377                  ;; attributes
378                  (case definition
379                    ((struct union)
380                     (outi (symbol->string definition))
381                     (out " ")
382                     (out (symbol->string name))
383                     (out ";\n"))))
384                 (else
385                   (let ((init #f))
386                     (for-each (^e (out (symbol->string e))
387                                   (out " "))
388                               definition)
389                     (out (symbol->string name))
390                     (for-each (^e
391                                 (let ((op (car e))
392                                       (args (cdr e)))
393                                   (case op
394                                     ((init)
395                                      (set! init (car args))))))
396                               body)
397                     (when init
398                       (out " = ")
399                       (out (cirs-exp->string init)))
400                     (out "; \n"))))))
401
402            ;; (defn NAME RETTYPE DEF attributes ... body ...)
403            ;; DEF: ((NAME def ...) ...)
404            ((defn)
405             (let ((name (car rest))
406                   (rettype (cadr rest))
407                   (def (caddr rest))
408                   (body (cdddr rest)))
409               (define (out-types l)
410                 (cond
411                   ((list? l)
412                    (for-each (^e
413                                (out (symbol->string e))
414                                (out " "))
415                              l))
416                   (else
417                     (out (symbol->string l))
418                     (out " "))))
419               (define (out-def r)
420                 (define (out-entry e)
421                   (let ((name (car e))
422                         (types (cdr e)))
423                     (out-types types)
424                     (out (symbol->string name))))
425                 (let ((head (car r))
426                       (tail (cdr r)))
427                   (out-entry head)
428                   (unless (null? tail)
429                     (out ", ")
430                     (out-def tail))))
431
432               ;; output
433               (indent)
434               (out-types rettype)
435               (out "\n")
436               (outi (symbol->string name))
437               (cond
438                 ((null? def)
439                  (out "(void)"))
440                 (else
441                   (out "(")
442                   (out-def def)
443                   (out ")")))
444               (emit-block (^[] (put-begin body)))
445               (out "\n")))
446            #|
447            ;; (deftype NAME DEF) => typedef DEF name;
448            ((deftype)
449             )
450            |#
451
452            (else
453              (indent)
454              (out-exp l)
455              (out ";\n")
456              )))
457        (out (cirs-exp->string l))))
458    (for-each put-form obj)))
459    ;; === keywords ===
460    ;; (array X Y Z ...) => { X , Y , Z , ... }
461    ;; (attribute A X) => UNSPEC
462    ;; (cpp-if P X Y)
463    ;; (cpp-cond (P X) (P Y) ... (else Z))
464    ;; (cpp-ifdef S X Y)
465    ;; (cpp-ifndef S X Y)
466    ;; (cpp-include FN)
467
468)
469