summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmamut.lisp128
1 files changed, 90 insertions, 38 deletions
diff --git a/cmamut.lisp b/cmamut.lisp
index a132744..bacca56 100644
--- a/cmamut.lisp
+++ b/cmamut.lisp
@@ -2,15 +2,19 @@
; Ideas:
; Generate code that creates a package and puts all definitions there.
-; If symbol names are unaltered we can skip connecting everything together.
; To avoid collisions the created package shouldn't import any symbols.
-; Maybe use straight defuns and ffi functions to get as close as possible to the C names without much work.
; Only define functions from the target library, but get all other definitions.
+; To reduce amount of names being generated, resolve all types to their base counterparts
+; Separate generation, preprocessing and type resolution phases
+; Preprocessing phase should handle enums, structs and unions
+; Basic types are handled by type resolution phase
+; Can put an error to default case in cook type to enforce type resolution
; TODO: Get constants from macro file generated by c2ffi -M
; TODO: Use c2ffi to extract the spec.json using the header file as parameter
-(defvar reference-table (make-hash-table :test #'equal :size 256))
+(defvar enum-references (make-hash-table :test #'equal :size 256))
+(defvar type-associations (make-hash-table :test #'equal :size 256))
(defun get-spec ()
(json:from-file "~/common-lisp/cmamut/spec.json"))
@@ -23,9 +27,11 @@
'sb-alien:function)
((string= tag ":pointer")
(let ((pointed-type (gethash "type" raw-type)))
- (if (string= (gethash "tag" pointed-type) ":char")
- 'sb-alien:c-string
- (list 'sb-alien:* (cook-type pointed-type)))))
+ (cond ((string= (gethash "tag" pointed-type) ":char")
+ 'sb-alien:c-string)
+ ((string= (gethash "tag" pointed-type) ":void")
+ (list 'sb-alien:* t))
+ (t (list 'sb-alien:* (cook-type pointed-type))))))
((string= tag ":float")
'sb-alien:float)
((string= tag ":double")
@@ -47,7 +53,9 @@
((or (string= tag ":long") (string= tag ":signed-long"))
'sb-alien:long)
((string= tag ":array")
- (cook-array raw-type))
+ (list 'sb-alien:array
+ (cook-type (gethash "type" raw-type))
+ (gethash "size" raw-type)))
((string= tag ":struct")
(list 'sb-alien:struct (intern (gethash "name" raw-type))))
((string= tag ":union")
@@ -56,12 +64,13 @@
(cook-struct raw-type))
((string= tag "union")
(cook-union raw-type))
- (t tag))))
-
-(defun cook-array (raw-array)
- `(sb-alien:array
- ,(cook-type (gethash "type" raw-array))
- ,(gethash "size" raw-array)))
+ (t
+ (let ((new-tag (gethash tag type-associations)))
+ (if new-tag
+ (progn
+ (setf (gethash "tag" raw-type) new-tag)
+ (cook-type raw-type))
+ (error (format nil "Unknown type tag ~a" tag))))))))
(defun cook-function (raw-function &optional name-transformer)
(let ((raw-params (gethash "parameters" raw-function))
@@ -82,8 +91,7 @@
(let* ((base-type (gethash "type" raw-typedef))
(new-name (gethash "name" raw-typedef)))
(if (string= (gethash "tag" base-type) ":enum")
- (setf (gethash (gethash "id" base-type) reference-table)
- new-name)
+ (progn (setf (gethash (gethash "id" base-type) enum-references) new-name) nil)
`(sb-alien:define-alien-type
,new-name
,(cook-type base-type)))))
@@ -96,7 +104,8 @@
(list (intern (string-upcase (gethash "name" (aref raw-fields j))))
(cook-type (gethash "type" (aref raw-fields j))))))
`(sb-alien:struct
- ,(intern (gethash "name" raw-struct))
+ ,(when (> (length (gethash "name" raw-struct)) 0)
+ (intern (gethash "name" raw-struct)))
,@(queue:to-list cooked-fields))))
(defun cook-union (raw-union)
@@ -107,11 +116,12 @@
(list (intern (string-upcase (gethash "name" (aref raw-fields j))))
(cook-type (gethash "type" (aref raw-fields j))))))
`(sb-alien:union
- ,(intern (gethash "name" raw-union))
+ ,(when (> (length (gethash "name" raw-union)) 0)
+ (intern (gethash "name" raw-union)))
,@(queue:to-list cooked-fields))))
(defun cook-enum (raw-enum)
- (let ((name (gethash (gethash "id" raw-enum) reference-table))
+ (let ((name (gethash (gethash "id" raw-enum) enum-references))
(raw-fields (gethash "fields" raw-enum))
(cooked-fields (queue:new)))
(dotimes (j (length raw-fields))
@@ -124,6 +134,47 @@
nil
,@(queue:to-list cooked-fields)))))
+(defun filter-base-types (raw-typedefs)
+ (clrhash type-associations)
+ (setf (gethash ":char" type-associations) t)
+ (setf (gethash ":short" type-associations) t)
+ (setf (gethash ":int" type-associations) t)
+ (setf (gethash ":long" type-associations) t)
+ (setf (gethash ":signed-char" type-associations) t)
+ (setf (gethash ":signed-short" type-associations) t)
+ (setf (gethash ":signed-int" type-associations) t)
+ (setf (gethash ":signed-long" type-associations) t)
+ (setf (gethash ":unsigned-char" type-associations) t)
+ (setf (gethash ":unsigned-short" type-associations) t)
+ (setf (gethash ":unsigned-int" type-associations) t)
+ (setf (gethash ":unsigned-long" type-associations) t)
+ (setf (gethash ":float" type-associations) t)
+ (setf (gethash ":double" type-associations) t)
+ (setf (gethash ":function-pointer" type-associations) t)
+ (labels ((take-deps
+ (deps)
+ (let (remaining)
+ (dolist (i deps)
+ (let ((tag (gethash "tag" (gethash "type" i))))
+ (if (gethash tag type-associations)
+ (setf (gethash (gethash "name" i) type-associations) tag)
+ (push i remaining))))
+ (if (= (length deps) (length remaining))
+ remaining
+ (take-deps remaining)))))
+ (let ((result (take-deps raw-typedefs)))
+ (labels ((associate-base-type
+ (k v)
+ (let ((new-v (gethash v type-associations)))
+ (if (eq new-v t)
+ (setf (gethash k type-associations) v)
+ (associate-base-type k new-v)))))
+ (maphash (lambda (k v)
+ (unless (eq v t)
+ (associate-base-type k v)))
+ type-associations))
+ result)))
+
(defstruct spec
functions
typedefs
@@ -131,8 +182,7 @@
unions
enums)
-(defun prepare-spec (spec)
- (clrhash reference-table)
+(defun classify-definitions (spec)
(let ((s (make-spec)))
(dotimes (i (length spec))
(cond ((string= (gethash "tag" (aref spec i)) "function")
@@ -146,20 +196,25 @@
((string= (gethash "tag" (aref spec i)) "union")
(push (aref spec i) (spec-unions s)))
(t)))
-; typedefs must be generated first to build the reference table
- (setf (spec-typedefs s) (mapcar #'cook-typedef (spec-typedefs s)))
- (setf (spec-functions s) (mapcar #'cook-function (spec-functions s)))
- (setf (spec-enums s) (mapcar #'cook-enum (spec-enums s)))
- (setf (spec-structs s)
- (mapcar (lambda (x)
- `(sb-alien:define-alien-type nil ,(cook-struct x)))
- (spec-structs s)))
- (setf (spec-unions s)
- (mapcar (lambda (x)
- `(sb-alien:define-alien-type nil ,(cook-union x)))
- (spec-unions s)))
s))
+(defun codegen (spec)
+ (clrhash enum-references)
+ ; typedefs must be generated first to build the reference table
+ (setf (spec-typedefs spec)
+ (remove nil (mapcar #'cook-typedef (filter-base-types (spec-typedefs spec)))))
+ (setf (spec-functions spec) (mapcar #'cook-function (spec-functions spec)))
+ (setf (spec-enums spec) (mapcar #'cook-enum (spec-enums spec)))
+ (setf (spec-structs spec)
+ (mapcar (lambda (x)
+ `(sb-alien:define-alien-type nil ,(cook-struct x)))
+ (spec-structs spec)))
+ (setf (spec-unions spec)
+ (mapcar (lambda (x)
+ `(sb-alien:define-alien-type nil ,(cook-union x)))
+ (spec-unions spec)))
+ spec)
+
(defun to-file (spec filename)
(with-open-file (f filename
:direction :output
@@ -171,9 +226,6 @@
(*print-level* nil))
(format f "~{~s~&~}" (spec-enums spec))
(format f "~{~s~&~}" (spec-typedefs spec)))))
- ;(format f "~{~s~&~}" (spec-structs spec))
- ;(format f "~{~s~&~}" (spec-unions spec))
- ;(format f "~{~s~&~}" (spec-functions spec)))))
-
-(defun generate (filename)
- (to-file (prepare-spec (get-spec)) filename))
+;(format f "~{~s~&~}" (spec-structs spec))
+;(format f "~{~s~&~}" (spec-unions spec))
+;(format f "~{~s~&~}" (spec-functions spec)))))