978 lines
47 KiB
Scheme
978 lines
47 KiB
Scheme
|
;;; Copyright 1984-2017 Cisco Systems, Inc.
|
||
|
;;;
|
||
|
;;; Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
;;; you may not use this file except in compliance with the License.
|
||
|
;;; You may obtain a copy of the License at
|
||
|
;;;
|
||
|
;;; http://www.apache.org/licenses/LICENSE-2.0
|
||
|
;;;
|
||
|
;;; Unless required by applicable law or agreed to in writing, software
|
||
|
;;; distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
;;; See the License for the specific language governing permissions and
|
||
|
;;; limitations under the License.
|
||
|
|
||
|
;;; cp0 is needed to optimize away run-time calls to record-constructor,
|
||
|
;;; record-predicate, etc., in define-record-type for rcd.
|
||
|
(eval-when (compile) (run-cp0 (default-run-cp0)))
|
||
|
|
||
|
;;; TODO:
|
||
|
;;; indirect flag for $record{,-ref,-set!}
|
||
|
;;; gc support for indirect records
|
||
|
;;; examples/foreign.ss support for (indirect) records
|
||
|
;;; support for more datatypes
|
||
|
;;; SWIG converter?
|
||
|
;;; include size of tag in record size OR don't include tag in record offsets
|
||
|
|
||
|
(let ()
|
||
|
(define (rtd-parent x) ($object-ref 'scheme-object x (constant record-type-parent-disp)))
|
||
|
(define (rtd-size x) ($object-ref 'scheme-object x (constant record-type-size-disp)))
|
||
|
(define (rtd-pm x) ($object-ref 'scheme-object x (constant record-type-pm-disp)))
|
||
|
(define (rtd-mpm x) ($object-ref 'scheme-object x (constant record-type-mpm-disp)))
|
||
|
(define (rtd-name x) ($object-ref 'scheme-object x (constant record-type-name-disp)))
|
||
|
(define (rtd-flds x) ($object-ref 'scheme-object x (constant record-type-flds-disp)))
|
||
|
(define (rtd-flags x) ($object-ref 'scheme-object x (constant record-type-flags-disp)))
|
||
|
(define (rtd-uid x) ($object-ref 'scheme-object x (constant record-type-uid-disp)))
|
||
|
|
||
|
(define (child-flds rtd)
|
||
|
(let ([flds (rtd-flds rtd)] [prtd (rtd-parent rtd)])
|
||
|
(if prtd
|
||
|
(list-tail flds (length (rtd-flds prtd)))
|
||
|
flds)))
|
||
|
|
||
|
; $record is hand-coded and is defined in prims.ss
|
||
|
|
||
|
(let ([addr? (constant-case ptr-bits
|
||
|
[(32) $integer-32?]
|
||
|
[(64) $integer-64?])])
|
||
|
(set-who! foreign-alloc
|
||
|
(let ([malloc (foreign-procedure "(cs)malloc" (fixnum) uptr)])
|
||
|
(lambda (n)
|
||
|
(unless (and (fixnum? n) (fx> n 0))
|
||
|
($oops who "~s is not a positive fixnum" n))
|
||
|
(malloc n))))
|
||
|
|
||
|
(set-who! foreign-free
|
||
|
(let ([free (foreign-procedure "(cs)free" (uptr) void)])
|
||
|
(lambda (addr)
|
||
|
(unless (addr? addr) ($oops who "invalid foreign address ~s" addr))
|
||
|
(free addr))))
|
||
|
|
||
|
(let ()
|
||
|
(define (check-args who ty addr offset)
|
||
|
(define-syntax check-ending-addr
|
||
|
(syntax-rules ()
|
||
|
[(_ type bytes pred)
|
||
|
(unless (addr? (+ addr offset (fx- bytes 1)))
|
||
|
($oops who "invalid effective address (+ ~s ~s) for ~s-byte type ~s" addr offset bytes 'type))]))
|
||
|
(unless (addr? addr) ($oops who "invalid address ~s" addr))
|
||
|
(unless (fixnum? offset) ($oops who "~s is not a fixnum" offset))
|
||
|
(unless (addr? (+ addr offset)) ($oops who "invalid effective address (+ ~s ~s)" addr offset))
|
||
|
(record-datatype cases (filter-foreign-type ty) check-ending-addr
|
||
|
($oops who "unrecognized type ~s" ty)))
|
||
|
(set-who! foreign-ref ; checks ty, addr, and offset, but inherently unsafe
|
||
|
(lambda (ty addr offset)
|
||
|
(define-syntax ref
|
||
|
(syntax-rules (scheme-object char wchar boolean integer-64 unsigned-64)
|
||
|
[(_ scheme-object bytes pred) ($oops who "cannot load scheme pointers from foreign memory")]
|
||
|
[(_ char bytes pred) (integer->char (#3%foreign-ref 'unsigned-8 addr offset))]
|
||
|
[(_ wchar bytes pred)
|
||
|
(constant-case wchar-bits
|
||
|
[(16) (integer->char (#3%foreign-ref 'unsigned-16 addr offset))]
|
||
|
[(32) (integer->char (#3%foreign-ref 'unsigned-32 addr offset))])]
|
||
|
[(_ boolean bytes pred)
|
||
|
(constant-case int-bits
|
||
|
[(32) (not (eq? (#3%foreign-ref 'integer-32 addr offset) 0))]
|
||
|
[(64) (not (eq? (#3%foreign-ref 'integer-64 addr offset) 0))])]
|
||
|
[(_ integer-64 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(logor (ash (#3%foreign-ref 'integer-32 addr offset) 32)
|
||
|
(#3%foreign-ref 'unsigned-32 (+ addr 4) offset))]
|
||
|
[(little)
|
||
|
(logor (ash (#3%foreign-ref 'integer-32 (+ addr 4) offset) 32)
|
||
|
(#3%foreign-ref 'unsigned-32 addr offset))])]
|
||
|
[(_ unsigned-64 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(logor (ash (#3%foreign-ref 'unsigned-32 addr offset) 32)
|
||
|
(#3%foreign-ref 'unsigned-32 (+ addr 4) offset))]
|
||
|
[(little)
|
||
|
(logor (ash (#3%foreign-ref 'unsigned-32 (+ addr 4) offset) 32)
|
||
|
(#3%foreign-ref 'unsigned-32 addr offset))])]
|
||
|
[(_ type bytes pred) (#3%foreign-ref 'type addr offset)]))
|
||
|
(check-args who ty addr offset)
|
||
|
(record-datatype cases (filter-foreign-type ty) ref
|
||
|
($oops who "unrecognized type ~s" ty))))
|
||
|
|
||
|
(set-who! foreign-set! ; checks ty, addr, offset, and v, but inherently unsafe
|
||
|
(lambda (ty addr offset v)
|
||
|
(define (value-err x t) ($oops who "invalid value ~s for foreign type ~s" x t))
|
||
|
(define-syntax set
|
||
|
(syntax-rules (scheme-object char wchar boolean integer-40 unsigned-40 integer-48 unsigned-48
|
||
|
integer-56 unsigned-56 integer-64 unsigned-64)
|
||
|
[(_ scheme-object bytes pred) ($oops who "cannot store scheme pointers into foreign memory")]
|
||
|
[(_ char bytes pred)
|
||
|
(begin
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(#3%foreign-set! 'unsigned-8 addr offset (char->integer v)))]
|
||
|
[(_ wchar bytes pred)
|
||
|
(begin
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(constant-case wchar-bits
|
||
|
[(16) (#3%foreign-set! 'unsigned-16 addr offset (char->integer v))]
|
||
|
[(32) (#3%foreign-set! 'unsigned-32 addr offset (char->integer v))]))]
|
||
|
[(_ boolean bytes pred)
|
||
|
(constant-case int-bits
|
||
|
[(32) (#3%foreign-set! 'integer-32 addr offset (if v 1 0))]
|
||
|
[(64) (#3%foreign-set! 'integer-64 addr offset (if v 1 0))])]
|
||
|
[(_ integer-40 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%foreign-set! 'integer-32 addr offset (bitwise-arithmetic-shift-right v 8))
|
||
|
(#3%foreign-set! 'unsigned-8 (+ addr 4) offset (logand v (- (expt 2 8) 1)))]
|
||
|
[(little)
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%foreign-set! 'integer-8 (+ addr 4) offset (bitwise-arithmetic-shift-right v 32))]))]
|
||
|
[(_ unsigned-40 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (bitwise-arithmetic-shift-right v 8))
|
||
|
(#3%foreign-set! 'unsigned-8 (+ addr 4) offset (logand v (- (expt 2 8) 1)))]
|
||
|
[(little)
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%foreign-set! 'unsigned-8 (+ addr 4) offset (bitwise-arithmetic-shift-right v 32))]))]
|
||
|
[(_ integer-48 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%foreign-set! 'integer-32 addr offset (bitwise-arithmetic-shift-right v 16))
|
||
|
(#3%foreign-set! 'unsigned-16 (+ addr 4) offset (logand v (- (expt 2 16) 1)))]
|
||
|
[(little)
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%foreign-set! 'integer-16 (+ addr 4) offset (bitwise-arithmetic-shift-right v 32))]))]
|
||
|
[(_ unsigned-48 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (bitwise-arithmetic-shift-right v 16))
|
||
|
(#3%foreign-set! 'unsigned-16 (+ addr 4) offset (logand v (- (expt 2 16) 1)))]
|
||
|
[(little)
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%foreign-set! 'unsigned-16 (+ addr 4) offset (bitwise-arithmetic-shift-right v 32))]))]
|
||
|
[(_ integer-56 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%foreign-set! 'integer-32 addr offset (bitwise-arithmetic-shift-right v 24))
|
||
|
(#3%foreign-set! 'unsigned-16 (+ addr 4) offset (logand (bitwise-arithmetic-shift-right v 8) (- (expt 2 16) 1)))
|
||
|
(#3%foreign-set! 'unsigned-8 (+ addr 6) offset (logand v (- (expt 2 8) 1)))]
|
||
|
[(little)
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%foreign-set! 'unsigned-16 (+ addr 4) offset (fxlogand (bitwise-arithmetic-shift-right v 32) (- (expt 2 16) 1)))
|
||
|
(#3%foreign-set! 'integer-8 (+ addr 6) offset (bitwise-arithmetic-shift-right v 48))]))]
|
||
|
[(_ unsigned-56 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (bitwise-arithmetic-shift-right v 24))
|
||
|
(#3%foreign-set! 'unsigned-16 (+ addr 4) offset (logand (bitwise-arithmetic-shift-right v 8) (- (expt 2 16) 1)))
|
||
|
(#3%foreign-set! 'unsigned-8 (+ addr 6) offset (logand v (- (expt 2 8) 1)))]
|
||
|
[(little)
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%foreign-set! 'unsigned-16 (+ addr 4) offset (fxlogand (bitwise-arithmetic-shift-right v 32) (- (expt 2 16) 1)))
|
||
|
(#3%foreign-set! 'unsigned-8 (+ addr 6) offset (bitwise-arithmetic-shift-right v 48))]))]
|
||
|
[(_ integer-64 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%foreign-set! 'integer-32 addr offset (ash v -32))
|
||
|
(#3%foreign-set! 'unsigned-32 (+ addr 4) offset (logand v (- (expt 2 32) 1)))]
|
||
|
[(little)
|
||
|
(#3%foreign-set! 'integer-32 (+ addr 4) offset (ash v -32))
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (logand v (- (expt 2 32) 1)))]))]
|
||
|
[(_ unsigned-64 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (ash v -32))
|
||
|
(#3%foreign-set! 'unsigned-32 (+ addr 4) offset (logand v (- (expt 2 32) 1)))]
|
||
|
[(little)
|
||
|
(#3%foreign-set! 'unsigned-32 (+ addr 4) offset (ash v -32))
|
||
|
(#3%foreign-set! 'unsigned-32 addr offset (logand v (- (expt 2 32) 1)))]))]
|
||
|
[(_ type bytes pred)
|
||
|
(begin
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(#3%foreign-set! 'type addr offset v))]))
|
||
|
(check-args who ty addr offset)
|
||
|
(record-datatype cases (filter-foreign-type ty) set
|
||
|
($oops who "unrecognized type ~s" ty))))))
|
||
|
|
||
|
(set-who! $filter-foreign-type
|
||
|
; version that filters using host-machine information
|
||
|
(lambda (ty)
|
||
|
(filter-foreign-type ty)))
|
||
|
|
||
|
(set-who! $object-ref ; not safe, just handles non-constant types
|
||
|
(lambda (ty r offset)
|
||
|
(define-syntax ref
|
||
|
(syntax-rules (char wchar boolean integer-64 unsigned-64)
|
||
|
[(_ char bytes pred) (integer->char (#3%$object-ref 'unsigned-8 r offset))]
|
||
|
[(_ wchar bytes pred)
|
||
|
(constant-case wchar-bits
|
||
|
[(16) (integer->char (#3%$object-ref 'unsigned-16 r offset))]
|
||
|
[(32) (integer->char (#3%$object-ref 'unsigned-32 r offset))])]
|
||
|
[(_ boolean bytes pred)
|
||
|
(constant-case int-bits
|
||
|
[(32) (not (eq? (#3%$object-ref 'integer-32 r offset) 0))]
|
||
|
[(64) (not (eq? (#3%$object-ref 'integer-64 r offset) 0))])]
|
||
|
[(_ type bytes pred) (#3%$object-ref 'type r offset)]))
|
||
|
(record-datatype cases (filter-foreign-type ty) ref
|
||
|
($oops who "unrecognized type ~s" ty))))
|
||
|
|
||
|
(set-who! $swap-object-ref ; not safe, just handles non-constant types
|
||
|
(lambda (ty r offset)
|
||
|
(define-syntax ref
|
||
|
(syntax-rules (char wchar boolean integer-64 unsigned-64)
|
||
|
[(_ char bytes pred) (integer->char (#3%$swap-object-ref 'unsigned-8 r offset))]
|
||
|
[(_ wchar bytes pred)
|
||
|
(constant-case wchar-bits
|
||
|
[(16) (integer->char (#3%$swap-object-ref 'unsigned-16 r offset))]
|
||
|
[(32) (integer->char (#3%$swap-object-ref 'unsigned-32 r offset))])]
|
||
|
[(_ boolean bytes pred)
|
||
|
(constant-case int-bits
|
||
|
[(32) (not (eq? (#3%$swap-object-ref 'integer-32 r offset) 0))]
|
||
|
[(64) (not (eq? (#3%$swap-object-ref 'integer-64 r offset) 0))])]
|
||
|
[(_ type bytes pred) (#3%$swap-object-ref 'type r offset)]))
|
||
|
(record-datatype cases (filter-foreign-type ty) ref
|
||
|
($oops who "unrecognized type ~s" ty))))
|
||
|
|
||
|
(set-who! $object-set! ; not safe, just handles non-constant types
|
||
|
(lambda (ty r offset v)
|
||
|
(define-syntax set
|
||
|
(syntax-rules (char wchar boolean integer-40 unsigned-40 integer-48 unsigned-48
|
||
|
integer-56 unsigned-56 integer-64 unsigned-64)
|
||
|
[(_ char bytes pred)
|
||
|
(#3%$object-set! 'unsigned-8 r offset (char->integer v))]
|
||
|
[(_ wchar bytes pred)
|
||
|
(constant-case wchar-bits
|
||
|
[(16) (#3%$object-set! 'unsigned-16 r offset (char->integer v))]
|
||
|
[(32) (#3%$object-set! 'unsigned-32 r offset (char->integer v))])]
|
||
|
[(_ boolean bytes pred)
|
||
|
(constant-case int-bits
|
||
|
[(32) (#3%$object-set! 'integer-32 r offset (if v 1 0))]
|
||
|
[(64) (#3%$object-set! 'integer-64 r offset (if v 1 0))])]
|
||
|
[(_ integer-40 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%$object-set! 'integer-32 r offset (bitwise-arithmetic-shift-right v 8))
|
||
|
(#3%$object-set! 'unsigned-8 r (fx+ offset 4) (logand v (- (expt 2 8) 1)))]
|
||
|
[(little)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%$object-set! 'integer-8 r (fx+ offset 4) (bitwise-arithmetic-shift-right v 32))]))]
|
||
|
[(_ unsigned-40 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (bitwise-arithmetic-shift-right v 8))
|
||
|
(#3%$object-set! 'unsigned-8 r (fx+ offset 4) (logand v (- (expt 2 8) 1)))]
|
||
|
[(little)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%$object-set! 'unsigned-8 r (fx+ offset 4) (bitwise-arithmetic-shift-right v 32))]))]
|
||
|
[(_ integer-48 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%$object-set! 'integer-32 r offset (bitwise-arithmetic-shift-right v 16))
|
||
|
(#3%$object-set! 'unsigned-16 r (fx+ offset 4) (logand v (- (expt 2 16) 1)))]
|
||
|
[(little)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%$object-set! 'integer-16 r (fx+ offset 4) (bitwise-arithmetic-shift-right v 32))]))]
|
||
|
[(_ unsigned-48 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (bitwise-arithmetic-shift-right v 16))
|
||
|
(#3%$object-set! 'unsigned-16 r (fx+ offset 4) (logand v (- (expt 2 16) 1)))]
|
||
|
[(little)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%$object-set! 'unsigned-16 r (fx+ offset 4) (bitwise-arithmetic-shift-right v 32))]))]
|
||
|
[(_ integer-56 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%$object-set! 'integer-32 r offset (bitwise-arithmetic-shift-right v 24))
|
||
|
(#3%$object-set! 'unsigned-16 r (fx+ offset 4) (logand (bitwise-arithmetic-shift-right v 8) (- (expt 2 16) 1)))
|
||
|
(#3%$object-set! 'unsigned-8 r (fx+ offset 6) (logand v (- (expt 2 8) 1)))]
|
||
|
[(little)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%$object-set! 'unsigned-16 r (fx+ offset 4) (fxlogand (bitwise-arithmetic-shift-right v 32) (- (expt 2 16) 1)))
|
||
|
(#3%$object-set! 'integer-8 r (fx+ offset 6) (bitwise-arithmetic-shift-right v 48))]))]
|
||
|
[(_ unsigned-56 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(begin
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (bitwise-arithmetic-shift-right v 24))
|
||
|
(#3%$object-set! 'unsigned-16 r (fx+ offset 4) (logand (bitwise-arithmetic-shift-right v 8) (- (expt 2 16) 1)))
|
||
|
(#3%$object-set! 'unsigned-8 r (fx+ offset 6) (logand v (- (expt 2 8) 1)))]
|
||
|
[(little)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%$object-set! 'unsigned-16 r (fx+ offset 4) (fxlogand (bitwise-arithmetic-shift-right v 32) (- (expt 2 16) 1)))
|
||
|
(#3%$object-set! 'unsigned-8 r (fx+ offset 6) (bitwise-arithmetic-shift-right v 48))]))]
|
||
|
[(_ integer-64 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%$object-set! 'integer-32 r offset (bitwise-arithmetic-shift-right v 32))
|
||
|
(#3%$object-set! 'unsigned-32 r (fx+ offset 4) (logand v (- (expt 2 32) 1)))]
|
||
|
[(little)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%$object-set! 'integer-32 r (fx+ offset 4) (bitwise-arithmetic-shift-right v 32))])]
|
||
|
[(_ unsigned-64 bytes pred)
|
||
|
(< (constant ptr-bits) 64)
|
||
|
(constant-case native-endianness
|
||
|
[(big)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (bitwise-arithmetic-shift-right v 32))
|
||
|
(#3%$object-set! 'unsigned-32 r (fx+ offset 4) (logand v (- (expt 2 32) 1)))]
|
||
|
[(little)
|
||
|
(#3%$object-set! 'unsigned-32 r offset (logand v (- (expt 2 32) 1)))
|
||
|
(#3%$object-set! 'unsigned-32 r (fx+ offset 4) (bitwise-arithmetic-shift-right v 32))])]
|
||
|
[(_ type bytes pred) (#3%$object-set! 'type r offset v)]))
|
||
|
(record-datatype cases (filter-foreign-type ty) set
|
||
|
($oops who "unrecognized type ~s" ty))))
|
||
|
|
||
|
(set-who! foreign-sizeof
|
||
|
(lambda (ty)
|
||
|
(define-syntax size
|
||
|
(syntax-rules ()
|
||
|
[(_ type bytes pred) bytes]))
|
||
|
(record-datatype cases (filter-foreign-type ty) size
|
||
|
($oops who "invalid foreign type specifier ~s" ty))))
|
||
|
|
||
|
(set-who! #(csv7: record-type-descriptor)
|
||
|
(lambda (r)
|
||
|
(unless (record? r) ($oops who "~s is not a record" r))
|
||
|
(#3%record-rtd r)))
|
||
|
|
||
|
(set-who! record-rtd
|
||
|
(lambda (r)
|
||
|
(unless (record? r) ($oops who "~s is not a record" r))
|
||
|
(#3%record-rtd r)))
|
||
|
|
||
|
(set! record-predicate
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops 'record-predicate "~s is not a record type descriptor" rtd))
|
||
|
(if (record-type-sealed? rtd)
|
||
|
(rec predicate (lambda (x) ($sealed-record? x rtd)))
|
||
|
(rec predicate (lambda (x) (record? x rtd))))))
|
||
|
|
||
|
(let ((base-rtd #!base-rtd))
|
||
|
(define (make-flags uid sealed? opaque? parent)
|
||
|
(fxlogor
|
||
|
(if uid 0 (constant rtd-generative))
|
||
|
(if (or opaque? (and parent (record-type-opaque? parent)))
|
||
|
(constant rtd-opaque)
|
||
|
0)
|
||
|
(if sealed? (constant rtd-sealed) 0)))
|
||
|
(define ($mrt who base-rtd name parent uid flags fields extras)
|
||
|
(include "layout.ss")
|
||
|
(when (and parent (record-type-sealed? parent))
|
||
|
($oops who "cannot extend sealed record type ~s" parent))
|
||
|
(let ([parent-fields (if (not parent) '() (csv7:record-type-field-decls parent))]
|
||
|
[uid (or uid (gensym (symbol->string name)))])
|
||
|
; start base offset at rtd field
|
||
|
; synchronize with syntax.ss and front.ss
|
||
|
(let-values ([(pm mpm flds size)
|
||
|
(compute-field-offsets who
|
||
|
(constant record-type-disp)
|
||
|
; rtd must be immutable if we are ever to store records
|
||
|
; in space pure
|
||
|
(cons `(immutable scheme-object ,uid)
|
||
|
(append parent-fields fields)))])
|
||
|
(cond
|
||
|
[(and (not (fxlogtest flags (constant rtd-generative)))
|
||
|
(let ([x ($sgetprop uid '*rtd* #f)])
|
||
|
(and (record-type-descriptor? x) x))) =>
|
||
|
(lambda (rtd)
|
||
|
(define same-fields?
|
||
|
(lambda (flds1 flds2)
|
||
|
(define same-field?
|
||
|
(lambda (fld1 fld2) ; mutability checked separately
|
||
|
(and (eq? (fld-name fld1) (fld-name fld2))
|
||
|
; not using filter-foreign-type here. this makes the
|
||
|
; comparison faster and prevents unwanted machine-dependent
|
||
|
; matches like int and integer-32. it also prevents
|
||
|
; ptr and scheme-object from matching---c'est la vie.
|
||
|
(eq? (fld-type fld1) (fld-type fld2))
|
||
|
; following is paranoid; overall size
|
||
|
; check should suffice
|
||
|
#;(= (fld-byte fld1) (fld-byte fld2)))))
|
||
|
(and (= (length flds1) (length flds2))
|
||
|
(andmap same-field? flds1 flds2))))
|
||
|
; following assumes extras match
|
||
|
(let ()
|
||
|
(define (squawk what) ($oops who "incompatible record type ~s - ~a" name what))
|
||
|
(unless (eq? ($record-type-descriptor rtd) base-rtd) (squawk "different base rtd"))
|
||
|
(unless (eq? (rtd-parent rtd) parent) (squawk "different parent"))
|
||
|
(unless (same-fields? (rtd-flds rtd) (cdr flds)) (squawk "different fields"))
|
||
|
(unless (= (rtd-mpm rtd) mpm) (squawk "different mutability"))
|
||
|
(unless (fx= (rtd-flags rtd) flags) (squawk "different flags"))
|
||
|
(unless (eq? (rtd-size rtd) size) (squawk "different size")))
|
||
|
rtd)]
|
||
|
[else
|
||
|
(let ([rtd (apply #%$record base-rtd parent size pm mpm name
|
||
|
(cdr flds) flags uid #f extras)])
|
||
|
(with-tc-mutex ($sputprop uid '*rtd* rtd))
|
||
|
rtd)]))))
|
||
|
|
||
|
(set-who! $remake-rtd
|
||
|
(lambda (rtd compute-field-offsets)
|
||
|
(let ([key ($target-machine)] [uid (rtd-uid rtd)])
|
||
|
(assert (not (eq? key (machine-type))))
|
||
|
(or ($sgetprop uid key #f)
|
||
|
(let ([base-rtd ($record-type-descriptor rtd)]
|
||
|
[parent (rtd-parent rtd)]
|
||
|
[name (rtd-name rtd)]
|
||
|
[flags (rtd-flags rtd)]
|
||
|
[fields (csv7:record-type-field-decls rtd)])
|
||
|
(let-values ([(pm mpm flds size)
|
||
|
(compute-field-offsets who
|
||
|
(constant record-type-disp)
|
||
|
(cons `(immutable scheme-object ,uid) fields))])
|
||
|
(let ([rtd (apply #%$record base-rtd parent size pm mpm name (cdr flds) flags uid #f
|
||
|
(let* ([n (length (rtd-flds ($record-type-descriptor base-rtd)))]
|
||
|
[ls (list-tail (rtd-flds base-rtd) n)])
|
||
|
(let f ([n n] [ls ls])
|
||
|
(if (null? ls)
|
||
|
'()
|
||
|
(cons ((csv7:record-field-accessor base-rtd n) rtd)
|
||
|
(f (fx+ n 1) (cdr ls)))))))])
|
||
|
(with-tc-mutex ($sputprop uid key rtd))
|
||
|
rtd)))))))
|
||
|
|
||
|
(let ()
|
||
|
(define (mrt base-rtd parent name fields sealed? opaque? extras)
|
||
|
(cond
|
||
|
[(gensym? name)
|
||
|
($mrt 'make-record-type base-rtd
|
||
|
(string->symbol (symbol->string name)) parent name
|
||
|
(make-flags name sealed? opaque? parent)
|
||
|
fields extras)]
|
||
|
[(string? name)
|
||
|
($mrt 'make-record-type base-rtd
|
||
|
(string->symbol name) parent #f
|
||
|
(make-flags #f sealed? opaque? parent)
|
||
|
fields extras)]
|
||
|
[else ($oops 'make-record-type "invalid record name ~s" name)]))
|
||
|
|
||
|
(set-who! make-record-type
|
||
|
(rec make-record-type
|
||
|
(case-lambda
|
||
|
[(name fields)
|
||
|
(unless (list? fields)
|
||
|
($oops who "invalid field list ~s" fields))
|
||
|
(mrt base-rtd #f name fields #f #f '())]
|
||
|
[(parent name fields)
|
||
|
(unless (or (not parent) (record-type-descriptor? parent))
|
||
|
($oops who "~s is not a record type descriptor"
|
||
|
parent))
|
||
|
(unless (list? fields)
|
||
|
($oops who "invalid field list ~s" fields))
|
||
|
(mrt base-rtd parent name fields #f #f '())])))
|
||
|
|
||
|
(set! $make-record-type
|
||
|
(lambda (base-rtd parent name fields sealed? opaque? . extras)
|
||
|
(unless (record-type-descriptor? base-rtd)
|
||
|
($oops 'make-record-type "~s is not a record type descriptor"
|
||
|
base-rtd))
|
||
|
(unless (or (not parent) (record-type-descriptor? parent))
|
||
|
($oops 'make-record-type "~s is not a record type descriptor"
|
||
|
parent))
|
||
|
(unless (list? fields)
|
||
|
($oops 'make-record-type "invalid field list ~s" fields))
|
||
|
(mrt base-rtd parent name fields sealed? opaque? extras))))
|
||
|
|
||
|
(let ()
|
||
|
(define (mrtd base-rtd name parent uid sealed? opaque? fields who extras)
|
||
|
(unless (symbol? name)
|
||
|
($oops who "invalid record name ~s" name))
|
||
|
(unless (or (not parent) (record-type-descriptor? parent))
|
||
|
($oops who "invalid parent ~s" parent))
|
||
|
(unless (or (not uid) (symbol? uid))
|
||
|
($oops who "invalid uid ~s" uid))
|
||
|
(unless (vector? fields)
|
||
|
($oops who "invalid field vector ~s" fields))
|
||
|
($mrt who base-rtd name parent uid
|
||
|
(make-flags uid sealed? opaque? parent)
|
||
|
(let ([n (vector-length fields)])
|
||
|
(let f ([i 0])
|
||
|
(if (fx= i n)
|
||
|
'()
|
||
|
(let ([x (vector-ref fields i)])
|
||
|
(unless (and (pair? x)
|
||
|
(memq (car x) '(mutable immutable))
|
||
|
(let ([x (cdr x)])
|
||
|
(and (pair? x)
|
||
|
(symbol? (car x))
|
||
|
(null? (cdr x)))))
|
||
|
($oops who "invalid field specifier ~s" x))
|
||
|
(cons x (f (fx+ i 1)))))))
|
||
|
extras))
|
||
|
|
||
|
(set! $make-record-type-descriptor
|
||
|
(lambda (base-rtd name parent uid sealed? opaque? fields who . extras)
|
||
|
(unless (record-type-descriptor? base-rtd)
|
||
|
($oops who "invalid base rtd ~s" base-rtd))
|
||
|
(mrtd base-rtd name parent uid sealed? opaque? fields who extras)))
|
||
|
|
||
|
(set-who! make-record-type-descriptor
|
||
|
(lambda (name parent uid sealed? opaque? fields)
|
||
|
(mrtd base-rtd name parent uid sealed? opaque? fields who '()))))
|
||
|
|
||
|
(set! record-type-descriptor?
|
||
|
(lambda (x)
|
||
|
(#3%record? x base-rtd)))
|
||
|
|
||
|
(set! record?
|
||
|
(case-lambda
|
||
|
[(x) (#3%record? x)]
|
||
|
[(x rtd)
|
||
|
(unless (#3%record? rtd base-rtd)
|
||
|
($oops 'record? "~s is not a record type descriptor" rtd))
|
||
|
(#3%record? x rtd)])))
|
||
|
|
||
|
(set! r6rs:record?
|
||
|
(rec record?
|
||
|
(lambda (x)
|
||
|
(#3%r6rs:record? x))))
|
||
|
|
||
|
(set! record-type-parent
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops 'record-type-parent "~s is not a record type descriptor" rtd))
|
||
|
(rtd-parent rtd)))
|
||
|
|
||
|
(set-who! #(csv7: record-type-name)
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops who "~s is not a record type descriptor" rtd))
|
||
|
(symbol->string (rtd-name rtd))))
|
||
|
|
||
|
(set-who! record-type-name
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops who "~s is not a record type descriptor" rtd))
|
||
|
(rtd-name rtd)))
|
||
|
|
||
|
(set-who! #(csv7: record-type-symbol)
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops who "~s is not a record type descriptor" rtd))
|
||
|
(rtd-uid rtd)))
|
||
|
|
||
|
(set-who! record-type-uid
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops who "~s is not a record type descriptor" rtd))
|
||
|
(rtd-uid rtd)))
|
||
|
|
||
|
(set-who! #(csv7: record-type-field-names)
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops who "~s is not a record type descriptor" rtd))
|
||
|
(map (lambda (x) (fld-name x)) (rtd-flds rtd))))
|
||
|
|
||
|
(set-who! record-type-field-names
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops who "~s is not a record type descriptor" rtd))
|
||
|
(list->vector (map (lambda (x) (fld-name x)) (child-flds rtd)))))
|
||
|
|
||
|
(set-who! #(csv7: record-type-field-decls)
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops who "~s is not a record type descriptor" rtd))
|
||
|
(map (lambda (x)
|
||
|
`(,(if (fld-mutable? x) 'mutable 'immutable)
|
||
|
,(fld-type x)
|
||
|
,(fld-name x)))
|
||
|
(rtd-flds rtd))))
|
||
|
|
||
|
(set! $record-type-field-offsets
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops '$record-type-field-offsets "~s is not a record type descriptor" rtd))
|
||
|
(map (lambda (x) (fld-byte x)) (rtd-flds rtd))))
|
||
|
|
||
|
(set! record-type-opaque?
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops 'record-type-opaque? "~s is not a record type descriptor" rtd))
|
||
|
(#3%record-type-opaque? rtd)))
|
||
|
|
||
|
(set! record-type-sealed?
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops 'record-type-sealed? "~s is not a record type descriptor" rtd))
|
||
|
(#3%record-type-sealed? rtd)))
|
||
|
|
||
|
(set! record-type-generative?
|
||
|
(lambda (rtd)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops 'record-type-generative? "~s is not a record type descriptor" rtd))
|
||
|
(#3%record-type-generative? rtd)))
|
||
|
|
||
|
(let ()
|
||
|
(define (find-fld who rtd field-spec)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops who "~s is not a record type descriptor" rtd))
|
||
|
(cond
|
||
|
[(symbol? field-spec)
|
||
|
; reverse order to check child's fields first
|
||
|
(let loop ((flds (reverse (rtd-flds rtd))))
|
||
|
(when (null? flds)
|
||
|
($oops who "unrecognized field name ~s for type ~s"
|
||
|
field-spec rtd))
|
||
|
(let ((fld (car flds)))
|
||
|
(if (eq? field-spec (fld-name fld))
|
||
|
fld
|
||
|
(loop (cdr flds)))))]
|
||
|
[(and (fixnum? field-spec) (fx>= field-spec 0))
|
||
|
(let ((flds (rtd-flds rtd)))
|
||
|
(when (fx>= field-spec (length flds))
|
||
|
($oops who "invalid field ordinal ~s for type ~s"
|
||
|
field-spec rtd))
|
||
|
(list-ref flds field-spec))]
|
||
|
[else ($oops who "invalid field specifier ~s" field-spec)]))
|
||
|
|
||
|
(define (r6rs:find-fld who rtd field-spec)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops who "~s is not a record type descriptor" rtd))
|
||
|
(cond
|
||
|
[(and (fixnum? field-spec) (fx>= field-spec 0))
|
||
|
(let ((flds (child-flds rtd)))
|
||
|
(when (fx>= field-spec (length flds))
|
||
|
($oops who "invalid field index ~s for type ~s"
|
||
|
field-spec rtd))
|
||
|
(list-ref flds field-spec))]
|
||
|
[else ($oops who "invalid field specifier ~s" field-spec)]))
|
||
|
|
||
|
(let ()
|
||
|
(define (rfa who rtd fld)
|
||
|
(let ((record-err (lambda (x) ($record-oops #f x rtd)))
|
||
|
(offset (fld-byte fld))
|
||
|
(ty (fld-type fld)))
|
||
|
(define-syntax ref
|
||
|
(syntax-rules ()
|
||
|
[(_ type bytes pred)
|
||
|
(rec accessor
|
||
|
(lambda (x)
|
||
|
(unless (record? x rtd) (record-err x))
|
||
|
(#3%$object-ref 'type x offset)))]))
|
||
|
(record-datatype cases (filter-foreign-type ty) ref
|
||
|
($oops who "unrecognized type ~s" ty))))
|
||
|
(set-who! #(csv7: record-field-accessor)
|
||
|
(lambda (rtd field-spec)
|
||
|
(rfa who rtd (find-fld who rtd field-spec))))
|
||
|
(set-who! record-accessor
|
||
|
(lambda (rtd field-spec)
|
||
|
(rfa who rtd (r6rs:find-fld who rtd field-spec)))))
|
||
|
|
||
|
(let ()
|
||
|
(define (rfm who rtd fld field-spec)
|
||
|
(if (fld-mutable? fld)
|
||
|
(let ((record-err (lambda (x t) ($record-oops #f x t)))
|
||
|
(value-err (lambda (x t) ($oops #f "invalid value ~s for foreign type ~s" x t)))
|
||
|
(offset (fld-byte fld))
|
||
|
(ty (fld-type fld)))
|
||
|
(define-syntax set
|
||
|
(syntax-rules (scheme-object)
|
||
|
[(_ scheme-object bytes pred)
|
||
|
(rec mutator
|
||
|
(lambda (x v)
|
||
|
(unless (record? x rtd) (record-err x rtd))
|
||
|
(#3%$object-set! 'scheme-object x offset v)))]
|
||
|
[(_ type bytes pred)
|
||
|
(rec mutator
|
||
|
(lambda (x v)
|
||
|
(unless (record? x rtd) (record-err x rtd))
|
||
|
(unless (pred v) (value-err v ty))
|
||
|
(#3%$object-set! 'type x offset v)))]))
|
||
|
(record-datatype cases (filter-foreign-type ty) set
|
||
|
($oops who "unrecognized type ~s" ty)))
|
||
|
($oops who "field ~s of ~s is immutable"
|
||
|
field-spec rtd)))
|
||
|
(set-who! #(csv7: record-field-mutator)
|
||
|
(lambda (rtd field-spec)
|
||
|
(rfm who rtd (find-fld who rtd field-spec) field-spec)))
|
||
|
(set-who! record-mutator
|
||
|
(lambda (rtd field-spec)
|
||
|
(rfm who rtd (r6rs:find-fld who rtd field-spec) field-spec))))
|
||
|
|
||
|
(set-who! #(csv7: record-field-accessible?)
|
||
|
; if this is ever made to do anything reasonable, revisit handlers in
|
||
|
; cp0 and cp1in as well
|
||
|
(lambda (rtd field-spec)
|
||
|
(find-fld who rtd field-spec)
|
||
|
#t))
|
||
|
|
||
|
(set-who! #(csv7: record-field-mutable?)
|
||
|
(lambda (rtd field-spec)
|
||
|
(fld-mutable? (find-fld who rtd field-spec))))
|
||
|
|
||
|
(set-who! record-field-mutable?
|
||
|
(lambda (rtd field-spec)
|
||
|
(fld-mutable? (r6rs:find-fld who rtd field-spec)))))
|
||
|
|
||
|
(let ()
|
||
|
; if you update this, also update duplicate in cp0.ss
|
||
|
(define-record-type rcd
|
||
|
(fields (immutable rtd) (immutable prcd) (immutable protocol))
|
||
|
(nongenerative #{rcd qh0yzh5qyrxmz2l-a})
|
||
|
(sealed #t))
|
||
|
|
||
|
(set! record-constructor-descriptor?
|
||
|
(lambda (x)
|
||
|
(rcd? x)))
|
||
|
|
||
|
(let ()
|
||
|
(define (mrcd rtd prcd protocol who)
|
||
|
(unless (record-type-descriptor? rtd)
|
||
|
($oops who "~s is not a record-type descriptor" rtd))
|
||
|
(unless (or (not prcd) (rcd? prcd))
|
||
|
($oops who "invalid record constructor descriptor ~s" prcd))
|
||
|
(unless (or (not protocol) (procedure? protocol))
|
||
|
($oops who "invalid protocol ~s" protocol))
|
||
|
(unless (eqv? (rtd-pm rtd) -1) ; all pointers?
|
||
|
($oops who "cannot create constructor descriptor for record type with non-scheme-object fields"))
|
||
|
(let ([prtd (record-type-parent rtd)])
|
||
|
(when (and prcd (not prtd))
|
||
|
($oops who
|
||
|
"record constructor descriptor ~s specified for base record type ~s"
|
||
|
prcd rtd))
|
||
|
(when (and prcd prtd (not (eq? (rcd-rtd prcd) prtd)))
|
||
|
($oops who
|
||
|
"record constructor descriptor ~s is not for parent of record type ~s"
|
||
|
prcd rtd))
|
||
|
(when (and (not protocol) prcd (rcd-protocol prcd))
|
||
|
($oops who "no protocol specified, but parent ~s has protocol" prcd))
|
||
|
(make-rcd rtd prcd protocol)))
|
||
|
|
||
|
(set! $make-record-constructor-descriptor
|
||
|
(lambda (rtd prcd protocol who)
|
||
|
(mrcd rtd prcd protocol who)))
|
||
|
|
||
|
(set! make-record-constructor-descriptor
|
||
|
(lambda (rtd prcd protocol)
|
||
|
(mrcd rtd prcd protocol 'make-record-constructor-descriptor))))
|
||
|
|
||
|
(let ()
|
||
|
(define $rtd->record-constructor
|
||
|
(lambda (rtd)
|
||
|
(define type->pred
|
||
|
(lambda (ty)
|
||
|
(define-syntax ->pred
|
||
|
(syntax-rules () ((_ type bytes pred) 'pred)))
|
||
|
(record-datatype cases ty ->pred
|
||
|
($oops 'record-constructor "unrecognized type ~s" ty))))
|
||
|
(let* ((flds (rtd-flds rtd)) (nflds (length flds)))
|
||
|
(if (eqv? (rtd-pm rtd) -1) ; all pointers?
|
||
|
(let ()
|
||
|
(define-syntax nlambda
|
||
|
(lambda (x)
|
||
|
(syntax-case x ()
|
||
|
[(_ n)
|
||
|
(with-syntax (((t ...)
|
||
|
(generate-temporaries
|
||
|
(make-list
|
||
|
(datum n)))))
|
||
|
#'(rec constructor
|
||
|
(lambda (t ...) ($record rtd t ...))))])))
|
||
|
(case nflds
|
||
|
[(0) (nlambda 0)]
|
||
|
[(1) (nlambda 1)]
|
||
|
[(2) (nlambda 2)]
|
||
|
[(3) (nlambda 3)]
|
||
|
[(4) (nlambda 4)]
|
||
|
[(5) (nlambda 5)]
|
||
|
[(6) (nlambda 6)]
|
||
|
[else (rec constructor
|
||
|
(lambda xr
|
||
|
(unless (fx= (length xr) nflds)
|
||
|
($oops #f "incorrect number of arguments to ~s" constructor))
|
||
|
(apply $record rtd xr)))]))
|
||
|
(let* ([args (make-record-call-args flds (rtd-size rtd)
|
||
|
(map (lambda (x) 0) flds))]
|
||
|
[nargs (length args)]
|
||
|
[setters (map (lambda (fld)
|
||
|
(let ([byte (fld-byte fld)]
|
||
|
[ty (fld-type fld)])
|
||
|
(let ([msg (format "invalid value ~~s for foreign type ~s" ty)])
|
||
|
(define-syntax init
|
||
|
(syntax-rules (scheme-object)
|
||
|
[(_ scheme-object bytes pred)
|
||
|
(lambda (x v)
|
||
|
(#3%$object-set! 'scheme-object x byte v))]
|
||
|
[(_ type bytes pred)
|
||
|
(lambda (x v)
|
||
|
(unless (pred v) ($oops #f msg v))
|
||
|
(#3%$object-set! 'type x byte v))]))
|
||
|
(record-datatype cases (filter-foreign-type ty) init
|
||
|
($oops 'record-constructor "unrecognized type ~s" ty)))))
|
||
|
flds)])
|
||
|
(define-syntax nmlambda
|
||
|
(lambda (x)
|
||
|
(syntax-case x ()
|
||
|
[(_ n m)
|
||
|
(with-syntax ([(t ...) (generate-temporaries
|
||
|
(make-list (datum n)))]
|
||
|
[(z ...) (make-list (datum m) 0)])
|
||
|
(with-syntax ([(t! ...) (generate-temporaries #'(t ...))])
|
||
|
#'(apply
|
||
|
(lambda (t! ...)
|
||
|
(rec constructor
|
||
|
(lambda (t ...)
|
||
|
(let ([x ($record rtd z ...)])
|
||
|
(t! x t) ...
|
||
|
x))))
|
||
|
setters)))])))
|
||
|
(or (constant-case ptr-bits
|
||
|
[(64)
|
||
|
(case nflds
|
||
|
[(0) (and (= nargs 0) (nmlambda 0 0))]
|
||
|
[(1) (and (= nargs 1) (nmlambda 1 1))]
|
||
|
[(2) (case nargs
|
||
|
[(1) (nmlambda 2 1)]
|
||
|
[(2) (nmlambda 2 2)]
|
||
|
[else #f])]
|
||
|
[(3) (case nargs
|
||
|
[(1) (nmlambda 3 1)]
|
||
|
[(2) (nmlambda 3 2)]
|
||
|
[(3) (nmlambda 3 3)]
|
||
|
[else #f])]
|
||
|
[(4) (case nargs
|
||
|
[(1) (nmlambda 4 1)]
|
||
|
[(2) (nmlambda 4 2)]
|
||
|
[(3) (nmlambda 4 3)]
|
||
|
[(4) (nmlambda 4 4)]
|
||
|
[else #f])]
|
||
|
[else #f])]
|
||
|
[(32)
|
||
|
(case nflds
|
||
|
[(0) (nmlambda 0 0)]
|
||
|
[(1) (case nargs
|
||
|
[(1) (nmlambda 1 1)]
|
||
|
[(2) (nmlambda 1 2)]
|
||
|
[(3) (nmlambda 1 3)]
|
||
|
[else #f])]
|
||
|
[(2) (case nargs
|
||
|
[(1) (nmlambda 2 1)]
|
||
|
[(2) (nmlambda 2 2)]
|
||
|
[(3) (nmlambda 2 3)]
|
||
|
[(4) (nmlambda 2 4)]
|
||
|
[(5) (nmlambda 2 5)]
|
||
|
[else #f])]
|
||
|
[(3) (case nargs
|
||
|
[(1) (nmlambda 3 1)]
|
||
|
[(2) (nmlambda 3 2)]
|
||
|
[(3) (nmlambda 3 3)]
|
||
|
[(4) (nmlambda 3 4)]
|
||
|
[(5) (nmlambda 3 5)]
|
||
|
[(6) (nmlambda 3 6)]
|
||
|
[(7) (nmlambda 3 7)]
|
||
|
[else #f])]
|
||
|
[(4) (case nargs
|
||
|
[(1) (nmlambda 4 1)]
|
||
|
[(2) (nmlambda 4 2)]
|
||
|
[(3) (nmlambda 4 3)]
|
||
|
[(4) (nmlambda 4 4)]
|
||
|
[(5) (nmlambda 4 5)]
|
||
|
[(6) (nmlambda 4 6)]
|
||
|
[(7) (nmlambda 4 7)]
|
||
|
[(8) (nmlambda 4 8)]
|
||
|
[(9) (nmlambda 4 9)]
|
||
|
[else #f])]
|
||
|
[else #f])])
|
||
|
(rec constructor
|
||
|
(lambda xr
|
||
|
(unless (fx= (length xr) nflds)
|
||
|
($oops #f "incorrect number of arguments to ~s" constructor))
|
||
|
(let ([x (apply $record rtd args)])
|
||
|
(for-each (lambda (setter v) (setter x v)) setters xr)
|
||
|
x)))))))))
|
||
|
|
||
|
(define ($rcd->record-constructor rcd)
|
||
|
(let ([rtd (rcd-rtd rcd)] [protocol (rcd-protocol rcd)])
|
||
|
(let ([rc ($rtd->record-constructor rtd)])
|
||
|
(if protocol
|
||
|
(protocol
|
||
|
(cond
|
||
|
[(rtd-parent rtd) =>
|
||
|
(lambda (prtd)
|
||
|
(lambda pp-args
|
||
|
(lambda vals
|
||
|
(let f ([prcd (rcd-prcd rcd)] [prtd prtd] [pp-args pp-args] [vals vals])
|
||
|
(#2%apply
|
||
|
(cond
|
||
|
[(and prcd (rcd-protocol prcd)) =>
|
||
|
(lambda (protocol)
|
||
|
(protocol
|
||
|
(cond
|
||
|
[(rtd-parent prtd) =>
|
||
|
(lambda (prtd)
|
||
|
(lambda pp-args
|
||
|
(lambda new-vals
|
||
|
(f (rcd-prcd prcd) prtd pp-args
|
||
|
(append new-vals vals)))))]
|
||
|
[else
|
||
|
(lambda new-vals
|
||
|
(apply rc (append new-vals vals)))])))]
|
||
|
[else
|
||
|
(lambda new-vals
|
||
|
(apply rc (append new-vals vals)))])
|
||
|
pp-args)))))]
|
||
|
[else rc]))
|
||
|
rc))))
|
||
|
|
||
|
(set! record-constructor
|
||
|
(lambda (x)
|
||
|
(cond
|
||
|
[(record-type-descriptor? x) ($rtd->record-constructor x)]
|
||
|
[(record-constructor-descriptor? x) ($rcd->record-constructor x)]
|
||
|
[else ($oops 'record-constructor "~s is not a record type or constructor descriptor" x)])))
|
||
|
|
||
|
(set-who! #(r6rs: record-constructor)
|
||
|
(lambda (rcd)
|
||
|
(unless (rcd? rcd)
|
||
|
($oops who "~s is not a record constructor descriptor" rcd))
|
||
|
($rcd->record-constructor rcd)))))
|
||
|
)
|