#lang racket (provide quoted->contract explain-iface) (require syrup goblins/actor-lib/ward) (define (quoted->contract interface) (define (convert-one iface) (match iface [(list '-> args ... return-type) (define converted-args (map convert-one args)) (dynamic->* #:mandatory-domain-contracts converted-args #:range-contracts (list (convert-one return-type)))] [(list 'and/c ifaces ...) (apply and/c (map convert-one ifaces))] [(list 'or/c ifaces ...) (apply or/c (map convert-one ifaces))] ['string? string?] ['integer? integer?] ['positive-integer? positive-integer?] ['float? (and/c number? inexact?)] ['symbol? symbol?] ['boolean? boolean?])) (convert-one interface)) (define (explain-iface iface [indent-level 0] [bullet? #f]) (define first-line? #t) (define (displayln-indent str) (display "; ") ;; indent (for ([i (* indent-level 2)]) (display " ")) ;; maybe display a bullet (when bullet? (if first-line? (begin (set! first-line? #f) (display "- ")) (display " "))) ;; display the rest (displayln str)) (define next-indent-level (if bullet? (+ indent-level 2) (+ indent-level 1))) (match iface [(list '-> args ... return-type) (displayln-indent (format "A procedure which takes ~a arguments:" (length args))) (for ([arg args]) (explain-iface arg next-indent-level #t)) (displayln-indent "... and returns:") (explain-iface return-type next-indent-level)] [(list 'and/c ifaces ...) (displayln-indent "Something which meets *all* of:") (for ([iface ifaces]) (explain-iface iface next-indent-level #t))] [(list 'or/c ifaces ...) (displayln-indent "Something which meets *any* of:") (for ([iface ifaces]) (explain-iface iface next-indent-level #t))] ['string? (displayln-indent "A string")] ['integer? (displayln-indent "An integer")] ['positive-integer? (displayln-indent "A positive integer")] ['float? (displayln-indent "A floating point number")] ['symbol? (displayln-indent "A symbol")] ['boolean? (displayln-indent "A boolean")]))