[Ecls-list] Easy way to bind c++ class instances in lisp?

Juan Jose Garcia-Ripoll juanjose.garciaripoll at gmail.com
Fri Dec 7 09:00:51 UTC 2012


On Fri, Dec 7, 2012 at 12:32 AM, Peter Enerccio <enerccio at gmail.com> wrote:

> I am looking for easy way of wrapping around class instances of c++. I can
> wrap it in lisp with classes with slot containing fixnum of the pointer and
> then recast it in c++ but its cumberstone and has lot of boiler plate on
> both lisp and c++ side. Any other way of doing that? Could be even in lisp
> altogether, because then I could generate c code out of it or something.
>

This is a nice exercise for the MOP, but I will try to keep it simpler:

* C++ classes are instances of a CLOS class that keeps the list of slot
names and accessor names (C++ ones).

* C++ objects are mapped into a CLOS class (one that stores the C++ class
and a single pointer (via FFI) to the class.

* struct/class statements are manually translated to a lisp form of the
type (DEFCLASS (LISP-NAME C++-NAME) ((SLOT-NAME [ :READER READER ] [
:WRITER WRITER ] [ :ACCESSOR ACCESSOR ]) ..))

* The previous form expands through macros into these other forms:
- A defclass form for this object
- A constructor
- A set of lisp functions with c-inline forms to access the slot values

A sketch follows. It is not working, but gives you an idea

(defpackage :c++
  (:use :cl :clos))

(defclass c++-object ()
  ((pointer :initarg :pointer :reader c++-object-pointer)
   (definition :reader c++-object-definition)))

(defun parse-slot-definition (list)
  (let ((name (pop list))
lisp-name
c++-name
 c-type
readers
writers)
    (if (atom name)
(setf lisp-name name
      c++-name (string-downcase name))
 (setf lisp-name (first name)
      c++-name (second name)))
    (loop for option = (pop list)
       for value = (pop list)
       while option
       do (case option
    (:c-type (setf c-type value))
    (:reader (push value readers))
    (:writer (push `(setf ,value) writers))
    (:accessor (push value readers)
       (push `(setf ,value) writers))))
    (unless c-type
      (error "In DEFC++CLASS definition, no value was supplied for the slot
type."))
    (list lisp-name c++-name c++-type readers writers)))

(defun c++-type-to-ffi-tag (c++-type)
  (or (second (assoc c++-type
     '((:float "ECL_FFI_DOUBLE"
:int "ECL_FFI_INT"))))
      (error "Unknown C++ type in DEFC++CLASS")))

(defun build-readers (class-name lisp-name c++-name readers writers)
  (let* ((slot-value (format nil "((~A *)(#0))->~A" class-c++-name
c++-name))
 (slot-pointer (format nil "&(~A)" slot-value))
 (tag (c++-type-to-ffi-tag c++-type)))
    (loop for reader in readers
       for c-form = (format nil "ecl_foregin_data_ref(~A, ~A)"
    slot-pointer value-c-tag)
       collect `(defmethod ,reader ((o ,class-name))
  (ffi:c-inline ((c++-object-pointer o))
 (:pointer-void) :object
,c-form :one-liner t)))))


(defmacro defc++class ((lisp-class-name c++-class-name) parents
slot-definitions)
  (let ((parse-definitions (mapcar #'parse-slot-definition
slot-definitions)))
    `(progn
       (defclass ,lisp-class-name ,(append parents '(c++-object))
 (definition :initform ',slot-definitions))
       ,@(loop for d in parsed-definitions
    nconc (apply #'build-readers lisp-name c++-class-name d)))))

#|
Assuming

struct foo {
  int a;
};

|#

(defc++class (foo "foo") ()
  ((a :c-type :int :reader foo-a)))


-- 
Instituto de Física Fundamental, CSIC
c/ Serrano, 113b, Madrid 28006 (Spain)
http://juanjose.garciaripoll.googlepages.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/ecl-devel/attachments/20121207/e47ea887/attachment.html>


More information about the ecl-devel mailing list