diff --git a/Jenkinsfile b/Jenkinsfile index 32f3630..804e729 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -def tests = ['primitives', 'addressof', 'callback'] +def tests = ['primitives', 'array', 'addressof', 'callback'] pipeline { agent any diff --git a/Makefile b/Makefile index 9d319cf..f5df761 100644 --- a/Makefile +++ b/Makefile @@ -168,6 +168,9 @@ guile: kawa: @echo "Nothing to build for Kawa" +mit-scheme: + @echo "Nothing to build for Kawa" + larceny: @echo "Nothing to build for Larceny" diff --git a/README.md b/README.md index 219be24..b393694 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,10 @@ is portable in the sense that it supports multiple implementations. - c-bytevector-\>bytevector - string-\>c-utf8 - c-utf8-\>string + - [c-array](#c-array) + - make-c-array + - c-array-ref + - c-array-set! - [Environment variables](#environment-variables) @@ -646,6 +650,46 @@ UTF-8 encoding of the given string. Returns a newly allocated string whose character sequence is encoded by the given c-bytevector. It is an error if _c-bytevector_ is null. +### c-array + +(**make-c-array** _type_ _size_)

+(**make-c-array** _type_ _size_ _fill_) + +If the _fill_ argument is missing, the initial contents of the +returned c-bytevector are unspecified. + +If the _fill_ argument is present, it specifies the initial value for the items +of the array. If it's value does not match _type_ behaviour is unspecified. + +Returns a newly allocated c-bytevector with size of _type_ times _size_. + +(**c-array-ref** _array_ _type_ _index_) + +_array_ is a c-bytevector. + +Returns the given value of _type_ from _index_ of _array_. If the value is not +of _type_ or _index_ is out of bounds the behaviour is unspecified. + +(**c-array-set!** _array_ _type_ _index_ _value_) + +_array_ is a c-bytevector. + +Sets the given _value_ of _type_ at _index_ of _array_. If _value_ is not of +_type_ or _index_ is out of bounds behaviour is unspecified. + +(**list->c-array** list _type_) + +Returns newly allocated c-bytevector with values of the _list_ in it. List +values must be of _type_. If the values are not of type behaviour is +unspecified. + +(**c-array->list** _array_ _type_ _size_) + +_array_ is a c-bytevector. + +Returns a list with values of _array_ in it. If _type_ and _size_ do not match +what is in the _c-bytevector_ the behaviour is unspecified. + ### Utilities **libc-name** diff --git a/foreign/c.sld b/foreign/c.sld index 6fc75c7..ed97dfe 100644 --- a/foreign/c.sld +++ b/foreign/c.sld @@ -203,6 +203,8 @@ ;;;; Utilities libc-name + c-type-signed? + c-type-unsigned? ;; TODO endianness native-endianness @@ -281,14 +283,12 @@ ;c-string-length ;; TODO Documentation, Testing - ;; c-struct - ;pffi-define-struct;define-c-struct - ;pffi-struct-pointer;c-struct-bytevector - ;pffi-struct-offset-get;c-struct-offset - ;pffi-struct-set!;c-struct-set! - ;pffi-struct-get;c-struct-get - ;; c-array + make-c-array + c-array-ref + c-array-set! + list->c-array + c-array->list ;define-c-array (?) ;pffi-array-allocate;make-c-array ;pffi-array-pointer;c-array-pointer @@ -299,6 +299,14 @@ ;pffi-list->array;list->c-array ;pffi-array->list;c-array->list + ;; c-struct + ;pffi-define-struct;define-c-struct + ;pffi-struct-pointer;c-struct-bytevector + ;pffi-struct-offset-get;c-struct-offset + ;pffi-struct-set!;c-struct-set! + ;pffi-struct-get;c-struct-get + + ;; c-variable ;define-c-variable (?) ) @@ -325,10 +333,11 @@ bytevector-c-int8-set! bytevector-c-uint8-ref) (include "c/primitives/ypsilon.scm"))) + (include "c/c-types.scm") (include "c/main.scm") (include "c/libc.scm") (include "c/c-bytevectors.scm") (include "c/pointer.scm") - ;(include "c/array.scm") + (include "c/array.scm") ;(include "c/struct.scm") ) diff --git a/foreign/c/array.scm b/foreign/c/array.scm index 9d4bd7e..ce36a5d 100644 --- a/foreign/c/array.scm +++ b/foreign/c/array.scm @@ -1,58 +1,59 @@ -(define-record-type - (array-make type size pointer) - pffi-array? - (type pffi-array-type) - (size pffi-array-size) - (pointer pffi-array-pointer)) +(define make-c-array + (lambda (type size . fill) + (let ((array (make-c-bytevector (* (c-type-size type) size)))) + (when (not (null? fill)) + (letrec* ((filler (car fill)) + (looper (lambda (count) + (when (> size count) + (c-array-set! array type count filler) + (looper (+ count 1)))))) + (looper 0))) + array))) -(define pffi-list->array - (lambda (type list-arg) - (let* ((array-size (length list-arg)) - (type-size (c-size-of type)) +(define c-array-ref + (lambda (array type index) + (let* ((size (c-type-size type)) + (offset (* index size))) + (cond + ((equal? 'pointer type) + (c-bytevector-pointer-ref array offset)) + ((c-type-signed? type) + (c-bytevector-sint-ref array offset (native-endianness) size)) + (else + (c-bytevector-uint-ref array offset (native-endianness) size)))))) + +(define c-array-set! + (lambda (array type index value) + (let* ((size (c-type-size type)) + (offset (* index size))) + (cond + ((equal? 'pointer type) + (c-bytevector-pointer-set! array offset value)) + ((c-type-signed? type) + (c-bytevector-sint-set! array offset value (native-endianness) size)) + (else + (c-bytevector-uint-set! array offset value (native-endianness) size)))))) + +(define list->c-array + (lambda (list type) + (let* ((array-size (length list)) + (type-size (c-type-size type)) (array (make-c-bytevector (* type-size array-size))) - (offset 0)) + (index 0)) (for-each (lambda (item) - (pffi-pointer-set! array type offset item) - (set! offset (+ offset type-size))) - list-arg) - (array-make type array-size array)))) + (c-array-set! array type index item) + (set! index (+ index 1))) + list) + array))) -(define pffi-pointer->array - (lambda (pointer type size) - (array-make type size pointer))) - -(define pffi-array->list - (lambda (array) - (letrec* ((type (pffi-array-type array)) - (type-size (c-size-of type)) - (max-offset (* type-size (pffi-array-size array))) - (array-pointer (pffi-array-pointer array)) - (looper (lambda (offset result) - (if (= offset max-offset) - result - (looper (+ offset type-size) - (append result - (list (pffi-pointer-get array-pointer - type - offset)))))))) +(define c-array->list + (lambda (array type size) + (letrec* + ((looper (lambda (index result) + (if (>= index size) + result + (looper (+ index 1) + (append result + (list (c-array-ref array type index)))))))) (looper 0 (list))))) - -(define pffi-array-allocate - (lambda (type size) - (array-make type size (pffi-pointer-allocate-calloc size (c-size-of type))))) - -(define pffi-array-get - (lambda (array index) - (let ((type (pffi-array-type array))) - (pffi-pointer-get (pffi-array-pointer array) - type - (* (c-size-of type) index))))) - -(define pffi-array-set! - (lambda (array index value) - (let ((type (pffi-array-type array))) - (pffi-pointer-set! (pffi-array-pointer array) - type - (* (c-size-of type) index) - value)))) diff --git a/foreign/c/c-types.scm b/foreign/c/c-types.scm new file mode 100644 index 0000000..80e6220 --- /dev/null +++ b/foreign/c/c-types.scm @@ -0,0 +1,11 @@ +(define c-type-signed? + (lambda (type) + (if (member type '(int8 int16 int32 int64 char short int long float double)) + #t + #f))) + +(define c-type-unsigned? + (lambda (type) + (if (member type '(uint8 uint16 uint32 uint64 unsigned-char unsigned-short unsigned-int unsigned-long)) + #t + #f))) diff --git a/foreign/c/struct.scm b/foreign/c/struct.scm index 926b9ee..afa4f1f 100644 --- a/foreign/c/struct.scm +++ b/foreign/c/struct.scm @@ -1,12 +1,12 @@ -(define-record-type - (struct-make c-type size pointer members) - pffi-struct? - (c-type pffi-struct-c-type) - (size pffi-struct-size) - (pointer pffi-struct-pointer) - (members pffi-struct-members)) +(define-record-type + (c-struct-make c-type size pointer members) + c-struct? + (c-type c-struct:type) + (size c-struct:size) + (pointer c-struct:pointer) + (members c-struct:members)) -(define-syntax pffi-define-struct +(define-syntax define-c-struct (syntax-rules () ((_ name c-type members) (define name @@ -19,13 +19,7 @@ (car arguments) (make-c-bytevector size))) (c-type-string (if (string? c-type) c-type (symbol->string c-type)))) - (struct-make c-type-string size pointer offsets))))))) - -(define c-align-of - (lambda (type) - (cond-expand - ;(guile (alignof (pffi-type->native-type type))) - (else (size-of-type type))))) + (c-struct-make c-type-string size pointer offsets))))))) (define round-to-next-modulo-of (lambda (to-round roundee) @@ -81,19 +75,19 @@ (c-type (if (string? c-type) c-type (symbol->string c-type)))) (struct-make c-type size pointer offsets)))) -(define (pffi-struct-offset-get struct member-name) +#;(define (pffi-struct-offset-get struct member-name) (when (not (assoc member-name (pffi-struct-members struct))) (error "Struct has no such member" (list struct member-name))) (car (cdr (cdr (assoc member-name (pffi-struct-members struct)))))) -(define (pffi-struct-get struct member-name) +#;(define (pffi-struct-get struct member-name) (when (not (assoc member-name (pffi-struct-members struct))) (error "Struct has no such member" (list struct member-name))) (let ((type (car (cdr (assoc member-name (pffi-struct-members struct))))) (offset (car (cdr (cdr (assoc member-name (pffi-struct-members struct))))))) (pffi-pointer-get (pffi-struct-pointer struct) type offset))) -(define (pffi-struct-set! struct member-name value) +#;(define (pffi-struct-set! struct member-name value) (when (not (assoc member-name (pffi-struct-members struct))) (error "Struct has no such member" (list struct member-name))) (let ((type (car (cdr (assoc member-name (pffi-struct-members struct))))) diff --git a/tests/array.scm b/tests/array.scm new file mode 100644 index 0000000..de0e1c2 --- /dev/null +++ b/tests/array.scm @@ -0,0 +1,98 @@ +(import (scheme base) + (scheme write) + (scheme read) + (scheme char) + (scheme file) + (scheme process-context) + (foreign c)) + +;; util +(define header-count 1) + +(define print-header + (lambda (title) + (set-tag title) + (display "=========================================") + (newline) + (display header-count) + (display " ") + (display title) + (newline) + (display "=========================================") + (newline) + (set! header-count (+ header-count 1)))) + +(define count 0) +(define assert-tag 'none) + +(define set-tag + (lambda (tag) + (set! assert-tag tag) + (set! count 0))) + +(cond-expand + (gambit + (define assert + (lambda (check value-a value-b) + (let ((result (apply check (list value-a value-b)))) + (set! count (+ count 1)) + (if (not result) (display "FAIL ") (display "PASS ")) + (display "[") + (display assert-tag) + (display " - ") + (display count) + (display "]") + (display ": ") + (write (list 'check 'value-a 'value-b)) + (newline) + (when (not result) (exit 1)))))) + (else + (define-syntax assert + (syntax-rules () + ((_ check value-a value-b) + (let ((result (apply check (list value-a value-b)))) + (set! count (+ count 1)) + (if (not result) (display "FAIL ") (display "PASS ")) + (display "[") + (display assert-tag) + (display " - ") + (display count) + (display "]") + (display ": ") + (write (list 'check 'value-a 'value-b)) + (newline) + (when (not result) (exit 1)))))))) + +(define-syntax debug + (syntax-rules () + ((_ value) + (begin + (display 'value) + (display ": ") + (write value) + (newline))))) + +;; make-c-array + +(print-header 'make-c-array) + +(define arr (make-c-array 'uint64 10 0)) +(debug arr) + +(c-array-set! arr 'uint64 5 100) +(debug (c-array-ref arr 'uint64 5)) +(assert = (c-array-ref arr 'uint64 5) 100) + +(c-array-set! arr 'uint64 9 101) +(assert = (c-array-ref arr 'uint64 9) 101) + +(define l (c-array->list arr 'uint64 10)) +(debug l) +(assert equal? l '(0 0 0 0 0 100 0 0 0 101)) + +(define arr1 (list->c-array '(0 1 2 3 4 5 6 7 8 9) 'uint32)) + +(assert = (c-array-ref arr1 'uint32 0) 0) +(assert = (c-array-ref arr1 'uint32 3) 3) +(assert = (c-array-ref arr1 'uint32 8) 8) + diff --git a/tests/structs.scm b/tests/structs.scm new file mode 100644 index 0000000..ca5ecd5 --- /dev/null +++ b/tests/structs.scm @@ -0,0 +1,78 @@ +(import (scheme base) + (scheme write) + (scheme read) + (scheme char) + (scheme file) + (scheme process-context) + (foreign c)) + +;; util +(define header-count 1) + +(define print-header + (lambda (title) + (set-tag title) + (display "=========================================") + (newline) + (display header-count) + (display " ") + (display title) + (newline) + (display "=========================================") + (newline) + (set! header-count (+ header-count 1)))) + +(define count 0) +(define assert-tag 'none) + +(define set-tag + (lambda (tag) + (set! assert-tag tag) + (set! count 0))) + +(cond-expand + (gambit + (define assert + (lambda (check value-a value-b) + (let ((result (apply check (list value-a value-b)))) + (set! count (+ count 1)) + (if (not result) (display "FAIL ") (display "PASS ")) + (display "[") + (display assert-tag) + (display " - ") + (display count) + (display "]") + (display ": ") + (write (list 'check 'value-a 'value-b)) + (newline) + (when (not result) (exit 1)))))) + (else + (define-syntax assert + (syntax-rules () + ((_ check value-a value-b) + (let ((result (apply check (list value-a value-b)))) + (set! count (+ count 1)) + (if (not result) (display "FAIL ") (display "PASS ")) + (display "[") + (display assert-tag) + (display " - ") + (display count) + (display "]") + (display ": ") + (write (list 'check 'value-a 'value-b)) + (newline) + (when (not result) (exit 1)))))))) + +(define-syntax debug + (syntax-rules () + ((_ value) + (begin + (display 'value) + (display ": ") + (write value) + (newline))))) + +;; define-c-struct + + +(define-c-struct test '() '())