~ chicken-core (chicken-5) /chicken-ffi-syntax.scm


  1;;;; chicken-ffi-syntax.scm
  2;
  3; Copyright (c) 2008-2022, The CHICKEN Team
  4; Copyright (c) 2000-2007, Felix L. Winkelmann
  5; All rights reserved.
  6;
  7; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
  8; conditions are met:
  9;
 10;   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
 11;     disclaimer.
 12;   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
 13;     disclaimer in the documentation and/or other materials provided with the distribution.
 14;   Neither the name of the author nor the names of its contributors may be used to endorse or promote
 15;     products derived from this software without specific prior written permission.
 16;
 17; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 18; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 19; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
 20; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 21; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 22; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 23; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 24; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 25; POSSIBILITY OF SUCH DAMAGE.
 26
 27
 28(declare
 29  (unit chicken-ffi-syntax)
 30  (uses data-structures extras internal)
 31  (disable-interrupts)
 32  (fixnum))
 33
 34#+(not debugbuild)
 35(declare
 36  (no-bound-checks)
 37  (no-procedure-checks))
 38
 39(import scheme
 40	chicken.base
 41	chicken.format
 42	chicken.internal
 43	chicken.platform
 44	chicken.syntax
 45	chicken.string)
 46
 47(include "common-declarations.scm")
 48(include "mini-srfi-1.scm")
 49
 50(define ##sys#chicken-ffi-macro-environment
 51  (let ((me0 (##sys#macro-environment)))
 52
 53;; IMPORTANT: These macros directly call fully qualified names from
 54;; the "chicken.compiler.c-backend" and "chicken.compiler.support"
 55;; modules.  These are unbound in the interpreter, so check first:
 56(define (compiler-only-er-transformer transformer)
 57  (##sys#er-transformer
 58   (lambda (form r c)
 59     (if (feature? 'compiling)
 60	 (transformer form r c)
 61	 (syntax-error
 62	  (car form) "The FFI is not supported in interpreted mode")))))
 63
 64(##sys#extend-macro-environment
 65 'define-external
 66 `((define . ,(alist-ref 'define me0))	; Or just me0?
 67   (begin . ,(alist-ref 'begin me0))
 68   (lambda . ,(alist-ref 'lambda me0)))
 69 (compiler-only-er-transformer
 70  (lambda (form r c)
 71    (let* ((form (cdr form))
 72	   (quals (and (pair? form) (string? (car form))))
 73	   (var (and (not quals) (pair? form) (symbol? (car form)))) )
 74      (cond [var
 75	     (##sys#check-syntax 'define-external form '(symbol _ . #(_ 0 1)))
 76	     (let ([var (car form)])
 77	       `(,(r 'begin)
 78		 (##core#define-foreign-variable ,var ,(cadr form))
 79		 (##core#define-external-variable ,var ,(cadr form) #t)
 80		 ,@(if (pair? (cddr form))
 81		       `((##core#set! ,var ,(caddr form)))
 82		       '() ) ) ) ]
 83	    [else
 84	     (if quals
 85		 (##sys#check-syntax 'define-external form '(string (symbol . #((_ symbol) 0)) _ . #(_ 1)))
 86		 (##sys#check-syntax 'define-external form '((symbol . #((_ symbol) 0)) _ . #(_ 1))) )
 87	     (let* ((head (if quals (cadr form) (car form)))
 88		    (args (cdr head)) )
 89	       `(,(r 'define) ,(car head)
 90		 (##core#foreign-callback-wrapper
 91		  (##core#quote ,(car head))
 92		  ,(if quals (car form) "")
 93		  (##core#quote ,(if quals (caddr form) (cadr form)))
 94		  (##core#quote ,(map (lambda (a) (car a)) args))
 95		  (,(r 'lambda) 
 96		   ,(map (lambda (a) (cadr a)) args)
 97		   ,@(if quals (cdddr form) (cddr form)) ) ) ) ) ] ) ) ) ) )
 98
 99
100
101;;; External locations:
102
103(##sys#extend-macro-environment
104 'location
105 '()
106 (compiler-only-er-transformer
107  (lambda (x r c)
108    (##sys#check-syntax 'location x '(location _))
109    `(##core#location ,(cadr x)))))
110
111(##sys#extend-macro-environment
112 'define-location
113 `((begin . ,(alist-ref 'begin me0)))
114 (compiler-only-er-transformer
115  (lambda (form r c)
116    (##sys#check-syntax 'define-location form '(_ variable _ . #(_ 0 1)))
117    (let ((var (cadr form))
118	  (type (caddr form))
119	  (init (optional (cdddr form) #f))
120	  (name (r (gensym))))
121      `(,(r 'begin)
122	(##core#define-foreign-variable ,var ,type ,(symbol->string name))
123	(##core#define-external-variable ,var ,type #f ,name)
124	,@(if (pair? init)
125	      `((##core#set! ,var ,(car init)))
126	      '() ) ) ) ) ) )
127
128(##sys#extend-macro-environment
129 'let-location
130 '()
131 (compiler-only-er-transformer
132  (lambda (form r c)
133    (##sys#check-syntax 'let-location form '(_ #((variable _ . #(_ 0 1)) 0) . _))
134    (let* ((bindings (cadr form))
135	   (body (cddr form))
136	   (aliases (map (lambda (_) (r (gensym))) bindings)))
137      `(##core#let
138	,(append-map
139	  (lambda (b a)
140	    (if (pair? (cddr b))
141		(list (cons a (cddr b)))
142		'() ) )
143	  bindings aliases)
144	,(let loop ((bindings bindings) (aliases aliases))
145	   (if (null? bindings)
146	       `(##core#let () ,@body)
147	       (let ((b (car bindings))
148		     (a (car aliases))
149		     (rest (loop (cdr bindings) (cdr aliases))))
150		 (if (= 3 (length b))
151		     `(##core#let-location
152		       ,(car b)
153		       ,(cadr b)
154		       ,a
155		       ,rest)
156		     `(##core#let-location
157		       ,(car b)
158		       ,(cadr b)
159		       ,rest) ) ))))))))
160
161
162;;; Embedding code directly:
163
164(##sys#extend-macro-environment
165 'foreign-code
166 `((declare . ,(alist-ref 'declare me0)))
167 (compiler-only-er-transformer
168  (lambda (form r c)
169    (##sys#check-syntax 'foreign-code form '(_ . #(string 0)))
170    (let ([tmp (gensym 'code_)])
171      `(##core#begin
172	 (,(r 'declare)
173	  (foreign-declare
174	   ,(sprintf "static C_word ~A() { ~A\n; return C_SCHEME_UNDEFINED; }\n" 
175		     tmp
176		     (string-intersperse (cdr form) "\n")) ) )
177	 (##core#inline ,tmp) ) ) ) ) )
178
179(##sys#extend-macro-environment
180 'foreign-value
181 '()
182 (compiler-only-er-transformer
183  (lambda (form r c)
184    (##sys#check-syntax 'foreign-value form '(_ _ _))
185    (let ((tmp (gensym "code_"))
186	  (code (cadr form)))
187      `(##core#begin
188	(##core#define-foreign-variable ,tmp
189	 ,(caddr form)
190	 ,(cond ((string? code) code)
191		((symbol? code) (symbol->string code))
192		(else
193		 (syntax-error
194		  'foreign-value
195		  "bad argument type - not a string or symbol" 
196		  code))))
197	(##core#the ,(chicken.compiler.support#foreign-type->scrutiny-type
198		      (chicken.syntax#strip-syntax (caddr form))
199		      'result) 
200		    #f ,tmp) ) ) ) ) )
201
202
203;;; Include foreign code fragments
204
205(##sys#extend-macro-environment
206 'foreign-declare
207 '()
208 (compiler-only-er-transformer
209  (lambda (form r c)
210    (##sys#check-syntax 'foreign-declare form '(_ . #(string 0)))
211    `(##core#declare (foreign-declare ,@(cdr form))))))
212
213
214;;; Aliases for internal forms
215
216(define (annotate-foreign-procedure e argtypes rtype)
217  (let ((scrut-atypes (map (cut chicken.compiler.support#foreign-type->scrutiny-type <> 'arg)
218			   (chicken.syntax#strip-syntax argtypes)))
219	(scrut-rtype (and rtype
220			  (chicken.compiler.support#foreign-type->scrutiny-type
221			   (chicken.syntax#strip-syntax rtype) 'result))))
222    ;; Don't add type annotation if the scrutinizer can infer the same
223    ;; or better.
224    ;;
225    ;; At least these cases should work:
226    ;;
227    ;;   (-> <some-known-type>)	=> annotate
228    ;;   (-> *)			=> no annotation
229    ;;   (* ... -> *)		=> no annotation
230    ;;
231    (if (and (or (not rtype) (eq? scrut-rtype '*))
232	     (every (cut eq? '* <>) scrut-atypes))
233	e
234	`(##core#the
235	  (procedure ,scrut-atypes
236		     ,@(if rtype
237			   (list scrut-rtype)
238			   ;; Special case for C_values(...). Only
239			   ;; triggered by foreign-primitive.
240			   '*))
241	  #f
242	  ,e))))
243
244(##sys#extend-macro-environment
245 'define-foreign-type
246 '()
247 (compiler-only-er-transformer
248  (lambda (form r c)
249    (##sys#check-syntax 'define-foreign-type form '(_ symbol _ . #(_ 0 2)))
250    `(##core#define-foreign-type ,@(cdr form)))))
251
252(##sys#extend-macro-environment
253 'define-foreign-variable
254 '()
255 (compiler-only-er-transformer
256  (lambda (form r c)
257    (##sys#check-syntax 'define-foreign-variable form '(_ symbol _ . #(string 0 1)))
258    `(##core#define-foreign-variable ,@(cdr form)))))
259
260(##sys#extend-macro-environment
261 'foreign-primitive
262 '()
263 (compiler-only-er-transformer
264  (lambda (form r c)
265    (##sys#check-syntax 'foreign-primitive form '(_ _ . _))
266    (let* ((hasrtype (and (pair? (cddr form)) (not (string? (caddr form)))))
267	   (rtype (and hasrtype (cadr form)))
268	   (args (if hasrtype (caddr form) (cadr form)))
269	   (argtypes (map car args)))
270      (annotate-foreign-procedure `(##core#foreign-primitive ,@(cdr form))
271				  argtypes
272				  rtype)))))
273
274(##sys#extend-macro-environment
275 'foreign-lambda
276 '()
277 (compiler-only-er-transformer
278  (lambda (form r c)
279    (##sys#check-syntax 'foreign-lambda form '(_ _ _ . _))
280    (annotate-foreign-procedure `(##core#foreign-lambda ,@(cdr form))
281				(cdddr form)
282				(cadr form)))))
283
284(##sys#extend-macro-environment
285 'foreign-lambda*
286 '()
287 (compiler-only-er-transformer
288  (lambda (form r c)
289    (##sys#check-syntax 'foreign-lambda* form '(_ _ _ _ . _))
290    (annotate-foreign-procedure `(##core#foreign-lambda* ,@(cdr form))
291				(map car (caddr form))
292				(cadr form)))))
293
294(##sys#extend-macro-environment
295 'foreign-safe-lambda
296 '()
297 (compiler-only-er-transformer
298  (lambda (form r c)
299    (##sys#check-syntax 'foreign-safe-lambda form '(_ _ _ . _))
300    (annotate-foreign-procedure `(##core#foreign-safe-lambda ,@(cdr form))
301				(cdddr form)
302				(cadr form)))))
303
304(##sys#extend-macro-environment
305 'foreign-safe-lambda*
306 '()
307 (compiler-only-er-transformer
308  (lambda (form r c)
309    (##sys#check-syntax 'foreign-safe-lambda* form '(_ _ _ _ . _))
310    (annotate-foreign-procedure `(##core#foreign-safe-lambda* ,@(cdr form))
311				(map car (caddr form))
312				(cadr form)))))
313
314(##sys#extend-macro-environment
315 'foreign-type-size
316 '()
317 (compiler-only-er-transformer
318  (lambda (form r c)
319    (##sys#check-syntax 'foreign-type-size form '(_ _))
320    (let* ((t (chicken.syntax#strip-syntax (cadr form)))
321	   (tmp (gensym "code_"))
322	   (decl
323	    (if (string? t)
324		t
325		;; TODO: Backend should be configurable
326		(chicken.compiler.c-backend#foreign-type-declaration t ""))))
327      `(##core#begin
328	(##core#define-foreign-variable ,tmp size_t ,(string-append "sizeof(" decl ")"))
329	(##core#the fixnum #f ,tmp))))))
330
331
332(macro-subset me0)))
Trap