|
899 | 899 | (host-new (or (deftype-ctor-class ctx class) class) |
900 | 900 | (mapv #(analyze ctx % env) args))) |
901 | 901 |
|
| 902 | +;; Literal, data-only struct descriptors. Keep the analyzer representation free |
| 903 | +;; of reader objects so it survives self-hosting and can be embedded in the IR. |
| 904 | +(def ^:private ffi-layout-scalars |
| 905 | + #{"int" "uint" "int8" "i8" "uint8" "u8" "byte" "char" |
| 906 | + "int16" "short" "uint16" "ushort" "int32" "uint32" |
| 907 | + "long" "ulong" "int64" "uint64" "size_t" "ssize_t" "iptr" "uptr" |
| 908 | + "double" "float" "pointer" "void*"}) |
| 909 | + |
| 910 | +(declare analyze-ffi-layout-type) |
| 911 | + |
| 912 | +(defn- analyze-ffi-layout-struct [form] |
| 913 | + (when-not (form-vec? form) |
| 914 | + (throw (str "jolt.ffi layout descriptor must be [:struct [[field type] ...]], got " |
| 915 | + (pr-str form)))) |
| 916 | + (let [parts (vec (form-vec-items form))] |
| 917 | + (when-not (and (= 2 (count parts)) |
| 918 | + (form-keyword? (nth parts 0)) |
| 919 | + (nil? (namespace (nth parts 0))) |
| 920 | + (= "struct" (name (nth parts 0))) |
| 921 | + (form-vec? (nth parts 1))) |
| 922 | + (throw (str "jolt.ffi layout descriptor must be [:struct [[field type] ...]], got " |
| 923 | + (pr-str form)))) |
| 924 | + (let [field-forms (vec (form-vec-items (nth parts 1)))] |
| 925 | + (when (empty? field-forms) |
| 926 | + (throw "jolt.ffi struct descriptor must contain at least one field")) |
| 927 | + (loop [remaining field-forms names #{} fields []] |
| 928 | + (if (empty? remaining) |
| 929 | + {:ffi-kind :struct :fields fields} |
| 930 | + (let [field (first remaining)] |
| 931 | + (when-not (form-vec? field) |
| 932 | + (throw (str "jolt.ffi struct field must be [keyword type], got " |
| 933 | + (pr-str field)))) |
| 934 | + (let [fp (vec (form-vec-items field))] |
| 935 | + (when-not (= 2 (count fp)) |
| 936 | + (throw (str "jolt.ffi struct field must be [keyword type], got " |
| 937 | + (pr-str field)))) |
| 938 | + (let [field-name (nth fp 0)] |
| 939 | + (when-not (and (form-keyword? field-name) |
| 940 | + (nil? (namespace field-name))) |
| 941 | + (throw (str "jolt.ffi struct field name must be an unqualified keyword, got " |
| 942 | + (pr-str field-name)))) |
| 943 | + (let [nm (name field-name)] |
| 944 | + (when (contains? names nm) |
| 945 | + (throw (str "jolt.ffi struct field names must be unique; duplicate :" nm))) |
| 946 | + (recur (rest remaining) |
| 947 | + (conj names nm) |
| 948 | + (conj fields {:name nm |
| 949 | + :type (analyze-ffi-layout-type (nth fp 1))}))))))))))) |
| 950 | + |
| 951 | +(defn- analyze-ffi-layout-type [form] |
| 952 | + (cond |
| 953 | + (form-keyword? form) |
| 954 | + (let [n (name form)] |
| 955 | + (when-not (and (nil? (namespace form)) (contains? ffi-layout-scalars n)) |
| 956 | + (throw (str "jolt.ffi struct field type must be a fixed-size scalar or nested struct; got " |
| 957 | + (pr-str form)))) |
| 958 | + n) |
| 959 | + |
| 960 | + (form-vec? form) (analyze-ffi-layout-struct form) |
| 961 | + |
| 962 | + :else |
| 963 | + (throw (str "jolt.ffi struct field type must be a fixed-size scalar or nested struct; got " |
| 964 | + (pr-str form))))) |
| 965 | + |
| 966 | +(defn- analyze-ffi-layout [items] |
| 967 | + (when-not (= 2 (count items)) |
| 968 | + (throw "jolt.ffi/layout expects one literal struct descriptor")) |
| 969 | + {:op :ffi-layout :layout (analyze-ffi-layout-struct (nth items 1))}) |
| 970 | + |
902 | 971 | ;; jolt.ffi/__cfn: the low-level foreign-function form a jolt library |
903 | 972 | ;; uses (via the jolt.ffi/foreign-fn macro) to bind native code. Shape: |
904 | 973 | ;; (jolt.ffi/__cfn "c_symbol" [:argtype ...] :rettype) ; non-blocking |
|
1235 | 1304 | (and (form-sym? head) (= "jolt.ffi" (form-sym-ns head)) |
1236 | 1305 | (= "__cfn" (form-sym-name head))) |
1237 | 1306 | (analyze-ffi-fn ctx items env) |
| 1307 | + ;; jolt.ffi/layout expands to this literal-only leaf. The back end |
| 1308 | + ;; asks Chez for the actual ABI size, alignment and offsets. |
| 1309 | + (and (form-sym? head) (= "jolt.ffi" (form-sym-ns head)) |
| 1310 | + (= "__layout" (form-sym-name head))) |
| 1311 | + (analyze-ffi-layout items) |
1238 | 1312 | ;; jolt.ffi/__ccallable — the foreign-callback special form (the fn is a |
1239 | 1313 | ;; child expression, analyzed here). |
1240 | 1314 | (and (form-sym? head) (= "jolt.ffi" (form-sym-ns head)) |
|
0 commit comments