#lang racket/base (require racket/cmdline racket/match unstable/generics) (generics module-symbol (print module-symbol)) (define-struct symbol:normal (name) #:property prop:module-symbol (define-methods module-symbol (define (print self) (format "~a" (symbol:normal-name self))))) (define-struct symbol:renamed (provided defined) #:property prop:module-symbol (define-methods module-symbol (define (print self) (format "~a as ~a" (symbol:renamed-defined self) (symbol:renamed-provided self))))) (define-struct symbol:module-exported (where) #:property prop:module-symbol (define-methods module-symbol (define/generic symbol-print print) (define (print self) (format "from ~a" (resolved-module-path-name (module-path-index-resolve (symbol:module-exported-where self))) )))) (define-struct symbol:module-exported-as (where phase-shift imported-name import-shift) #:property prop:module-symbol (define-methods module-symbol (define/generic symbol-print print) (define (print self) (format "from ~a as ~a" (resolved-module-path-name (module-path-index-resolve (symbol:module-exported-as-where self))) (symbol:module-exported-as-imported-name self))))) (define-struct symbol:multiple-modules (symbol modules) #:property prop:module-symbol (define-methods module-symbol (define/generic symbol-print print) (define (print self) (format "~a ~a" (symbol:multiple-modules-symbol self) (let ([modules (symbol:multiple-modules-modules self)]) (if (null? modules) "" (for/fold ([start (symbol-print (car modules))]) ([next (cdr modules)]) (format "~a and ~a" start (symbol-print next))))))))) (struct provided (phase variables syntaxes)) (define (read-file file) (parameterize ([read-accept-reader #t]) (with-input-from-file file (lambda () (read))))) (define (make-symbol something) (match something [(list exported (list paths ...)) (symbol:multiple-modules exported (map (lambda (path) (match path [(and (? module-path-index?) module) (symbol:module-exported module)] [(list path phase-shift imported-name imported-phase) (symbol:module-exported-as path phase-shift imported-name imported-phase)])) paths))]) #; (match something [(list exported (list)) (symbol:normal exported)] [(list exported (list paths ...)) (for/fold ([symbol (symbol:normal exported)]) ([path paths]) (match path [(and (? module-path-index?) module) (symbol:module-exported symbol module)] [(list path phase-shift imported-name imported-phase) (symbol:module-exported-as symbol path phase-shift imported-name imported-phase)]))]) #; (match something [(and (? symbol?) x) (symbol:normal something)] [(cons module-path-index (cons provided-sym defined-sym)) (symbol:module-exported module-path-index provided-sym defined-sym)] [(cons (and (? symbol?) provided) (and (? symbol?) defined)) (symbol:renamed provided defined)])) (define (get-provides file) (define (sort-symbols symbols) (sort symbols (lambda (a b) (define (get-symbol what) (match what [(list name rest ...) (symbol->string name)])) (stringexports file) #; (expand (read-file file)))]) ; (printf "Expanded is ~a\n" expanded) ; (printf "Variables ~a\n" (syntax-property expanded 'module-variable-provides)) ; (printf "Syntaxes ~a\n" (syntax-property expanded 'module-syntax-provides)) (define exports (make-hash)) (for ([export exported-variables]) (match export [(list (and (? number?) phase) symbols ...) (hash-set! exports phase (provided phase (map make-symbol (sort-symbols symbols)) '()))])) (for ([export exported-syntaxes]) (match export [(list (and (? number?) phase) symbols ...) (hash-set! exports phase (let ([existing (hash-ref exports phase (lambda () (provided phase '() '())))]) (provided phase (provided-variables existing) (map make-symbol (sort-symbols symbols)))))])) (hash-map exports (lambda (a b) b)))) (define (phase-name phase) (case phase [(0) " (runtime)"] [(1) " (syntax)"] [(-1) " (template)"] [else ""])) (define (check-file file [phase 'all]) (define (print-all prefix stuff) (for ([symbol stuff]) (printf "~a~a\n" prefix (print symbol)))) (for ([provide (get-provides file)]) (when (or (eq? phase 'all) (equal? phase (provided-phase provide))) (printf "Phase ~a~a\n" (provided-phase provide) (phase-name (provided-phase provide))) (printf " Variables\n") (print-all " " (provided-variables provide)) (printf " Syntaxes\n") (print-all " " (provided-syntaxes provide))))) (define only-phase (make-parameter 'all)) (check-file (command-line #:program "checker" #:once-each [("--phase") phase "Only show identifiers at this phase" (only-phase (string->number phase))] #:args (file) file) (only-phase))