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