(module standard-resolver mzscheme (require (planet "unzip.ss" ("dherman" "zip.plt" 2))) (require (lib "string.ss" "srfi" "13")) (require (lib "list.ss" "srfi" "1")) (require (all-except (lib "class.ss") class-info)) (require (lib "file.ss")) (require (lib "etc.ss")) (require "class-resolver.ss") (require "semantic-object.ss") (require "resolve-binary.ss") (require "resolve-source.ss") (require "../util/class-file.ss") (require "../java.ss") ;; =========================================================================== ;; DELEGATES TO PERFORM RESOLUTION ;; =========================================================================== ;; java-filename? : path -> boolean (define (java-filename? name) (bytes=? (filename-extension name) #"java")) ;; jar-filename? : path -> boolean (define (jar-filename? name) (let ([ext (filename-extension name)]) (or (bytes=? ext #"jar") (bytes=? ext #"zip")))) ;; class-filename? : path -> boolean (define (class-filename? name) (bytes=? (filename-extension name) #"class")) ;; make-jar-resolver : path -> (path -> (option declared-type%)) (define (make-jar-resolver jar) (let ([zipdir (read-zip-directory jar)]) (lambda (entry) (let ([entry (path->zip-path entry)]) (and (zip-directory-contains? entry zipdir) (unzip-entry jar zipdir entry (lambda (p dir? in) (resolve-binary (read-class-file in))))))))) ;; make-directory-resolver : path -> (path -> (option declared-type%)) (define (make-directory-resolver basedir) (lambda (file) (and (class-filename? file) (let ([fullpath (build-path basedir file)]) (and (file-exists? fullpath) (resolve-binary (with-input-from-file fullpath read-class-file))))))) ;; make-binary-resolver : path -> (path -> (option declared-type%)) (define (make-binary-resolver classpath-entry) (cond [(directory-exists? classpath-entry) (make-directory-resolver classpath-entry)] [(and (jar-filename? classpath-entry) (file-exists? classpath-entry)) (make-jar-resolver classpath-entry)] [else (error 'make-resolver "bad classpath entry: ~v" classpath-entry)])) ;; try : (listof (a -> (option b))) a -> (option b) (define (try preds x) (and (pair? preds) (or ((car preds) x) (try (cdr preds) x)))) ;; =========================================================================== ;; CLASS RESOLVER OBJECT ;; =========================================================================== ;; class-filename : type-name -> path (define (class-filename tn) (let ([file (string-append (symbol->string (type-name-type tn)) ".class")] [pkg (type-name-package tn)]) (if (null? pkg) file (build-path (let loop ([pkg (cdr pkg)] [path (string->path (symbol->string (car pkg)))]) (if (null? pkg) path (loop (cdr pkg) (build-path path (symbol->string (car pkg)))))) file)))) (define class-resolver% (class* object% (class-resolver<%>) (public resolve-package resolve-type) (define all-packages (make-hash-table 'equal)) (define classpath (map make-binary-resolver (current-classpath))) (define (find-package name) (hash-table-get all-packages name (lambda () (let ([entry (cons (make-object package% name) (make-hash-table))]) (hash-table-put! all-packages name entry) entry)))) ;; resolve-package : (listof symbol) -> package% (define (resolve-package pkg) (car (find-package pkg))) ;; TODO: where to create unknown-type% instances? (define (resolve-primitive-type name) (and (null? (type-name-package name)) (case (type-name-type name) [(byte) byte] [(char) char] [(int) int] [(long) long] [(short) short] [(float) float] [(double) double] [(boolean) boolean] [else #f]))) ;; resolve-type : type-name -> (option type<%>) (define (resolve-type ty) (or (resolve-primitive-type ty) (let* ([type-name (type-name-type ty)] [entry (find-package (type-name-package ty))] [package (car entry)] [types (cdr entry)]) (hash-table-get types type-name (lambda () (cond [(try classpath (class-filename ty)) => (lambda (type) (hash-table-put! types type-name type) (send type resolve-all) type)] [else #f])))))) (super-new))) (provide class-resolver%))