git @ Cat's Eye Technologies define-opaque / master src / define-opaque-0.3.scm
master

Tree @master (Download .tar.gz)

define-opaque-0.3.scm @masterraw · history · blame

;
; define-opaque.scm
; 0.3
;
; SPDX-FileCopyrightText: In 2023, Chris Pressey, the original author of this work, placed it into the public domain.
; SPDX-License-Identifier: Unlicense
; For more information, please refer to <https://unlicense.org/>
;

; ------ Helper Macros ------

(define-syntax opaque-op
  (syntax-rules ()
    ((opaque-op (name body) args)
      (apply body args))))

(define-syntax opaque-ops
  (syntax-rules ()
    ((opaque-ops target args ())
      (error "Undefined operation:" target))
    ((opaque-ops target args (op rest ...))
      (if (equal? (car 'op) target) (opaque-op op args) (opaque-ops target args (rest ...))))))

; ------ Method 1 from article: ADT ------

(define-syntax define-opaque-adt
  (syntax-rules ()
    ((define-opaque-adt name make-name open-name priv priv-default ops)
      (define name
        (let* ((secret-token (list 1)))
          (letrec
            (
              (make-name (lambda (priv)
                (lambda (target . args)
                  (if (and (eq? target secret-token) (null? args))
                    priv
                    (opaque-ops target args ops)))))
              (open-name (lambda (instance)
                (instance secret-token)))
            )
            (make-name priv-default)))))))

; ------ Method 3 from article: Immutable Object ------

(define-syntax define-opaque-object
  (syntax-rules ()
    ((define-opaque-object name make-name privs priv-defaults ops)
      (define name
        (letrec
          (
            (make-name (lambda privs
              (lambda (target . args)
                (opaque-ops target args ops))))
          )
          (make-name . priv-defaults))))))

; ------ compatibility with older versions ------

(define-syntax define-opaque
  (syntax-rules ()
    ((define-opaque name make-name privs priv-defaults ops)
      (define-opaque-object name make-name privs priv-defaults ops))))