chiark / gitweb /
Another day, another commit.
[sod] / module-output.lisp
1 ;;; -*-lisp-*-
2 ;;;
3 ;;; Output handling for modules
4 ;;;
5 ;;; (c) 2009 Straylight/Edgeware
6 ;;;
7
8 ;;;----- Licensing notice ---------------------------------------------------
9 ;;;
10 ;;; This file is part of the Simple Object Definition system.
11 ;;;
12 ;;; SOD is free software; you can redistribute it and/or modify
13 ;;; it under the terms of the GNU General Public License as published by
14 ;;; the Free Software Foundation; either version 2 of the License, or
15 ;;; (at your option) any later version.
16 ;;;
17 ;;; SOD is distributed in the hope that it will be useful,
18 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;;; GNU General Public License for more details.
21 ;;;
22 ;;; You should have received a copy of the GNU General Public License
23 ;;; along with SOD; if not, write to the Free Software Foundation,
24 ;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 (cl:in-package #:sod)
27
28 ;;;--------------------------------------------------------------------------
29 ;;; Utilities.
30
31 (defun banner (title output &key (blank-line-p t))
32   (format output "~&/*----- ~A ~A*/~%"
33           title
34           (make-string (- 77 2 5 1 (length title) 1 2)
35                        :initial-element #\-))
36   (when blank-line-p
37     (terpri output)))
38
39 (defun guard-name (filename)
40   "Return a sensible inclusion guard name for FILENAME."
41   (with-output-to-string (guard)
42     (let* ((pathname (make-pathname :name (pathname-name filename)
43                                     :type (pathname-type filename)))
44            (name (namestring pathname))
45            (uscore t))
46       (dotimes (i (length name))
47         (let ((ch (char name i)))
48           (cond ((alphanumericp ch)
49                  (write-char (char-upcase ch) guard)
50                  (setf uscore nil))
51                 ((not uscore)
52                  (write-char #\_ guard)
53                  (setf uscore t))))))))
54
55 ;;;--------------------------------------------------------------------------
56 ;;; Driving output.
57
58 (defun guess-output-file (module type)
59   (merge-pathnames (make-pathname :type type :case :common)
60                    (module-name module)))
61
62 (defun output-module (module reason stream)
63   (let ((sequencer (make-instance 'sequencer)))
64     (add-output-hooks module reason sequencer)
65     (invoke-sequencer-items sequencer stream)))
66
67 ;;;--------------------------------------------------------------------------
68 ;;; Main output protocol implementation.
69
70 (defmethod add-output-hooks progn ((module module) reason sequencer)
71   (dolist (item (module-items module))
72     (add-output-hooks item reason sequencer)))
73
74 ;;;--------------------------------------------------------------------------
75 ;;; Header output.
76
77 (defmethod add-output-hooks progn
78     ((module module) (reason (eql :h)) sequencer)
79   (sequence-output (stream sequencer)
80     :constraint (:prologue
81                  (:guard :start)
82                  (:typedefs :start) :typedefs (:typedefs :end)
83                  (:includes :start) :includes (:includes :end)
84                  (:classes :start) (:classes :end)
85                  (:guard :end)
86                  :epilogue)
87
88     (:prologue
89      (format stream "~
90 /* -*-c-*-
91  *
92  * Header file generated by SOD for ~A
93  */~2%"
94              (namestring (module-name module))))
95
96     ((:guard :start)
97      (format stream "~
98 #ifndef ~A
99 #define ~:*~A
100
101 #ifdef __cplusplus
102   extern \"C\" {
103 #endif~2%"
104              (or (get-property (module-pset module) :guard :id)
105                  (guard-name (or (stream-pathname stream)
106                                  (guess-output-file module "H"))))))
107     ((:guard :end)
108      (banner "That's all, folks" stream)
109      (format stream "~
110 #ifdef __cplusplus
111   }
112 #endif
113
114 #endif~%"))
115
116     ((:typedefs :start)
117      (banner "Forward type declarations" stream))
118     ((:typedefs :end)
119      (terpri stream))
120
121     ((:includes :start)
122      (banner "External header files" stream))
123     ((:includes :end)
124      (terpri stream))))
125
126 ;;;--------------------------------------------------------------------------
127 ;;; Source output.
128
129 (defmethod add-output-hooks progn
130     ((module module) (reason (eql :c)) sequencer)
131   (sequence-output (stream sequencer)
132     :constraint (:prologue
133                  (:includes :start) :includes (:includes :end)
134                  (:classes :start) (:classes :end)
135                  :epilogue)
136
137     (:prologue
138      (format stream "~
139 /* -*-c-*-
140  *
141  * Implementation file generated by SOD for ~A
142  */~2%"
143              (namestring (module-name module))))
144
145     (:epilogue
146      (banner "That's all, folks" stream :blank-line-p nil))
147
148     ((:includes :start)
149      (banner "External header files" stream))
150     ((:includes :end)
151      (terpri stream))))
152
153 ;;;----- That's all, folks --------------------------------------------------