src/method-aggregate.lisp: Give aggregating combinations their own file.
[sod] / src / codegen-impl.lisp
CommitLineData
dea4d055
MW
1;;; -*-lisp-*-
2;;;
3;;; Code generation protocol implementation
4;;;
5;;; (c) 2009 Straylight/Edgeware
6;;;
7
8;;;----- Licensing notice ---------------------------------------------------
9;;;
10;;; This file is part of the Sensble Object Design, an object system for C.
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;;; Temporary names.
30
31(export '(temporary-argument temporary-function))
32(defclass temporary-argument (temporary-name) ())
33(defclass temporary-function (temporary-name) ())
34
35(export 'temporary-variable)
36(defclass temporary-variable (temporary-name)
37 ((in-use-p :initarg :in-use-p :initform nil
38 :type boolean :accessor var-in-use-p)))
39
40(defmethod commentify-argument-name ((name temporary-name))
41 nil)
42
43(export 'temporary-function)
44(defun temporary-function ()
45 "Return a temporary function name."
46 (make-instance 'temporary-function
47 :tag (prog1 *temporary-index* (incf *temporary-index*))))
48
49(defmethod format-temporary-name ((var temporary-name) stream)
50 (format stream "~A" (temp-tag var)))
51(defmethod format-temporary-name ((var temporary-argument) stream)
52 (format stream "sod__a~A" (temp-tag var)))
53(defmethod format-temporary-name ((var temporary-variable) stream)
54 (format stream "sod__v~A" (temp-tag var)))
55(defmethod format-temporary-name ((var temporary-function) stream)
56 (format stream "sod__f~A" (temp-tag var)))
57
58(defmethod print-object ((var temporary-name) stream)
59 (if *print-escape*
60 (print-unreadable-object (var stream :type t)
61 (prin1 (temp-tag var) stream))
62 (format-temporary-name var stream)))
63
64;;;--------------------------------------------------------------------------
65;;; Instruction types.
66
67;; Compound statements.
68
418752c5 69(definst if (stream :export t) (condition consequent alternative)
dea4d055
MW
70 (format-compound-statement (stream consequent alternative)
71 (format stream "if (~A)" condition))
72 (when alternative
73 (format-compound-statement (stream alternative)
74 (write-string "else" stream))))
75
418752c5 76(definst while (stream :export t) (condition body)
dea4d055
MW
77 (format-compound-statement (stream body)
78 (format stream "while (~A)" condition)))
79
418752c5 80(definst do-while (stream :export t) (body condition)
dea4d055
MW
81 (format-compound-statement (stream body :space)
82 (write-string "do" stream))
83 (format stream "while (~A);" condition))
84
85;; Special varargs hacks.
86
418752c5 87(definst va-start (stream :export t) (ap arg)
dea4d055
MW
88 (format stream "va_start(~@<~A, ~_~A~:>);" ap arg))
89
418752c5 90(definst va-copy (stream :export t) (to from)
dea4d055
MW
91 (format stream "va_copy(~@<~A, ~_~A~:>);" to from))
92
418752c5 93(definst va-end (stream :export t) (ap)
dea4d055
MW
94 (format stream "va_end(~A);" ap))
95
96;; Expressions.
97
418752c5 98(definst call (stream :export t) (func args)
dea4d055
MW
99 (format stream "~A(~@<~{~A~^, ~_~}~:>)" func args))
100
101;;;--------------------------------------------------------------------------
102;;; Code generator objects.
103
104(defclass basic-codegen ()
105 ((vars :initarg :vars :initform nil :type list :accessor codegen-vars)
106 (insts :initarg :insts :initform nil :type list :accessor codegen-insts)
107 (temp-index :initarg :temp-index :initform 0
108 :type fixnum :accessor codegen-temp-index))
109 (:documentation
110 "Base class for code generator state.
111
3109662a
MW
112 This contains the bare essentials for supporting the `emit-inst' and
113 `ensure-var' protocols; see the documentation for those generic functions
dea4d055
MW
114 for more details.
115
3109662a 116 This class isn't abstract. A full `codegen' object uses instances of this
dea4d055
MW
117 to keep track of pending functions which haven't been completed yet.
118
119 Just in case that wasn't clear enough: this is nothing to do with the
120 BASIC language."))
121
122(defmethod emit-inst ((codegen basic-codegen) inst)
123 (push inst (codegen-insts codegen)))
124
125(defmethod emit-insts ((codegen basic-codegen) insts)
126 (asetf (codegen-insts codegen) (revappend insts it)))
127
3f4ac959
MW
128(defmethod emit-decl ((codegen basic-codegen) inst)
129 (push inst (codegen-vars codegen)))
130
131(defmethod emit-decls ((codegen basic-codegen) insts)
132 (asetf (codegen-vars codegen) (revappend insts it)))
133
dea4d055
MW
134(defmethod ensure-var ((codegen basic-codegen) name type &optional init)
135 (let* ((vars (codegen-vars codegen))
66836e14
MW
136 (var (find name
137 (remove-if-not (lambda (var) (typep var 'var-inst)) vars)
138 :key #'inst-name :test #'equal)))
dea4d055
MW
139 (cond ((not var)
140 (setf (codegen-vars codegen)
141 (cons (make-var-inst name type init) vars)))
142 ((not (c-type-equal-p type (inst-type var)))
143 (error "(Internal) Redefining type for variable ~A." name)))
144 name))
145
146(export 'codegen)
147(defclass codegen (basic-codegen)
148 ((functions :initform nil :type list :accessor codegen-functions)
149 (stack :initform nil :type list :accessor codegen-stack))
150 (:documentation
151 "A full-fat code generator which can generate and track functions.
152
153 This is the real deal. Subclasses may which to attach additional state
154 for convenience's sake, but this class is self-contained. It supports the
3109662a 155 `codegen-push', `codegen-pop' and `codegen-pop-function' protocols."))
dea4d055
MW
156
157(defmethod codegen-push ((codegen codegen))
158 (with-slots (vars insts temp-index stack) codegen
159 (push (make-instance 'basic-codegen
160 :vars vars
161 :insts insts
162 :temp-index temp-index)
163 stack)
164 (setf vars nil insts nil temp-index 0)))
165
166(defmethod codegen-pop ((codegen codegen))
167 (with-slots (vars insts temp-index stack) codegen
168 (multiple-value-prog1
169 (values (nreverse vars) (nreverse insts))
170 (let ((sub (pop stack)))
171 (setf vars (codegen-vars sub)
172 insts (codegen-insts sub)
173 temp-index (codegen-temp-index sub))))))
174
175(defmethod codegen-add-function ((codegen codegen) function)
176 (with-slots (functions) codegen
177 (setf functions (nconc functions (list function)))))
178
179(defmethod temporary-var ((codegen basic-codegen) type)
180 (with-slots (vars temp-index) codegen
181 (or (some (lambda (var)
182 (let ((name (inst-name var)))
183 (if (and (not (var-in-use-p name))
184 (c-type-equal-p type (inst-type var)))
185 name
186 nil)))
66836e14 187 (remove-if-not (lambda (var) (typep var 'var-inst)) vars))
dea4d055
MW
188 (let* ((name (make-instance 'temporary-variable
189 :in-use-p t
190 :tag (prog1 temp-index
191 (incf temp-index)))))
192 (push (make-var-inst name type nil) vars)
193 name))))
194
195;;;----- That's all, folks --------------------------------------------------