summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmamut.lisp142
1 files changed, 75 insertions, 67 deletions
diff --git a/cmamut.lisp b/cmamut.lisp
index dc62a98..d30821e 100644
--- a/cmamut.lisp
+++ b/cmamut.lisp
@@ -11,11 +11,11 @@
; 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 enum-references (make-hash-table :test #'equal :size 256))
-(defun get-spec ()
+; TODO: Use c2ffi to extract the spec.json using the header file as parameter
+(defun get-raw-spec ()
(json:from-file "~/common-lisp/cmamut/spec.json"))
(defun cook-type (raw-type)
@@ -63,7 +63,7 @@
(cook-struct raw-type))
((string= tag "union")
(cook-union raw-type))
- (t tag))))
+ (t tag)))) ;TODO: Add type resolution
(defun cook-function (raw-function &optional name-transformer)
(let ((raw-params (gethash "parameters" raw-function))
@@ -80,15 +80,6 @@
,(cook-type (gethash "return-type" raw-function))
,@(queue:to-list cooked-params))))
-(defun cook-typedef (raw-typedef)
- (let* ((base-type (gethash "type" raw-typedef))
- (new-name (gethash "name" raw-typedef)))
- (if (string= (gethash "tag" base-type) ":enum")
- (progn (setf (gethash (gethash "id" base-type) enum-references) new-name) nil)
- `(sb-alien:define-alien-type
- ,new-name
- ,(cook-type base-type)))))
-
(defun cook-struct (raw-struct)
(let ((raw-fields (gethash "fields" raw-struct))
(cooked-fields (queue:new)))
@@ -127,23 +118,20 @@
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)
+; If the enum table population gets done at an earlier stage and all typedefs get flattened, there would be no need of having codegen for typedefs.
+(defun cook-typedef (raw-typedef)
+ (let* ((base-type (gethash "type" raw-typedef))
+ (new-name (gethash "name" raw-typedef)))
+ (if (string= (gethash "tag" base-type) ":enum")
+ (progn (setf (gethash (gethash "id" base-type) enum-references) new-name) nil)
+ `(sb-alien:define-alien-type
+ ,new-name
+ ,(cook-type base-type)))))
+
+; Generates a table for type resolution.
+; Typedefs get "flattened" so that resolving is just a lookup.
+(defun flatten-typedefs (raw-typedefs)
+ (let ((type-associations (make-hash-table :test #'equal :size 256)))
(labels ((take-deps
(deps)
(let (remaining)
@@ -166,7 +154,7 @@
(unless (eq v t)
(associate-base-type k v)))
type-associations))
- result)))
+ result))))
(defstruct spec
functions
@@ -175,41 +163,57 @@
unions
enums)
-(defun classify-definitions (spec)
- (let ((s (make-spec)))
- (dotimes (i (length spec))
- (let ((tag (gethash "tag" (aref spec i))))
- (cond ((string= tag "function")
- (push (aref spec i) (spec-functions s)))
-
- ((string= tag "typedef")
- (let ((internal-type (gethash "type" (aref spec i))))
- (cond ((string= (gethash "tag" internal-type) "struct")
- (when (string= (gethash "name" internal-type) "")
- (setf (gethash "name" internal-type) (gethash "name" (aref spec i))))
- (push (gethash "type" (aref spec i)) (spec-structs s))
- (setf (gethash "type" (aref spec i))
- (json:from-string
- (format nil
- "{ \"tag\": \":struct\", \"name\": ~s }"
- (gethash "name" internal-type))))))
- (push (aref spec i) (spec-typedefs s))))
-
- ((string= tag "struct")
- (push (aref spec i) (spec-structs s)))
- ((string= tag "enum")
- (push (aref spec i) (spec-enums s)))
- ((string= tag "union")
- (push (aref spec i) (spec-unions s)))
- (t))))
- s))
+; This is done so we can separate definition types into stages when generating code.
+; Some crazy shit is happening when processing typedefs so we can identify nested composite types and put them into the right buckets.
+; What's left on the typedefs are references to said composite types.
+; This allows for a comfier type resolution stage by letting us flatten typedefs.
+; Composite types cause problems because they can't be redefined.
+(defun classify-definitions (raw-spec)
+ (let ((spec (make-spec)))
+ (dotimes (i (length raw-spec))
+ (classify-definition (aref raw-spec i) spec))
+ spec))
+
+(defun classify-definition (def spec)
+ (let ((tag (gethash "tag" def)))
+ (cond ((string= tag "function")
+ (push def (spec-functions spec)))
+
+ ((or (string= tag "typedef")
+ (string= tag ":array")
+ (string= tag ":pointer"))
+ (let* ((internal-type (gethash "type" def))
+ (internal-tag (gethash "tag" internal-type)))
+ (cond ((or (string= internal-tag "struct")
+ (string= internal-tag "union"))
+ (when (string= (gethash "name" internal-type) "")
+ (setf (gethash "name" internal-type) (gethash "name" def)))
+ (classify-definition internal-type spec)
+ (setf (gethash "type" def)
+ (json:from-string
+ (format nil
+ "{ \"tag\": \":~a\", \"name\": ~s }"
+ (gethash "tag" internal-type)
+ (gethash "name" internal-type)))))
+ ((or (string= internal-tag ":array")
+ (string= internal-tag ":pointer"))
+ (classify-definition internal-type spec)))
+ (when (string= tag "typedef")
+ (push def (spec-typedefs spec)))))
+
+ ((string= tag "struct")
+ (push def (spec-structs spec)))
+ ((string= tag "enum")
+ (push def (spec-enums spec)))
+ ((string= tag "union")
+ (push def (spec-unions spec)))))
+ spec)
(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)
@@ -219,19 +223,23 @@
(mapcar (lambda (x)
`(sb-alien:define-alien-type nil ,(cook-union x)))
(spec-unions spec)))
+ (setf (spec-functions spec) (mapcar #'cook-function (spec-functions spec)))
spec)
-(defun to-file (spec filename)
+(defun to-json-file (code filename)
+ (with-open-file (f filename
+ :direction :output
+ :if-exists :supersede
+ :if-does-not-exist :create)
+ (let ((*print-length* nil)
+ (*print-level* nil))
+ (format f "~{~a~&~}" (mapcar #'json:to-string code)))))
+
+(defun to-file (code filename)
(with-open-file (f filename
:direction :output
:if-exists :supersede
:if-does-not-exist :create)
- (princ ";;; GENERATED BY CMAMUT" f)
- (terpri f)
(let ((*print-length* nil)
(*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)))))
+ (format f "~{~s~&~}" code))))