#lang racket/base (provide (struct-out annotated) annotate annotations strip-annotations strip-annotations-proc peel-annotations peel-annotations-proc) (require racket/match) (require (for-syntax racket/base)) (require "record.rkt") (require racket/dict) (require racket/set) ;; Syntax properties and syntax objects would be almost perfect for ;; representing annotations, plus position/source tracking as ;; lagniappe, but unfortunately they don't play nicely with data much ;; outside of ordinary S-expressions as found in Racket source. ;; ;; So we do our own thing, for now. ;; ;; See also https://gitlab.com/preserves/preserves/-/issues/16, ;; 'Consider Racket "correlated objects" for annotations ;; representation'. ;; (struct annotated (annotations srcloc item) #:transparent #:methods gen:equal+hash [(define (equal-proc a b =?) (=? (annotated-item a) (annotated-item b))) (define (hash-proc a h) (h (annotated-item a))) (define (hash2-proc a h) (h (annotated-item a)))]) (define (annotate v . as) (match v [(annotated annotations srcloc item) (annotated (append as annotations) srcloc item)] [item (annotated as #f item)])) (define (annotations v) (match v [(annotated annotations _ _) annotations] [_ '()])) (define (strip-annotations-proc v #:depth [depth +inf.0]) (let walk* ((v v) (depth depth)) (define next-depth (- depth 1)) (define (walk v) (walk* v next-depth)) (if (zero? depth) v (match v [(annotated _ _ item) (match item [(record label fields) (record (walk* label depth) (map walk fields))] [(? list?) (map walk item)] [(? set?) (for/set [(i (in-set item))] (walk i))] [(? dict?) (for/hash [((k v) (in-dict item))] (values (walk* k depth) (walk v)))] [(? annotated?) (error 'strip-annotations "Improper annotation structure: ~v" v)] [_ item])] [_ v])))) (define (peel-annotations-proc v) (strip-annotations-proc v #:depth 1)) (define-match-expander strip-annotations (syntax-rules () [(_ pat extra ...) (app (lambda (v) (strip-annotations-proc v extra ...)) pat)]) (lambda (stx) (syntax-case stx () [(_ args ...) #'(strip-annotations-proc args ...)] [_ #'strip-annotations-proc]))) (define-match-expander peel-annotations (syntax-rules () [(_ pat extra ...) (app (lambda (v) (peel-annotations-proc v extra ...)) pat)]) (lambda (stx) (syntax-case stx () [(_ args ...) #'(peel-annotations-proc args ...)] [_ #'peel-annotations-proc])))