guile-srfi-123

guile-srfi-123 is an SRFI-123 implementation for Guile. (More on SRFI-123 on https://srfi.schemers.org/srfi-123/)
git clone https://kaka.farm/~git/guile-srfi-123
Log | Files | Refs

srfi-123.scm (9578B)


      1 ;;; generic-ref-set --- Generic accessor and modifier operators.
      2 
      3 ;; Copyright © 2015  Taylan Ulrich Bayırlı/Kammer <taylanbayirli@gmail.com>
      4 
      5 ;; Permission is hereby granted, free of charge, to any person obtaining
      6 ;; a copy of this software and associated documentation files (the
      7 ;; "Software"), to deal in the Software without restriction, including
      8 ;; without limitation the rights to use, copy, modify, merge, publish,
      9 ;; distribute, sublicense, and/or sell copies of the Software, and to
     10 ;; permit persons to whom the Software is furnished to do so, subject to
     11 ;; the following conditions:
     12 
     13 ;; The above copyright notice and this permission notice shall be
     14 ;; included in all copies or substantial portions of the Software.
     15 
     16 ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     17 ;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18 ;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     19 ;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     20 ;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     21 ;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     22 ;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23 
     24 (define-library (srfi srfi-123)
     25   (export ref ref* ~ register-getter-with-setter! $bracket-apply$ set! setter getter-with-setter)
     26   (import
     27    (scheme base)
     28    (scheme case-lambda)
     29 
     30    (rnrs hashtables)
     31    (rnrs records inspection)
     32    (rnrs records procedural)
     33    (rnrs records syntactic)
     34 
     35    (srfi 1)
     36    (srfi 4)
     37    (srfi 17)
     38    (srfi 26)
     39    (srfi 31)
     40    (srfi 43)
     41    (srfi 111)
     42    )
     43   (begin
     44 
     45 ;;; Helpers
     46 
     47     (define-syntax push!
     48       (syntax-rules ()
     49         ((_ <list-var> <x>)
     50          (set! <list-var> (cons <x> <list-var>)))))
     51 
     52     (define (alist->hashtable alist)
     53       (let ((table (make-eqv-hashtable 100)))
     54         (for-each (lambda (entry)
     55                     (hashtable-set! table (car entry) (cdr entry)))
     56                   alist)
     57         table))
     58 
     59     (define (pair-ref pair key)
     60       (cond
     61        ((eqv? 'car key)
     62         (car pair))
     63        ((eqv? 'cdr key)
     64         (cdr pair))
     65        (else
     66         (list-ref pair key))))
     67 
     68     (define (pair-set! pair key value)
     69       (cond
     70        ((eqv? 'car key)
     71         (set-car! pair value))
     72        ((eqv? 'cdr key)
     73         (set-cdr! pair value))
     74        (else
     75         (list-set! pair key value))))
     76 
     77 ;;; Record inspection support
     78 
     79     (define (rtd-field-index rtd field)
     80       "Find the index of a FIELD in the Record Type Descriptor RTD.
     81 
     82 Raise an error if the field does not exist."
     83       (let* ((fields (record-type-field-names rtd))
     84              (field-index (vector-index (cut eq? field <>) fields)))
     85         (unless field-index
     86           (error "Field does not exist in Record Type Descriptor (wanted field, existing fields):"
     87                  field-index
     88                  fields))
     89         field-index))
     90     (define rtd-accessor record-accessor)
     91     (define rtd-mutator record-mutator)
     92     (define (record-ref record field)
     93       (let* ((rtd (record-rtd record))
     94              (field-index (rtd-field-index rtd field))
     95              (accessor (rtd-accessor rtd field-index)))
     96         (accessor record)))
     97     (define (record-set! record field value)
     98       (let* ((rtd (record-rtd record))
     99              (field-index (rtd-field-index rtd field))
    100              (mutator (rtd-mutator rtd field-index)))
    101         (mutator record value)))
    102     (define record-getter
    103       (list (cons record? record-ref)))
    104     (define record-setter
    105       (list (cons record? record-set!)))
    106     (define record-type
    107       (list record?))
    108 
    109 ;;; SRFI-4 support
    110 
    111 ;;; In some implementations, SRFI-4 vectors are also bytevectors.  We accomodate
    112 ;;; for those implementations by using generic bytevector-ref/set! procedures
    113 ;;; which possibly dispatch to an SRFI-4 type's getter/setter, but also
    114 ;;; inserting the SRFI-4 getters/setters into the top-level dispatch tables.
    115 
    116     (define srfi-4-getters
    117       (list (cons s8vector? s8vector-ref)
    118             (cons u8vector? u8vector-ref)
    119             (cons s16vector? s16vector-ref)
    120             (cons u16vector? u16vector-ref)
    121             (cons s32vector? s32vector-ref)
    122             (cons u32vector? u32vector-ref)
    123             (cons s64vector? s64vector-ref)
    124             (cons u64vector? u64vector-ref)))
    125     (define srfi-4-setters
    126       (list (cons s8vector? s8vector-set!)
    127             (cons u8vector? u8vector-set!)
    128             (cons s16vector? s16vector-set!)
    129             (cons u16vector? u16vector-set!)
    130             (cons s32vector? s32vector-set!)
    131             (cons u32vector? u32vector-set!)
    132             (cons s64vector? s64vector-set!)
    133             (cons u64vector? u64vector-set!)))
    134     (define srfi-4-types
    135       (list s8vector? u8vector? s16vector? u16vector? s32vector? u32vector?
    136             s64vector? u64vector?))
    137     (define srfi-4-getters-table (alist->hashtable srfi-4-getters))
    138     (define srfi-4-setters-table (alist->hashtable srfi-4-setters))
    139     (define (bytevector-ref bytevector index)
    140       (let* ((type (find (lambda (pred) (pred bytevector)) srfi-4-types))
    141              (getter (if type
    142                          (ref srfi-4-getters-table type)
    143                          bytevector-u8-ref)))
    144         (getter bytevector index)))
    145     (define (bytevector-set! bytevector index value)
    146       (let* ((type (find (lambda (pred) (pred bytevector)) srfi-4-types))
    147              (setter (if type
    148                          (ref srfi-4-setters-table type)
    149                          bytevector-u8-set!)))
    150         (setter bytevector index value)))
    151 
    152 ;;; SRFI-111 boxes support
    153 
    154     (define (box-ref box _field)
    155       (unbox box))
    156     (define (box-set! box _field value)
    157       (set-box! box value))
    158     (define box-getter (list (cons box? box-ref)))
    159     (define box-setter (list (cons box? box-set!)))
    160     (define box-type (list box?))
    161 
    162 ;;; Main
    163 
    164     (define %ref
    165       (case-lambda
    166         ((object field)
    167          (let ((getter (lookup-getter object))
    168                (sparse? (sparse-type? object)))
    169            (if sparse?
    170                (let* ((not-found (cons #f #f))
    171                       (result (getter object field not-found)))
    172                  (if (eqv? result not-found)
    173                      (error "Object has no entry for field." object field)
    174                      result))
    175                (getter object field))))
    176         ((object field default)
    177          (let ((getter (lookup-getter object)))
    178            (getter object field default)))))
    179 
    180     (define (%ref* object field . fields)
    181       (if (null? fields)
    182           (%ref object field)
    183           (apply %ref* (%ref object field) fields)))
    184 
    185     (define (%set! object field value)
    186       (let ((setter (lookup-setter object)))
    187         (setter object field value)))
    188 
    189     (define ref
    190       (getter-with-setter
    191        %ref
    192        (lambda (object field value)
    193          (%set! object field value))))
    194 
    195     (define ref*
    196       (getter-with-setter
    197        %ref*
    198        ;; XXX: Originally it used the SRFI-31 rec construct, but it just would not compile!
    199        ;;
    200        ;; (rec (set!* object field rest0 . rest)
    201        ;;      (if (null? rest)
    202        ;;          (%set! object field rest0)
    203        ;;          (apply set!* (ref object field) rest0 rest)))
    204        ;;
    205        ;;
    206        (let ()
    207          (define (set!* object field rest0 . rest)
    208            (if (null? rest)
    209                (%set! object field rest0)
    210                (apply set!* (ref object field) rest0 rest)))
    211          set!*)))
    212 
    213     (define ~ ref*)
    214 
    215     (define $bracket-apply$ ref*)
    216 
    217     (define (lookup-getter object)
    218       (or (hashtable-ref getter-table (type-of object) #f)
    219           (error "No generic getter for object's type." object)))
    220 
    221     (define (lookup-setter object)
    222       (or (hashtable-ref setter-table (type-of object) #f)
    223           (error "No generic setter for object's type." object)))
    224 
    225     (define (sparse-type? object)
    226       (memv (type-of object) sparse-types))
    227 
    228     (define (type-of object)
    229       (find (lambda (pred) (pred object)) type-list))
    230 
    231     (define getter-table
    232       (alist->hashtable
    233        (append
    234         (list (cons bytevector? bytevector-ref)
    235               (cons hashtable? hashtable-ref)
    236               (cons pair? pair-ref)
    237               (cons string? string-ref)
    238               (cons vector? vector-ref))
    239         record-getter
    240         srfi-4-getters
    241         box-getter)))
    242 
    243     (define setter-table
    244       (alist->hashtable
    245        (append
    246         (list (cons bytevector? bytevector-set!)
    247               (cons hashtable? hashtable-set!)
    248               (cons pair? pair-set!)
    249               (cons string? string-set!)
    250               (cons vector? vector-set!))
    251         record-setter
    252         srfi-4-setters
    253         box-setter)))
    254 
    255     (define sparse-types
    256       (list hashtable?))
    257 
    258     (define type-list
    259       ;; Although the whole SRFI intrinsically neglects performance, we still use
    260       ;; the micro-optimization of ordering this list roughly according to most
    261       ;; likely match.
    262       (append
    263        (list hashtable? vector? pair? bytevector? string?)
    264        srfi-4-types
    265        box-type
    266        ;; The record type must be placed last so specific record types (e.g. box)
    267        ;; take precedence.
    268        record-type
    269        ;; Place those types we don't support really last.
    270        (list boolean? char? eof-object? null? number? port? procedure? symbol?)))
    271 
    272     (define (register-getter-with-setter! type getter sparse?)
    273       (push! type-list type)
    274       (set! (~ getter-table type) getter)
    275       (set! (~ setter-table type) (setter getter))
    276       (when sparse?
    277         (push! sparse-types type)))
    278     ))
    279 
    280 ;;; srfi-123.scm ends here