73d95a0895df12fa9f7939f7f8ca12d8476220f6
[jscl.git] / src / ffi.lisp
1 ;;; ffi.lisp ---
2
3 ;; JSCL is free software: you can redistribute it and/or
4 ;; modify it under the terms of the GNU General Public License as
5 ;; published by the Free Software Foundation, either version 3 of the
6 ;; License, or (at your option) any later version.
7 ;;
8 ;; JSCL is distributed in the hope that it will be useful, but
9 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
10 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 ;; General Public License for more details.
12 ;;
13 ;; You should have received a copy of the GNU General Public License
14 ;; along with JSCL.  If not, see <http://www.gnu.org/licenses/>.
15
16 (defvar *js-package*
17   (make-package "JS"))
18
19 (defun lisp-to-js (x) (%lisp-to-js x))
20 (defun js-to-list (x) (%js-to-lisp x))
21
22 (defun ffi-intern-hook (symbol)
23   (when (eq (symbol-package symbol) *js-package*)
24     (let ((sym-name (symbol-name symbol))
25           (args (gensym)))
26       ;; Generate a trampoline to call the JS function
27       ;; properly. This trampoline is very inefficient,
28       ;; but it still works. Ideas to optimize this are
29       ;; provide a special lambda keyword
30       ;; cl::&rest-vector to avoid list argument
31       ;; consing, as well as allow inline declarations.
32       (fset symbol
33             (eval `(lambda (&rest ,args)
34                      (let ((,args (list-to-vector (mapcar #'lisp-to-js ,args))))
35                        (js-to-list (%js-call (%js-vref ,sym-name) ,args))))))
36       ;; Define it as a symbol macro to access to the
37       ;; Javascript variable literally.
38       (%define-symbol-macro symbol `(%js-vref ,(string symbol))))))
39
40 (setq *intern-hook* #'ffi-intern-hook)