(module sigmatch mzscheme (require "../unit200.rkt") (define (hash-sig src-sig table) (and (pair? src-sig) (vector? (car src-sig)) (andmap (lambda (s) (cond [(symbol? s) (if (hash-table-get table s #f) #f (begin (hash-table-put! table s s) #t))] [(and (pair? s) (symbol? (car s))) (let ([name (car s)]) (if (hash-table-get table name #f) #f (let ([t (make-hash-table)]) (hash-table-put! table name t) (hash-sig (cdr s) t))))] [else #f])) (vector->list (car src-sig))))) (define (sig-path-name name path) (let loop ([s (symbol->string name)] [path path]) (if (null? path) s (loop (format "~a:~a" s (car path)) (cdr path))))) (define no-val (gensym)) (define (check-sig-match table sig path exact? who src-context dest-context wrapped? unwrap) (and (wrapped? sig) (vector? (unwrap sig)) (andmap (lambda (s) (cond [(symbol? s) (let ([v (hash-table-get table s no-val)]) (when (eq? v no-val) (raise (make-exn:fail:unit (format "~a: ~a is missing a value name `~a', required by ~a" who src-context (sig-path-name s path) dest-context) (current-continuation-marks)))) (and v (begin (unless (symbol? v) (let ([p (sig-path-name s path)]) (raise (make-exn:fail:unit (format "~a: ~a contains `~a' as a sub-unit name, but ~a contains `~a' as a value name" who src-context p dest-context p) (current-continuation-marks))))) (hash-table-put! table s #f) #t)))] [(and (pair? s) (symbol? (car s))) (let ([v (hash-table-get table (car s) no-val)]) (when (eq? v no-val) (raise (make-exn:fail:unit (format "~a: ~a is missing a sub-unit name `~a', required by ~a" who src-context (sig-path-name (car s) path) dest-context) (current-continuation-marks)))) (and v (begin (unless (hash-table? v) (let ([p (sig-path-name (car s) path)]) (raise (make-exn:fail:unit (format "~a: ~a contains `~a' as a value name, but ~a contains `~a' as a sub-unit name" who src-context p dest-context p) (current-continuation-marks))))) (hash-table-put! table (car s) #f) (check-sig-match v (cdr s) (cons (car s) path) exact? who src-context dest-context wrapped? unwrap))))] [else #f])) (vector->list (unwrap sig))) (or (not exact?) (hash-table-for-each table (lambda (k v) (when v (let ([p (sig-path-name k path)]) (raise (make-exn:fail:unit (format "~a: ~a contains an extra ~a name `~a' that is not required by ~a" who src-context (if (symbol? v) 'value 'sub-unit) p dest-context) (current-continuation-marks))))))) #t))) (define (-verify-signature-match who exact? dest-context dest-sig src-context src-sig wrapped? unwrap) (unless (symbol? who) (raise-type-error 'verify-signature-match "symbol" who)) (unless (string? dest-context) (raise-type-error 'verify-signature-match "string" dest-context)) (unless (string? src-context) (raise-type-error 'verify-signature-match "string" src-context)) (let ([src-table (make-hash-table)]) (unless (hash-sig src-sig src-table) (raise-type-error 'verify-signature-match "exploded signature" src-sig)) (unless (check-sig-match src-table dest-sig null exact? who src-context dest-context wrapped? unwrap) (raise-type-error 'verify-signature-match "exploded signature" dest-sig)))) (define (alt-verify-signature-match who exact? dest-context dest-sig src-context src-sig) (-verify-signature-match who exact? dest-context dest-sig src-context src-sig pair? car)) (define (verify-signature-match who exact? dest-context dest-sig src-context src-sig) (-verify-signature-match who exact? dest-context dest-sig src-context src-sig values values)) (provide -verify-signature-match verify-signature-match alt-verify-signature-match))