#lang racket/base ;; Macros for defining weak and extensible mappings between sets of values (provide define-mapping) ;; Internal. Extracts macro keywords from a list of arguments. (define-syntax check-defaults (syntax-rules () ((_ fn bn fd bd #:forward-default new-fd rest ...) (check-defaults fn bn new-fd bd rest ...)) ((_ fn bn fd bd #:backward-default new-bd rest ...) (check-defaults fn bn fd new-bd rest ...)) ((_ fn bn fd bd (lhs rhs) ...) (begin (define (fn l) (case l ((lhs) 'rhs) ... (else (fd l)))) (define (bn r) (case r ((rhs) 'lhs) ... (else (bd r)))))))) ;; Symbol -> raised exn:fail:contract ;; Used by default to complain when no specific mapping is found. ;; The argument indicates to the user the direction of the mapping. (define (die-with-mapping-name n) (lambda (v) (raise (exn:fail:contract (format "~v: Mapping not found for ~v" n v) (current-continuation-marks))))) ;; (define-mapping ;; { #:forward-default }? ;; { #:backward-default }? ;; ( ) ...) ;; Defines two functions, forward-name and backward-name, which take ;; values from the left-hand-sides of the mappings given as "( ;; )" to the right-hand-sides and vice versa, respectively. ;; ;; If specified, the #:forward-default and #:backward-default exprs ;; should evaluate to a procedure of one argument which can be used ;; for fallback computation of the mapping or for error ;; reporting. They default to raising exn:fail:contract. (define-syntax define-mapping (syntax-rules () ((_ forward-name backward-name rest ...) (check-defaults forward-name backward-name (die-with-mapping-name 'forward-name) (die-with-mapping-name 'backward-name) rest ...))))