racket/collects/tests/racket/submodule.rktl
Matthew Flatt f301838511 fix a syntax-object problem related to module bindings
The immediate symptom was that `(provide (all-defined-out))'
didn't work in a `module+'-based submodule, but there were
also non-submodule ways to expose the problem.
2012-03-29 14:55:13 -06:00

463 lines
15 KiB
Racket

(load-relative "loadtest.rktl")
(Section 'submodule)
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(test #t module-path? '(submod "."))
(test #t module-path? '(submod "." x))
(test #t module-path? '(submod "." x y))
(test #t module-path? '(submod "." x ".." y))
(test #t module-path? '(submod "." x ".." y ".." ".." ".."))
(test #f module-path? '(submod "." "x" y))
(test #f module-path? '(submod "." x "y"))
(test #t module-path? '(submod ".."))
(test #t module-path? '(submod ".." x))
(test #t module-path? '(submod ".." x y))
(test #f module-path? '(submod ".." "x" y))
(test #f module-path? '(submod ".." x "y"))
(test #t module-path? '(submod ".." ".."))
(test #f module-path? '(submod ".." "."))
(test #t module-path? '(submod x a b))
(test #f module-path? '(submod x "a" b))
(test #t module-path? '(submod 'x a))
(test #t module-path? '(submod 'x))
(define (check-resolution root [root-mod root])
(test root resolved-module-path-name
(module-path-index-resolve (module-path-index-join `(submod ,root-mod) #f)))
(test root resolved-module-path-name
(module-path-index-resolve (module-path-index-join `(submod ".") (make-resolved-module-path root))))
(test root resolved-module-path-name
(module-path-index-resolve (module-path-index-join `(submod "." "..") (make-resolved-module-path (list root 'y)))))
(test root resolved-module-path-name
(module-path-index-resolve (module-path-index-join `(submod "..") (make-resolved-module-path (list root 'y)))))
(err/rt-test
(module-path-index-resolve (module-path-index-join `(submod "..") (make-resolved-module-path root)))
exn:fail?))
(check-resolution 'x ''x)
(check-resolution (path->complete-path "file.rkt"))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module subm-example-1 racket/base
(define x 1)
(provide x)
(module* a racket/base
(define x '1a)
(provide x)
(module* i racket/base
(define x '1ai)
(provide x)))
(module* b racket/base
(define x '1b)
(provide x)))
(test 1 dynamic-require ''subm-example-1 'x)
(test '1a dynamic-require '(submod 'subm-example-1 a) 'x)
(test '1ai dynamic-require '(submod 'subm-example-1 a i) 'x)
(test '1b dynamic-require '(submod 'subm-example-1 b) 'x)
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module subm-example-2 racket/base
(define x 1)
(provide x)
(module a racket/base
(define x '1a)
(provide x)
(module i racket/base
(define x '1ai)
(provide x)))
(module b racket/base
(define x '1b)
(provide x)))
(test 1 dynamic-require ''subm-example-2 'x)
(test '1a dynamic-require '(submod 'subm-example-2 a) 'x)
(test '1ai dynamic-require '(submod 'subm-example-2 a i) 'x)
(test '1b dynamic-require '(submod 'subm-example-2 b) 'x)
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module subm-example-9 racket/base
(define x '(1))
(provide x)
(module* a #f
(require racket/list)
(define z (last x))
(provide z)
(define-syntax-rule (as-last) last)
(provide as-last)))
(test '(1) dynamic-require ''subm-example-9 'x)
(test 1 dynamic-require '(submod 'subm-example-9 a) 'z)
(module subm-example-use-9 racket/base
(require (submod 'subm-example-9 a))
(define x ((as-last) '(1 2 3)))
(provide x))
(test 3 dynamic-require ''subm-example-use-9 'x)
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(let ([o (open-output-bytes)])
(write (compile '(module subm-example-0 racket/base
(define x 1)
(provide x)
(module z racket/base
(define z 26))
(module* a racket/base
(define x '1a)
(provide x)
(module* i racket/base
(define x '1ai)
(provide x)))
(module* b racket/base
(define x '1b)
(provide x))))
o)
(define c (parameterize ([read-accept-compiled #t])
(read (open-input-bytes (get-output-bytes o)))))
(test 'subm-example-0 values (module-compiled-name c))
(test 2 values (length (module-compiled-submodules c #f)))
(for ([sub (in-list (append (module-compiled-submodules c #t)
(module-compiled-submodules c #f)))]
[name '(z a b)])
(test (list 'subm-example-0 name) values (module-compiled-name sub))
(when (eq? name 'a)
(test 1 values (length (module-compiled-submodules sub #f)))
(test '(subm-example-0 a i) values (module-compiled-name (car (module-compiled-submodules sub #f))))))
(define a (module-compiled-name (car (module-compiled-submodules c #f))
'reset))
(test 'reset values (module-compiled-name a))
(test '(reset i) values (module-compiled-name (car (module-compiled-submodules a #f))))
(define aa (module-compiled-submodules a #f (list (module-compiled-name a 'again))))
(test '(reset again) values (module-compiled-name (car (module-compiled-submodules aa #f))))
(test '(reset again i) values (module-compiled-name (car (module-compiled-submodules (car (module-compiled-submodules aa #f)) #f)))))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(let ([decl '(module m racket/base
(module z racket/base
(provide z)
(define z 26))
(require (submod "." z))
(provide !)
(define ! (add1 z))
(module* a racket/base
(provide a)
(define a 1))
(module* b racket/base
(require (submod "." ".." a))
(provide b)
(define b (+ a 1))))])
;; write a module as part of a top-level sequence:
(parameterize ([current-namespace (make-base-namespace)])
(define o (open-output-bytes))
(write (compile `(begin ,decl 10)) o)
(define e (parameterize ([read-accept-compiled #t])
(read (open-input-bytes (get-output-bytes o)))))
(eval e)
(test 2 eval '(dynamic-require '(submod 'm b) 'b))
(test 27 eval '(dynamic-require ''m '!)))
;; write a module as directory:
(parameterize ([current-namespace (make-base-namespace)])
(define o (open-output-bytes))
(write (compile decl) o)
(define s (get-output-bytes o))
(define e (parameterize ([read-accept-compiled #t])
(read (open-input-bytes s))))
(test 1 values (length (module-compiled-submodules e #t)))
(test 2 values (length (module-compiled-submodules e #f)))
(eval e)
(test 2 eval '(dynamic-require '(submod 'm b) 'b))
(test 27 eval '(dynamic-require ''m '!))))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module submodule-exp5 racket/base
(require (for-syntax racket/base))
(define root 0)
(define-syntax (rooty stx) #'8)
(begin-for-syntax
(define nine 9))
(module* a #f
(provide root))
(module* b #f
(define root 1)
(module* c #f
(provide root
rooty
(for-syntax nine))))
(module* d racket/base
(require (for-syntax racket/base))
(require (submod "." ".." b c))
(define-syntax (use-nine stx) (datum->syntax #'here nine))
(define rootd (use-nine))
(provide rootd)))
(test 0 dynamic-require '(submod 'submodule-exp5 a) 'root)
(test 1 dynamic-require '(submod 'submodule-exp5 b c) 'root)
(test 8 dynamic-require '(submod 'submodule-exp5 b c) 'rooty)
(test 9 dynamic-require '(submod 'submodule-exp5 d) 'rootd)
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(let ()
(define (simplify base p)
(resolved-module-path-name (module-path-index-resolve (module-path-index-join p base))))
(define (check root-path)
(define a (module-path-index-join root-path #f))
(define ar (resolved-module-path-name (module-path-index-resolve a)))
(test (cons ar '(x)) simplify a '(submod "." x))
(test (cons ar '(x y z)) simplify a '(submod "." x y z))
(test (cons ar '(y z)) simplify a '(submod "." x ".." y z))
(test (cons ar '(z)) simplify a '(submod "." x y ".." ".." z))
(test (cons ar '(q x)) simplify
(module-path-index-join '(submod "." q) a)
'(submod "." x))
(test (cons ar '(x)) simplify
(module-path-index-join '(submod "." q) a)
'(submod "." ".." x))
(test ar simplify
(module-path-index-join '(submod "." q) a)
'(submod "." "..")))
(check ''a)
(check 'racket/base))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; check that re-expansion with submodules works right:
(eval
(expand
(expand '(module sub1-m racket/base
(module* n racket/base
(define-syntax-rule (mk v)
(begin
(define x v)
(provide x)))
(define x 11)
(mk 12))))))
(test 12 dynamic-require '(submod 'sub1-m n) 'x)
(eval
(expand
(expand '(module sub4-m racket/base
(module n racket/base
(define-syntax-rule (mk v)
(begin
(define x v)
(provide x)))
(define x 11)
(mk 120))))))
(test 120 dynamic-require '(submod 'sub4-m n) 'x)
(eval
(expand
(expand '(module sub3.5-m racket
(begin-for-syntax
(module* n #f (define x 8.5) (provide x)))))))
(test 8.5 dynamic-require '(submod 'sub3.5-m n) 'x)
(eval
(expand
(expand '(module sub3-m racket/base
(module* n #f (define x 8) (provide x))))))
(test 8 dynamic-require '(submod 'sub3-m n) 'x)
(eval
(expand
(expand '(module sub2-m racket/base
(define x 11)
(module* n #f
(define-syntax-rule (mk v)
(begin
(define y v)
(provide y)))
(mk x))))))
(test 11 dynamic-require '(submod 'sub2-m n) 'y)
(expand
(expand
#'(module s racket/base
(struct node (height))
(node-height 0)
(module+ main))))
(expand
(expand
#'(module s racket/base
(module* main #f)
(struct node (height))
(node-height 0))))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; `begin-for-syntax' doesn't affect `module' with non-#f language:
(module subm-example-6 racket
(begin-for-syntax
(module* a racket
(define x '6a)
(provide x)
(begin-for-syntax
(module* i racket/base
(define x '6ai)
(provide x))))))
(test '6a dynamic-require '(submod 'subm-example-6 a) 'x)
(test '6ai dynamic-require '(submod 'subm-example-6 a i) 'x)
(module subm-example-x6 racket
(begin-for-syntax
(module a racket
(define x 'x6a)
(provide x)
(begin-for-syntax
(module i racket/base
(define x 'x6ai)
(provide x))))))
(test 'x6a dynamic-require '(submod 'subm-example-x6 a) 'x)
(test 'x6ai dynamic-require '(submod 'subm-example-x6 a i) 'x)
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module subm-example-7 racket/base
(require (for-syntax racket/base))
(define x 7)
(begin-for-syntax
(define x 8)
(module* a #f
(define z x)
(provide z))))
(test '8 dynamic-require '(submod 'subm-example-7 a) 'z)
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(module subm-example-11 racket/base
(require (for-syntax racket/base))
(define (listify x) (list x))
(define-syntax (add-submodule stx)
(with-syntax (#;[(define-b-module) (generate-temporaries '(define-b))])
(syntax-local-lift-module-end-declaration
#'(module* a #f
(provide a)
(define a (listify 'a))))
(syntax-local-lift-module-end-declaration
#'(define-b-module))
#'(define-syntax (define-b-module stx)
#'(module* b #f
(define b 'b)
(provide b)))))
(add-submodule)
(provide add-submodule))
(test '(a) dynamic-require '(submod 'subm-example-11 a) 'a)
(test 'b dynamic-require '(submod 'subm-example-11 b) 'b)
(module subm-example-12 racket/base
(require 'subm-example-11)
(add-submodule))
(test '(a) dynamic-require '(submod 'subm-example-12 a) 'a)
(test 'b dynamic-require '(submod 'subm-example-12 b) 'b)
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; The `section' form:
(module module+-example-1 racket/base
(module+ alpha (define a root) (provide a))
(module+ beta (define b (+ root 1)) (provide b))
(module+ alpha (define aa (+ a a)) (provide aa))
(module+ gamma
(require (submod "." ".." beta))
(provide c)
(define c (+ b 1)))
(module+ beta)
(module+ beta)
(module+ beta)
(define root 1))
(test 1 dynamic-require '(submod 'module+-example-1 alpha) 'a)
(test 2 dynamic-require '(submod 'module+-example-1 alpha) 'aa)
(test 2 dynamic-require '(submod 'module+-example-1 beta) 'b)
(test 3 dynamic-require '(submod 'module+-example-1 gamma) 'c)
(syntax-test #'(module+ a))
(err/rt-test (eval #'(module m racket/base module+)) exn:fail:syntax?)
(err/rt-test (eval #'(module m racket/base (module+))) exn:fail:syntax?)
(err/rt-test (eval #'(module m racket/base (module+ 1))) exn:fail:syntax?)
(err/rt-test (eval #'(module m racket/base (module+ a . 2))) exn:fail:syntax?)
;; Check that `#%module-begin' context is reasonable:
(module module+-example-2 racket/base
(module alt-mod-beg racket/base
(provide (rename-out [module-begin #%module-begin])
module+
#%datum
#%app
void)
(define-syntax-rule (module-begin a b c)
(#%module-begin a (define x (+ b c)) (provide x))))
(module a (submod "." ".." alt-mod-beg)
(module+ b (void) 1 2)
3 4))
(test 3 dynamic-require '(submod 'module+-example-2 a b) 'x)
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Check that various shaodwings are allowed:
(module subm-example-20 racket/base
(require (only-in racket/list third))
(provide first get-first second)
(define first 1)
(define (get-first) first) ;; verifies shadowing not mutation
(module* first #f
(define first 0) ;; shadows outer 'first'
(define f first)
(provide first f))
(define second 2)
(module* second #f
(require (only-in racket/list second))
(define s second)
(provide second s))
(module* third #f
(require (only-in mzlib/list third)) ; different binding than from `racket/list'
(define t third)
(provide third t)))
(test 1 dynamic-require ''subm-example-20 'first)
(test 1 (dynamic-require ''subm-example-20 'get-first))
(test 2 dynamic-require ''subm-example-20 'second)
(test 'b (dynamic-require '(submod 'subm-example-20 second) 'second) '(a b c))
(test 'b (dynamic-require '(submod 'subm-example-20 second) 's) '(a b c))
(test 'c (dynamic-require '(submod 'subm-example-20 third) 'third) '(a b c))
(test 'c (dynamic-require '(submod 'subm-example-20 third) 't) '(a b c))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Check `all-defined-out':
(module subm-all-defined-1 racket/base
(module+ main
(define x 10)
(provide (all-defined-out))))
(test 10 dynamic-require '(submod 'subm-all-defined-1 main) 'x)
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(report-errs)