/collects/racket/package.rkt

http://github.com/gmarceau/PLT · Racket · 444 lines · 414 code · 17 blank · 13 comment · 73 complexity · e8a6d931a69494fe199fd08414957cff MD5 · raw file

  1. #lang scheme/base
  2. (require (for-syntax scheme/base
  3. scheme/list
  4. syntax/kerncase
  5. syntax/boundmap
  6. syntax/define
  7. syntax/flatten-begin))
  8. (provide define-package
  9. package-begin
  10. open-package
  11. open*-package
  12. define*
  13. define*-values
  14. define*-syntax
  15. define*-syntaxes
  16. (for-syntax package?
  17. package-exported-identifiers
  18. package-original-identifiers))
  19. (define-for-syntax (do-define-* stx define-values-id)
  20. (syntax-case stx ()
  21. [(_ (id ...) rhs)
  22. (let ([ids (syntax->list #'(id ...))])
  23. (for-each (lambda (id)
  24. (unless (identifier? id)
  25. (raise-syntax-error
  26. #f
  27. "expected an identifier for definition"
  28. stx
  29. id)))
  30. ids)
  31. (with-syntax ([define-values define-values-id])
  32. (syntax/loc stx
  33. (define-values (id ...) rhs))))]))
  34. (define-syntax (-define*-values stx)
  35. (do-define-* stx #'define-values))
  36. (define-syntax (-define*-syntaxes stx)
  37. (do-define-* stx #'define-syntaxes))
  38. (define-syntax (define*-values stx)
  39. (syntax-case stx ()
  40. [(_ (id ...) rhs)
  41. (syntax-property
  42. (syntax/loc stx (-define*-values (id ...) rhs))
  43. 'certify-mode
  44. 'transparent-binding)]))
  45. (define-syntax (define*-syntaxes stx)
  46. (syntax-case stx ()
  47. [(_ (id ...) rhs)
  48. (syntax-property
  49. (syntax/loc stx (-define*-syntaxes (id ...) rhs))
  50. 'certify-mode
  51. 'transparent-binding)]))
  52. (define-syntax (define* stx)
  53. (let-values ([(id rhs) (normalize-definition stx #'lambda)])
  54. (quasisyntax/loc stx
  55. (define*-values (#,id) #,rhs))))
  56. (define-syntax (define*-syntax stx)
  57. (let-values ([(id rhs) (normalize-definition stx #'lambda)])
  58. (quasisyntax/loc stx
  59. (define*-syntaxes (#,id) #,rhs))))
  60. (begin-for-syntax
  61. (define-struct package (exports hidden)
  62. #:omit-define-syntaxes
  63. #:property prop:procedure (lambda (r stx)
  64. (raise-syntax-error
  65. #f
  66. "misuse of a package name"
  67. stx)))
  68. (define (generate-hidden id)
  69. ;; Like `generate-temporaries', but preserve the symbolic name
  70. ((make-syntax-introducer) (datum->syntax #f (syntax-e id))))
  71. (define (reverse-mapping who id exports hidden)
  72. (or (ormap (lambda (m)
  73. (and (free-identifier=? id (cdr m))
  74. (car m)))
  75. exports)
  76. (ormap (lambda (h)
  77. (and (free-identifier=? id h)
  78. ;; Not at top level, where free-id=? is unreliable,
  79. ;; and re-definition is ok:
  80. (identifier-binding id)
  81. ;; Name is inaccessible. Generate a temporary to
  82. ;; avoid potential duplicate-definition errors
  83. ;; when the name is bound in the same context as
  84. ;; the package.
  85. (generate-hidden id)))
  86. hidden)
  87. id)))
  88. (define-for-syntax (move-props orig new)
  89. (datum->syntax new
  90. (syntax-e new)
  91. orig
  92. orig))
  93. (define-for-syntax (do-define-package stx exp-stx)
  94. (syntax-case exp-stx ()
  95. [(_ pack-id mode exports form ...)
  96. (let ([id #'pack-id]
  97. [exports #'exports]
  98. [mode (syntax-e #'mode)])
  99. (unless (eq? mode '#:begin)
  100. (unless (identifier? id)
  101. (raise-syntax-error #f
  102. "expected an identifier"
  103. stx
  104. id)))
  105. (let ([exports
  106. (cond
  107. [(syntax->list exports)
  108. => (lambda (l)
  109. (for-each (lambda (i)
  110. (unless (identifier? i)
  111. (raise-syntax-error #f
  112. "expected identifier to export"
  113. stx
  114. i)))
  115. l)
  116. (let ([dup-id (check-duplicate-identifier l)])
  117. (when dup-id
  118. (raise-syntax-error
  119. #f
  120. "duplicate export"
  121. stx
  122. dup-id)))
  123. l)]
  124. [else (raise-syntax-error #f
  125. (format "expected a parenthesized sequence of identifiers ~a"
  126. (case mode
  127. [(#:only) "to export"]
  128. [(#:all-defined-except) "to exclude from export"]
  129. [else (format "for ~a" mode)]))
  130. stx
  131. exports)])])
  132. (let* ([def-ctx (syntax-local-make-definition-context)]
  133. [ctx (cons (gensym 'intdef)
  134. (let ([orig-ctx (syntax-local-context)])
  135. (if (pair? orig-ctx)
  136. orig-ctx
  137. null)))]
  138. [pre-package-id (lambda (id def-ctxes)
  139. (identifier-remove-from-definition-context
  140. id
  141. def-ctxes))]
  142. [kernel-forms (list*
  143. #'-define*-values
  144. #'-define*-syntaxes
  145. (kernel-form-identifier-list))]
  146. [init-exprs (syntax->list #'(form ...))]
  147. [new-bindings (make-bound-identifier-mapping)]
  148. [fixup-sub-package (lambda (renamed-exports renamed-defines def-ctxes)
  149. (lambda (stx)
  150. (syntax-case* stx (define-syntaxes #%plain-app make-package quote-syntax
  151. list cons #%plain-lambda)
  152. free-transformer-identifier=?
  153. [(define-syntaxes (pack-id)
  154. (#%plain-app
  155. make-package
  156. (#%plain-lambda ()
  157. (#%plain-app list
  158. (#%plain-app cons
  159. (quote-syntax export)
  160. (quote-syntax renamed))
  161. ...))
  162. hidden))
  163. (with-syntax ([(export ...)
  164. (map (lambda (id)
  165. (if (or (ormap (lambda (e-id)
  166. (bound-identifier=? id e-id))
  167. renamed-exports)
  168. (not (ormap (lambda (e-id)
  169. (bound-identifier=? id e-id))
  170. renamed-defines)))
  171. ;; Need to preserve the original
  172. (pre-package-id id def-ctxes)
  173. ;; It's not accessible, so just hide the name
  174. ;; to avoid re-binding errors. (Is this necessary,
  175. ;; or would `pre-package-id' take care of it?)
  176. (generate-hidden id)))
  177. (syntax->list #'(export ...)))])
  178. (syntax/loc stx
  179. (define-syntaxes (pack-id)
  180. (make-package
  181. (lambda ()
  182. (list (cons (quote-syntax export)
  183. (quote-syntax renamed))
  184. ...))
  185. hidden))))]
  186. [_ stx])))]
  187. [complement (lambda (bindings ids)
  188. (let ([tmp (make-bound-identifier-mapping)])
  189. (bound-identifier-mapping-for-each bindings
  190. (lambda (k v)
  191. (bound-identifier-mapping-put! tmp k #t)))
  192. (for-each (lambda (id)
  193. (bound-identifier-mapping-put! tmp id #f))
  194. ids)
  195. (filter
  196. values
  197. (bound-identifier-mapping-map tmp (lambda (k v) (and v k))))))])
  198. (let ([register-bindings!
  199. (lambda (ids)
  200. (for-each (lambda (id)
  201. (when (bound-identifier-mapping-get new-bindings id (lambda () #f))
  202. (raise-syntax-error #f
  203. "duplicate binding"
  204. stx
  205. id))
  206. (bound-identifier-mapping-put! new-bindings
  207. id
  208. #t))
  209. ids))]
  210. [add-package-context (lambda (def-ctxes)
  211. (lambda (stx)
  212. (let ([q (local-expand #`(quote #,stx)
  213. ctx
  214. (list #'quote)
  215. def-ctxes)])
  216. (syntax-case q ()
  217. [(_ stx) #'stx]))))])
  218. (let loop ([exprs init-exprs]
  219. [rev-forms null]
  220. [def-ctxes (list def-ctx)])
  221. (cond
  222. [(null? exprs)
  223. (for-each (lambda (def-ctx)
  224. (internal-definition-context-seal def-ctx))
  225. def-ctxes)
  226. (let ([exports-renamed (map (add-package-context def-ctxes) exports)]
  227. [defined-renamed (bound-identifier-mapping-map new-bindings
  228. (lambda (k v) k))])
  229. (for-each (lambda (ex renamed)
  230. (unless (bound-identifier-mapping-get new-bindings
  231. renamed
  232. (lambda () #f))
  233. (raise-syntax-error #f
  234. (format "no definition for ~a identifier"
  235. (case mode
  236. [(#:only) "exported"]
  237. [(#:all-defined-except) "excluded"]))
  238. stx
  239. ex)))
  240. exports
  241. exports-renamed)
  242. (let-values ([(exports exports-renamed)
  243. (if (memq mode '(#:only #:begin))
  244. (values exports exports-renamed)
  245. (let ([all-exports-renamed (complement new-bindings exports-renamed)])
  246. ;; In case of define*, get only the last definition:
  247. (let ([tmp (make-bound-identifier-mapping)])
  248. (for-each (lambda (id)
  249. (bound-identifier-mapping-put!
  250. tmp
  251. ((add-package-context def-ctxes)
  252. (pre-package-id id def-ctxes))
  253. #t))
  254. all-exports-renamed)
  255. (let* ([exports-renamed (bound-identifier-mapping-map tmp (lambda (k v) k))]
  256. [exports (map (lambda (id) (pre-package-id id def-ctxes))
  257. exports-renamed)])
  258. (values exports exports-renamed)))))]
  259. [(prune)
  260. (lambda (stx)
  261. (identifier-prune-lexical-context stx (list (syntax-e stx) '#%top)))])
  262. (with-syntax ([(export ...) (map prune exports)]
  263. [(renamed ...) (map prune exports-renamed)]
  264. [(hidden ...) (map prune (complement new-bindings exports-renamed))])
  265. (let ([body (map (fixup-sub-package exports-renamed defined-renamed def-ctxes)
  266. (reverse rev-forms))])
  267. (if (eq? mode '#:begin)
  268. (if (eq? 'expression (syntax-local-context))
  269. (quasisyntax/loc stx (let () #,@body))
  270. (quasisyntax/loc stx (begin #,@body)))
  271. (quasisyntax/loc stx
  272. (begin
  273. #,@(if (eq? 'top-level (syntax-local-context))
  274. ;; delcare all bindings before they are used:
  275. #`((define-syntaxes #,defined-renamed (values)))
  276. null)
  277. #,@body
  278. (define-syntax pack-id
  279. (make-package
  280. (lambda ()
  281. (list (cons (quote-syntax export)
  282. (quote-syntax renamed))
  283. ...))
  284. (lambda ()
  285. (list (quote-syntax hidden) ...)))))))))))]
  286. [else
  287. (let ([expr (local-expand (car exprs)
  288. ctx
  289. kernel-forms
  290. def-ctxes)])
  291. (syntax-case expr (begin)
  292. [(begin . rest)
  293. (loop (append (flatten-begin expr) (cdr exprs))
  294. rev-forms
  295. def-ctxes)]
  296. [(def (id ...) rhs)
  297. (and (or (free-identifier=? #'def #'define-syntaxes)
  298. (free-identifier=? #'def #'-define*-syntaxes))
  299. (andmap identifier? (syntax->list #'(id ...))))
  300. (with-syntax ([rhs (local-transformer-expand
  301. #'rhs
  302. 'expression
  303. null)])
  304. (let ([star? (free-identifier=? #'def #'-define*-syntaxes)]
  305. [ids (syntax->list #'(id ...))])
  306. (let* ([def-ctx (if star?
  307. (syntax-local-make-definition-context (car def-ctxes))
  308. (last def-ctxes))]
  309. [ids (map
  310. (lambda (id) (syntax-property id 'unshadowable #t))
  311. (if star?
  312. (map (add-package-context (list def-ctx)) ids)
  313. ids))])
  314. (syntax-local-bind-syntaxes ids #'rhs def-ctx)
  315. (register-bindings! ids)
  316. (loop (cdr exprs)
  317. (cons (move-props expr #`(define-syntaxes #,ids rhs))
  318. rev-forms)
  319. (if star? (cons def-ctx def-ctxes) def-ctxes)))))]
  320. [(def (id ...) rhs)
  321. (and (or (free-identifier=? #'def #'define-values)
  322. (free-identifier=? #'def #'-define*-values))
  323. (andmap identifier? (syntax->list #'(id ...))))
  324. (let ([star? (free-identifier=? #'def #'-define*-values)]
  325. [ids (syntax->list #'(id ...))])
  326. (let* ([def-ctx (if star?
  327. (syntax-local-make-definition-context (car def-ctxes))
  328. (last def-ctxes))]
  329. [ids (map
  330. (lambda (id) (syntax-property id 'unshadowable #t))
  331. (if star?
  332. (map (add-package-context (list def-ctx)) ids)
  333. ids))])
  334. (syntax-local-bind-syntaxes ids #f def-ctx)
  335. (register-bindings! ids)
  336. (loop (cdr exprs)
  337. (cons (move-props expr #`(define-values #,ids rhs)) rev-forms)
  338. (if star? (cons def-ctx def-ctxes) def-ctxes))))]
  339. [else
  340. (loop (cdr exprs)
  341. (cons (if (and (eq? mode '#:begin)
  342. (null? (cdr exprs)))
  343. expr
  344. #`(define-values () (begin #,expr (values))))
  345. rev-forms)
  346. def-ctxes)]))]))))))]))
  347. (define-syntax (define-package stx)
  348. (syntax-case stx ()
  349. [(_ id #:all-defined form ...)
  350. (do-define-package stx #'(define-package id #:all-defined () form ...))]
  351. [(_ id #:all-defined-except ids form ...)
  352. (do-define-package stx stx)]
  353. [(_ id #:only ids form ...)
  354. (do-define-package stx stx)]
  355. [(_ id ids form ...)
  356. (do-define-package stx #'(define-package id #:only ids form ...))]))
  357. (define-syntax (package-begin stx)
  358. (syntax-case stx ()
  359. [(_ form ...)
  360. (do-define-package stx #'(define-package #f #:begin () form ...))]))
  361. (define-for-syntax (do-open stx define-syntaxes-id)
  362. (syntax-case stx ()
  363. [(_ pack-id)
  364. (let ([id #'pack-id])
  365. (unless (identifier? id)
  366. (raise-syntax-error #f
  367. "expected an identifier for a package"
  368. stx
  369. id))
  370. (let ([v (syntax-local-value id (lambda () #f))])
  371. (unless (package? v)
  372. (raise-syntax-error #f
  373. "identifier is not bound to a package"
  374. stx
  375. id))
  376. (let ([introduce (syntax-local-make-delta-introducer
  377. (syntax-local-introduce id))])
  378. (with-syntax ([(intro ...)
  379. (map (lambda (i)
  380. (syntax-local-introduce
  381. (syntax-local-get-shadower
  382. (introduce i))))
  383. (map car ((package-exports v))))]
  384. [(defined ...)
  385. (map (lambda (v) (syntax-local-introduce (cdr v)))
  386. ((package-exports v)))]
  387. [((a . b) ...) (map (lambda (p)
  388. (cons (syntax-local-introduce (car p))
  389. (syntax-local-introduce (cdr p))))
  390. ((package-exports v)))]
  391. [(h ...) (map syntax-local-introduce ((package-hidden v)))])
  392. (syntax-property
  393. #`(#,define-syntaxes-id (intro ...)
  394. (let ([rev-map (lambda (x)
  395. (reverse-mapping
  396. 'pack-id
  397. x
  398. (list (cons (quote-syntax a)
  399. (quote-syntax b))
  400. ...)
  401. (list (quote-syntax h) ...)))])
  402. (values (make-rename-transformer #'defined rev-map)
  403. ...)))
  404. 'disappeared-use
  405. (syntax-local-introduce id))))))]))
  406. (define-syntax (open-package stx)
  407. (do-open stx #'define-syntaxes))
  408. (define-syntax (open*-package stx)
  409. (do-open stx #'define*-syntaxes))
  410. (define-for-syntax (package-exported-identifiers id)
  411. (let ([v (and (identifier? id)
  412. (syntax-local-value id (lambda () #f)))])
  413. (unless (package? v)
  414. (raise-type-error 'package-exported-identifiers "identifier bound to a package" id))
  415. (let ([introduce (syntax-local-make-delta-introducer
  416. (syntax-local-introduce id))])
  417. (map (lambda (i)
  418. (syntax-local-introduce
  419. (syntax-local-get-shadower
  420. (introduce (car i)))))
  421. ((package-exports v))))))
  422. (define-for-syntax (package-original-identifiers id)
  423. (let ([v (and (identifier? id)
  424. (syntax-local-value id (lambda () #f)))])
  425. (unless (package? v)
  426. (raise-type-error 'package-exported-identifiers "identifier bound to a package" id))
  427. (map cdr ((package-exports v)))))