(provide "wrappers")
(defpackage "C-WRAPPERS" (:nicknames "WRAP") (:use "XLISP"))
(in-package "C-WRAPPERS")
(export '(make-wrappers
c-lines c-constant c-variable c-function c-subr c-pointer c-version))
(defvar *wrapper-functions*)
(defvar *wrapper-fixnum-constants*)
(defvar *wrapper-unsigned-constants*)
(defvar *wrapper-flonum-constants*)
(defvar *wrapper-string-constants*)
(defvar *wrapper-cptr-types*)
(defvar *wrapper-module-version*)
(defvar *c-output*)
(defun write-c-line (fmt &rest args)
(format *c-output* "~&~?~%" fmt args)
nil)
(defun make-wrappers (file &key (name (pathname-name file)))
(unless (equal (pathname-type file) "wrp")
(error "file ~a does not have a .wrp extension" file))
(let ((c-file (merge-pathnames (make-pathname :name name :type "c") file))
(lisp-file (merge-pathnames (make-pathname :name name :type "lsp") file))
(*package* *package*)
(*readtable* *readtable*)
(*wrapper-functions* nil)
(*wrapper-fixnum-constants* nil)
(*wrapper-unsigned-constants* nil)
(*wrapper-flonum-constants* nil)
(*wrapper-string-constants* nil)
(*wrapper-cptr-types* nil)
(*wrapper-module-version* nil)
(eof (cons nil nil)))
(with-open-file (in file)
(with-open-file (*c-output* c-file :direction :output)
(with-open-file (lisp-out lisp-file :direction :output)
(write-c-line "/* Generated automatically from ~a by make-wrappers. */" file)
(write-c-line "#include \"xlshlib.h\"")
(write-c-line "#include \"xlwrap.h\"")
(format lisp-out ";; Generated automatically from ~a by make-wrappers.~%" file)
(loop
(let ((expr (read in nil eof)))
(when (eq expr eof) (return))
(let ((wexpr (wrap-expression expr)))
(when wexpr
(let ((*print-readably* t)
(system:*print-symbol-package* t))
(format lisp-out "~&~s~%" wexpr))))))
(let ((path (format nil "(merge-pathnames \"~a.dll\" *load-truename*)" name))
(vers (if *wrapper-module-version*
(let* ((major (first *wrapper-module-version*))
(minor (second *wrapper-module-version*))
(oldmajor (third *wrapper-module-version*))
(oldminor (fourth *wrapper-module-version*))
(vers (+ (* (^ 2 16) major) minor))
(oldvers (+ (* (^ 2 16) oldmajor) oldminor)))
(format nil "~d ~d" vers oldvers))
nil)))
(format lisp-out "(shlib::load-shared-library ~a ~s ~@[ ~a~])~%" path name vers))
(let ((system:*print-symbol-package* t))
(write-c-line "static FUNDEF ~a_funs[] = {" name)
(dolist (e (reverse *wrapper-functions*))
(let ((sym (first e))
(fun (second e))
(mvals (third e)))
(unless (symbol-package sym) (error "~s has no package" sym))
(write-c-line " { \"~s\", ~:[SUBR~;MVSUBR~], ~a }," sym mvals fun)))
(write-c-line " { NULL, 0, NULL}~%};")
(write-c-line "static FIXCONSTDEF ~a_fixconsts[] = {" name)
(dolist (e (reverse *wrapper-fixnum-constants*))
(let ((sym (car e))
(val (cdr e)))
(unless (symbol-package sym) (error "~s has no package" sym))
(write-c-line " { \"~s\", ~a }," sym val)))
(write-c-line " { NULL, 0}~%};")
(write-c-line "static FLOCONSTDEF ~a_floconsts[] = {" name)
(dolist (e (reverse *wrapper-flonum-constants*))
(let ((sym (car e))
(val (cdr e)))
(unless (symbol-package sym) (error "~s has no package" sym))
(write-c-line " { \"~s\", ~a }," sym val)))
(write-c-line " { NULL, 0.0}~%};")
(write-c-line "static STRCONSTDEF ~a_strconsts[] = {" name)
(dolist (e (reverse *wrapper-string-constants*))
(let ((sym (car e))
(val (cdr e)))
(unless (symbol-package sym) (error "~s has no package" sym))
(write-c-line " { \"~s\", ~a }," sym val)))
(write-c-line " { NULL, NULL}~%};")
(write-c-line "static ULONGCONSTDEF ~a_ulongconsts[] = {" name)
(dolist (e (reverse *wrapper-unsigned-constants*))
(let ((sym (car e))
(val (cdr e)))
(unless (symbol-package sym) (error "~s has no package" sym))
(write-c-line " { \"~s\", ~a }," sym val)))
(write-c-line " { NULL, 0}~%};")
(let ((vers (if *wrapper-module-version* *wrapper-module-version* '(0 1 0 1))))
(write-c-line "static xlshlib_modinfo_t ~a_info = {~%~
~2tXLSHLIB_VERSION_INFO(~{~d,~d,~d,~d~}),~%~
~2t~a_funs,~%~
~2t~a_fixconsts,~%~
~2t~a_floconsts,~%~
~2t~a_strconsts,~%~
~2t~a_ulongconsts~%};"
name vers name name name name name))
(write-c-line "xlshlib_modinfo_t *~a__init(void) { return &~a_info; }"
name name)))))))
(defun wrap-expression (expr)
(case (first expr)
(macrolet (error "top level MACROLET not supported in wrappers"))
(eval-when
(let ((sits (second expr)))
(when (or (member 'compile sits) (member :compile-toplevel sits))
(dolist (e (rest (rest expr)))
(eval e))))
expr)
((defun defstruct do do* dolist dotimes) expr)
(progn `(progn ,@(mapcar #'wrap-expression (rest expr))))
((in-package defpackage defmacro) (eval expr) expr)
(t (multiple-value-bind (ee again) (macroexpand expr)
(if again
(wrap-expression ee)
ee)))))
(defun c-type (type)
(case type
(:void "void")
(:integer "long")
(:unsigned "unsigned long")
(:flonum "double")
(:string "char *")
(:lval "LVAL")
(t (cond
((stringp type) type)
((signed-type-p type) (format nil "signed ~a" (second type)))
((unsigned-type-p type) (format nil "unsigned ~a" (second type)))
((pointer-type-p type) (format nil "~a *" (c-type (second type))))
((struct-type-p type) (format nil "struct ~a" (second type)))
((union-type-p type) (format nil "union ~a" (second type)))
(t (error "type ~s is unknown" type))))))
(defun mangled-type (type)
(case type
(:void "void")
(:integer "long")
(:unsigned "unsigned_long")
(:flonum "double")
(:string "c_string")
(:lval "LVAL")
(t (cond
((stringp type) type)
((signed-type-p type) (format nil "signed_~a" (second type)))
((unsigned-type-p type) (format nil "unsigned_~a" (second type)))
((pointer-type-p type) (format nil "~a_P" (mangled-type (second type))))
((struct-type-p type) (format nil "S_~a" (second type)))
((union-type-p type) (format nil "U_~a" (second type)))
(t (error "type ~s is unknown" type))))))
(defun pointer-type-p (type)
(and (consp type) (eq (first type) :cptr)))
(defun signed-type-p (type)
(and (consp type) (eq (first type) :signed)))
(defun unsigned-type-p (type)
(and (consp type) (eq (first type) :unsigned)))
(defun struct-type-p (type)
(and (consp type) (eq (first type) :struct)))
(defun union-type-p (type)
(and (consp type) (eq (first type) :union)))
(defun register-pointer-type (type)
(unless *wrapper-cptr-types*
(push "void" *wrapper-cptr-types*)
(write-c-line "DECLARE_CPTR_TYPE(~a)" "void"))
(unless (member type *wrapper-cptr-types* :test #'equal)
(push type *wrapper-cptr-types*)
(write-c-line "DECLARE_CPTR_TYPE(~a)" (mangled-type type))))
(defmacro c-lines (&rest lines)
(dolist (ln lines)
(write-c-line ln)))
(defmacro c-constant (name cname type)
(case type
(:integer (push (cons name cname) *wrapper-fixnum-constants*))
(:unsigned (push (cons name cname) *wrapper-unsigned-constants*))
(:flonum (push (cons name cname) *wrapper-flonum-constants*))
(:string (push (cons name cname) *wrapper-string-constants*))
(t (error "can't handle constants of type ~s" type)))
nil)
(defmacro c-variable (name type &rest clauses)
(when (pointer-type-p type)
(register-pointer-type (second type)))
(dolist (c clauses)
(case (first c)
(:get (write-c-variable-get name type (second c)))
(:set (write-c-variable-set name type (second c))))))
(defconstant c-variable-get-fmt "~
static LVAL ~a(void) {
xllastarg();
return ~@?;
}")
(defun write-c-variable-get (name type fun)
(let ((cfun (c-function-name "get_~a_var" name)))
(write-c-line c-variable-get-fmt cfun (c-value-fmt type) name nil)
(register-subr fun cfun)))
(defun c-function-name (fmt &rest args)
(format nil "xlw_~?" fmt args))
(defun register-subr (lisp-name c-name &optional mvals)
(push (list lisp-name c-name mvals) *wrapper-functions*)
nil)
(defun c-value-fmt (type)
(case type
(:void "NIL")
(:integer "long2lisp(~a)")
(:unsigned "ulong2lisp(~a)")
(:flonum "cvflonum(~a)")
(:string "cvstrornil(~a)")
(:lval "~a")
(t (if (pointer-type-p type)
(format nil "cvcptr(CPTR_TYPE(~a),~~a,~~a)"
(mangled-type (second type)))
(error "can't handle ~a value type" type)))))
(defconstant c-variable-set-fmt "~
static LVAL ~a(void) {
LVAL xlw__val = xlgetarg();
xllastarg();
~a = ~@?;
return xlw__val;
}")
(defun write-c-variable-set (name type fun)
(let ((cfun (c-function-name "set_~a_var" name))
(afmt (c-argument-fmt type)))
(write-c-line c-variable-set-fmt cfun name afmt "xlw__val")
(register-subr fun cfun)))
(defun c-argument-fmt (type)
(case type
(:integer "lisp2long(~a)")
(:unsigned "lisp2ulong(~a)")
(:flonum "makefloat(~a)")
(:string "getstring(~a)")
(:lval "~a")
(t (error "can't handle ~a argument type" type))))
(defconstant c-function-fmt "~
static LVAL ~a(void)
{
~:{~& ~a ~a = ~a;~}
~@[~& ~a xlw__v;~]~& xllastarg();
~@[~*xlw__v = ~]~a(~:[~2*~;~a~{,~a~}~]);
return ~@?;
}")
(defmacro c-function (name cname args value)
(dolist (a args)
(when (pointer-type-p a)
(register-pointer-type (second a))))
(when (pointer-type-p value)
(register-pointer-type (second value)))
(let* ((fun (c-function-name "_~a_wrap" cname))
(ainfo (c-function-arginfo args))
(anames (mapcar #'second ainfo))
(vt (if (eq value :void) nil (c-type value))))
(write-c-line c-function-fmt
fun
ainfo
vt
vt cname anames (first anames) (rest anames)
(c-value-fmt value) "xlw__v" "NIL")
(register-subr name fun)))
(defun c-function-arginfo (args)
(let ((val nil)
(count 0))
(dolist (a args (nreverse val))
(incf count)
(let ((ct (c-type a))
(v (format nil "xlw__x~d" count))
(arg (if (pointer-type-p a)
(format nil "getcpaddr(xlgacptr(CPTR_TYPE(~a),~a))"
(mangled-type (second a))
(if (third a) "TRUE" "FALSE"))
(format nil (c-argument-fmt a) "xlgetarg()"))))
(push (list ct v arg) val)))))
(defmacro c-subr (fun cfun &optional mvals)
(register-subr fun cfun mvals))
(defmacro c-pointer (type &rest clauses)
(register-pointer-type type)
(dolist (c clauses)
(case (first c)
(:make (write-c-pointer-make type (second c)))
(:cast (write-c-pointer-cast type (second c)))
(:offset (write-c-pointer-offset type (second c)))
(:get (write-c-pointer-get type (second c) (third c) (fourth c)))
(:set (write-c-pointer-set type (second c) (third c) (fourth c))))))
(defconstant c-pointer-make-fmt "~
static LVAL ~a(void)
{
return xlw_make_cptr(CPTR_TYPE(~a), sizeof(~a));
}")
(defun write-c-pointer-make (type fun)
(let* ((mt (mangled-type type))
(ct (c-type type))
(cfun (c-function-name "make_~a_cptr" mt)))
(if (equal type "void")
(write-c-line c-pointer-make-fmt cfun "void" "char")
(write-c-line c-pointer-make-fmt cfun mt ct))
(register-subr fun cfun)))
(defconstant c-pointer-cast-fmt "~
static LVAL ~a()
{
return xlw_cast_cptr(CPTR_TYPE(~a));
}")
(defun write-c-pointer-cast (type fun)
(let* ((mt (mangled-type type))
(cfun (c-function-name "cast_~a_cptr" mt)))
(write-c-line c-pointer-cast-fmt cfun mt)
(register-subr fun cfun)))
(defconstant c-pointer-offset-fmt "~
static LVAL ~a(void)
{
return xlw_offset_cptr(CPTR_TYPE(~a), sizeof(~a));
}")
(defun write-c-pointer-offset (type fun)
(let* ((mt (mangled-type type))
(ct (c-type type))
(cfun (c-function-name "offset_~a_cptr" mt)))
(if (equal type "void")
(write-c-line c-pointer-offset-fmt cfun "void" "char")
(write-c-line c-pointer-offset-fmt cfun mt ct))
(register-subr fun cfun)))
(defconstant c-pointer-get-fmt "~
static LVAL ~a(void)
{
LVAL p = xlgacptr(CPTR_TYPE(~a), FALSE);
~a *x = getcpaddr(p);
FIXTYPE off = moreargs() ? getfixnum(xlgafixnum()) : 0;
xllastarg();
return ~@?;
}")
(defun write-c-pointer-get (type fun field vtype)
(when (pointer-type-p vtype)
(register-pointer-type (second vtype)))
(let* ((ct (c-type type))
(mt (mangled-type type))
(cfun (c-function-name "get_~a~@[_~a~]" mt field))
(val (format nil "x[off]~@[.~a~]" field))
(cvt (c-value-fmt vtype)))
(write-c-line c-pointer-get-fmt cfun mt ct cvt val "p")
(register-subr fun cfun)))
(defconstant c-pointer-set-fmt "~
static LVAL ~a(void)
{
~a *x = getcpaddr(xlgacptr(CPTR_TYPE(~a), FALSE));
LVAL val = xlgetarg();
FIXTYPE off = moreargs() ? getfixnum(xlgafixnum()) : 0;
xllastarg();
x[off]~@[.~a~] = ~@?;
return val;
}")
(defun write-c-pointer-set (type fun field vtype)
(when (pointer-type-p vtype)
(register-pointer-type (second vtype)))
(let* ((mt (mangled-type type))
(ct (c-type type))
(cfun (c-function-name "set_~a~@[_~a~]" mt field))
(cvt (c-argument-fmt vtype)))
(write-c-line c-pointer-set-fmt cfun ct mt field cvt "val")
(register-subr fun cfun)))
(defmacro c-version (&optional (major 0) (minor 0)
(oldmajor major) (oldminor minor))
(setf *wrapper-module-version* (list major minor oldmajor oldminor))
nil)
(defconstant c-callback-fmt "~
static ~a ~a(~a x1, ~a x2)
{
LVAL xlw_x1, xlw_x2, xlw_v;
static LVAL fsym = NULL;
if (fsym == NULL)
fsym = xlenter(\"~a\");
xlstkcheck(2);
xlsave(2);
xlw_x1 = ~@?;
xlw_x1 = ~@?;
xlw_v = xlappn(xlgetfunction(fsym), 2, xlw_x1, xlw_x2);
xlpopn(2);
return ...;
}")
syntax highlighted by Code2HTML, v. 0.9.1