library-group.scm 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. ;;; Library-group expander
  2. ;;; Copyright (C) 2024 Igalia, S.L.
  3. ;;;
  4. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  5. ;;; you may not use this file except in compliance with the License.
  6. ;;; You may obtain a copy of the License at
  7. ;;;
  8. ;;; http://www.apache.org/licenses/LICENSE-2.0
  9. ;;;
  10. ;;; Unless required by applicable law or agreed to in writing, software
  11. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  12. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ;;; See the License for the specific language governing permissions and
  14. ;;; limitations under the License.
  15. ;;; Commentary:
  16. ;;;
  17. ;;; Parser, linker, and expander for `library-group` form.
  18. ;;;
  19. ;;; Code:
  20. (define-module (hoot library-group)
  21. #:use-module (ice-9 match)
  22. #:use-module (language tree-il)
  23. #:use-module (language tree-il primitives)
  24. #:use-module ((srfi srfi-1) #:select (append-map partition fold))
  25. #:use-module (srfi srfi-9)
  26. #:use-module ((system syntax internal) #:select (syntax? syntax-sourcev))
  27. #:export (library-group?
  28. parse-library
  29. parse-library-group
  30. link-library-group
  31. expand-library-group))
  32. (define-record-type <iset-library>
  33. (make-iset-library name version)
  34. iset-library?
  35. (name iset-library-name)
  36. (version iset-library-version))
  37. (define-record-type <iset-only>
  38. (make-iset-only iset ids)
  39. only?
  40. (iset iset-only-iset)
  41. (ids iset-only-ids))
  42. (define-record-type <iset-except>
  43. (make-iset-except iset ids)
  44. iset-except?
  45. (iset iset-except-iset)
  46. (ids iset-except-ids))
  47. (define-record-type <iset-rename>
  48. (make-iset-rename iset renamings)
  49. iset-rename?
  50. (iset iset-rename-iset)
  51. (renamings iset-rename-renamings))
  52. (define-record-type <iset-prefix>
  53. (make-iset-prefix iset prefix)
  54. iset-prefix?
  55. (iset iset-prefix-iset)
  56. (prefix iset-prefix-prefix))
  57. (define-record-type <library>
  58. (make-library src name version trusted? exports isets body)
  59. library?
  60. (src library-src)
  61. (name library-name)
  62. (version library-version)
  63. (trusted? library-trusted?)
  64. (exports library-exports)
  65. (isets library-isets)
  66. (body library-body))
  67. (define-record-type <program>
  68. (make-program src trusted? isets body)
  69. program?
  70. (src program-src)
  71. (trusted? program-trusted?)
  72. (isets program-isets)
  73. (body program-body))
  74. (define-record-type <library-group>
  75. (make-library-group src libraries program)
  76. library-group?
  77. (src library-group-src)
  78. (libraries library-group-libraries)
  79. (program library-group-program))
  80. (define imported-library-name
  81. (match-lambda
  82. (($ <iset-only> iset select) (imported-library-name iset))
  83. (($ <iset-except> iset hide) (imported-library-name iset))
  84. (($ <iset-rename> iset renamings) (imported-library-name iset))
  85. (($ <iset-prefix> iset prefix) (imported-library-name iset))
  86. (($ <iset-library> name version) name)))
  87. (define (id? x) (symbol? x))
  88. (define (name-component? x) (id? x))
  89. (define (version-component? x) (and (exact-integer? x) (not (negative? x))))
  90. (define (name-matches? stx sym)
  91. (eq? (syntax->datum stx) sym))
  92. (define-syntax-rule (symbolic-match? name)
  93. (name-matches? #'name 'name))
  94. (define parse-name+version
  95. (match-lambda
  96. (((? name-component? name) ... ((? version-component? version) ...))
  97. (values name version))
  98. (((? name-component? name) ...)
  99. (values name '()))))
  100. (define (includes-forbidden filename)
  101. (error "library-group include clause forbidden" filename))
  102. (define (parse-imports import-sets)
  103. (define parse-import-set
  104. (match-lambda
  105. ((head . tail)
  106. (match head
  107. ('only
  108. (match tail
  109. ((iset (? id? select) ...)
  110. (make-iset-only (parse-import-set iset) select))))
  111. ('except
  112. (match tail
  113. ((iset (? id? hide) ...)
  114. (make-iset-except (parse-import-set iset) hide))))
  115. ('prefix
  116. (match tail
  117. ((iset (? id? prefix))
  118. (make-iset-prefix (parse-import-set iset) prefix))))
  119. ('rename
  120. (match tail
  121. ((iset ((? id? from) (? id? to)) ...)
  122. (make-iset-rename (parse-import-set iset) (map cons from to)))))
  123. ('library
  124. (match tail
  125. ((name+version)
  126. (call-with-values (lambda ()
  127. (parse-name+version name+version))
  128. (lambda (name version)
  129. (make-iset-library name version))))))
  130. (_
  131. (parse-import-set `(library (,head . ,tail))))))))
  132. (map (match-lambda
  133. ;; Strip level.
  134. (('for iset level ...) (parse-import-set iset))
  135. (iset (parse-import-set iset)))
  136. import-sets))
  137. (define (parse-r6rs-library form trusted?)
  138. "Given the R6RS library @var{form}, as a syntax object, parse out the
  139. imports and exports to a @code{library}."
  140. (define (parse-exports exports)
  141. ;; -> ((local . public) ...)
  142. (map (match-lambda
  143. ((? id? id) (cons id id))
  144. (('rename (? id? from) (? id? to)) (cons from to)))
  145. exports))
  146. (syntax-case form ()
  147. ((library (name ...)
  148. (export export-spec ...)
  149. (import import-spec ...)
  150. body ...)
  151. (and (symbolic-match? library)
  152. (symbolic-match? export)
  153. (symbolic-match? import))
  154. (let ()
  155. (define src
  156. (and (syntax? #'library) (syntax-sourcev #'library)))
  157. (define-values (modname version)
  158. (parse-name+version (syntax->datum #'(name ...))))
  159. (define exports
  160. (parse-exports (syntax->datum #'(export-spec ...))))
  161. (define imports
  162. (parse-imports (syntax->datum #'(import-spec ...))))
  163. (make-library src modname version trusted? exports imports
  164. #'(body ...))))))
  165. (define (convert-sloppy-keyword x)
  166. (if (symbol? x)
  167. (let ((str (symbol->string x)))
  168. (if (string-prefix? ":" str)
  169. (symbol->keyword (string->symbol (substring str 1)))
  170. x))
  171. x))
  172. (define (parse-guile-import ispec)
  173. (define (parse-args args)
  174. (let lp ((args args) (select #f) (hide #f) (prefix #f) (version #f))
  175. (match args
  176. (()
  177. (values select (or hide '()) prefix (or version '())))
  178. (((= convert-sloppy-keyword kw) . args)
  179. (unless (keyword? kw)
  180. (syntax-violation 'use-module "expected a keyword argument" ispec
  181. (datum->syntax ispec kw)))
  182. (match args
  183. ((val . args)
  184. (match kw
  185. (#:select
  186. (when select
  187. (syntax-violation 'use-module "too many #:select clauses"
  188. ispec))
  189. (lp args
  190. (match val
  191. (((or (? id?) ((? id?) . (? id?))) ...) val)
  192. (_
  193. (syntax-violation 'use-module "bad #:select declaration"
  194. ispec val)))
  195. hide prefix version))
  196. (#:hide
  197. (when hide
  198. (syntax-violation 'use-module "too many #:hide clauses"
  199. ispec))
  200. (lp args select
  201. (match val
  202. (((or (? id?) ((? id?) . (? id?))) ...) val)
  203. (_
  204. (syntax-violation 'use-module "bad #:select declaration"
  205. ispec val)))
  206. prefix version))
  207. (#:renamer
  208. (when prefix
  209. (syntax-violation 'use-module "too many #:renamer/#:prefix clauses"
  210. ispec))
  211. (lp args select hide
  212. (match val
  213. (#f #f)
  214. (('symbol-prefix-proc ('quote prefix)) prefix)
  215. (else
  216. (syntax-violation 'use-module "unsupported #:renamer clause"
  217. ispec val)))
  218. version))
  219. (#:prefix
  220. (when prefix
  221. (syntax-violation 'use-module "too many #:renamer/#:prefix clauses"
  222. ispec))
  223. (lp args select hide
  224. (match val
  225. (#f #f)
  226. ((? id?) val)
  227. (else
  228. (syntax-violation 'use-module "invalid #:prefix"
  229. ispec val)))
  230. version))
  231. (#:version
  232. (when version
  233. (syntax-violation 'use-module "too many #:version clauses"
  234. ispec))
  235. (lp args select hide prefix
  236. (match val
  237. (((? version-component?) ...) val)
  238. (else
  239. (syntax-violation 'use-module "invalid #:version"
  240. ispec val)))))
  241. (_
  242. (syntax-violation 'use-module "unrecognized keyword arg"
  243. ispec kw))))
  244. (_
  245. (syntax-violation 'use-module "missing keyword argument" ispec
  246. kw)))))))
  247. (match (syntax->datum ispec)
  248. (((? id? mod) ...)
  249. (make-iset-library mod '()))
  250. ((((? id? mod) ...) arg ...)
  251. (call-with-values (lambda () (parse-args arg))
  252. (lambda (select hide prefix version)
  253. (let* ((iset (make-iset-library mod version))
  254. (iset (if (null? hide)
  255. iset
  256. (make-iset-except iset hide)))
  257. (iset (if select
  258. (make-iset-only
  259. iset
  260. (map (match-lambda
  261. ((from . to) from)
  262. (var var))
  263. select))
  264. iset))
  265. (iset (if (and select (or-map pair? select))
  266. (make-iset-rename
  267. iset
  268. (filter pair? select))
  269. iset))
  270. (iset (if prefix
  271. (make-iset-prefix iset prefix)
  272. iset)))
  273. iset))))
  274. (_
  275. (syntax-violation 'use-module "invalid guile module import" ispec))))
  276. (define* (finish-guile-imports imports #:key pure?)
  277. (if pure?
  278. imports
  279. (cons (make-iset-library '(guile) '()) imports)))
  280. (define (parse-guile-library head body trusted?)
  281. (define (parse-exports exports)
  282. ;; -> ((local . public) ...)
  283. (map (match-lambda
  284. ((? id? id) (cons id id))
  285. (((? id? from) . (? id? to)) (cons from to)))
  286. exports))
  287. (define (parse-autoload modname bindings)
  288. (match (syntax->datum modname)
  289. (((? id? modname) ...)
  290. (match (syntax->datum bindings)
  291. (((? id? bindings) ...)
  292. (make-iset-only (make-iset-library modname '()) bindings))
  293. (_
  294. (syntax-violation 'define-module "bad #:autoload bindings"
  295. head bindings))))
  296. (_
  297. (syntax-violation 'define-module "bad #:autoload module name"
  298. head modname))))
  299. (define (parse-define-module-args args)
  300. (let parse ((args args)
  301. (imports '()) (exports '()) (version #f) (pure? #f))
  302. (syntax-case args ()
  303. (()
  304. (values (finish-guile-imports (reverse imports) #:pure? pure?)
  305. (reverse exports)
  306. version))
  307. ((kw . args)
  308. (match (convert-sloppy-keyword (syntax->datum #'kw))
  309. (#:pure
  310. (parse #'args imports exports version #t))
  311. (#:no-backtrace
  312. ;; Ignore.
  313. (parse #'args imports exports version pure?))
  314. ((? keyword? kw')
  315. (syntax-case #'args ()
  316. ((val . args)
  317. (match kw'
  318. (#:version
  319. (when version
  320. (syntax-violation 'define-module "duplicate #:version"
  321. head #'val))
  322. (match (syntax->datum #'val)
  323. (((? version-component? version) ...)
  324. (parse #'args imports exports version pure?))
  325. (_
  326. (syntax-violation 'define-module "invalid #:version"
  327. head #'val))))
  328. (#:duplicates
  329. (syntax-violation 'define-module
  330. "#:duplicates not yet implemented"
  331. head #'val))
  332. (#:filename
  333. ;; Ignore.
  334. (parse #'args imports exports version pure?))
  335. (#:declarative?
  336. (syntax-case #'val ()
  337. (#t (parse #'args imports exports version pure?))
  338. (_
  339. (syntax-violation
  340. 'define-module
  341. "library-group only supports modules with #:declarative? #t"
  342. head #'val))))
  343. (#:use-module
  344. (let ((ispec (parse-guile-import #'val)))
  345. (parse #'args (cons ispec imports) exports version pure?)))
  346. (#:use-syntax
  347. (syntax-violation 'define-module "#:use-syntax not supported"
  348. head #'val))
  349. ((or #:export #:re-export
  350. #:export-syntax #:re-export-syntax
  351. #:replace #:replace-syntax
  352. #:re-export-and-replace)
  353. (syntax-case #'val ()
  354. ((spec ...)
  355. (parse
  356. #'args imports
  357. (fold
  358. (lambda (spec exports)
  359. (syntax-case spec ()
  360. (id
  361. (id? (syntax->datum #'id))
  362. (acons (syntax->datum #'id) (syntax->datum #'id)
  363. exports))
  364. ((from . to)
  365. (and (id? (syntax->datum #'from))
  366. (id? (syntax->datum #'to)))
  367. (acons (syntax->datum #'from) (syntax->datum #'to)
  368. exports))
  369. (_
  370. (syntax-violation 'define-module "invalid export"
  371. head spec))))
  372. exports #'(spec ...))
  373. version pure?))
  374. (_
  375. (syntax-violation 'define-module "invalid export list"
  376. head #'val))))
  377. (#:autoload
  378. (syntax-case #'args ()
  379. ((bindings . args)
  380. (let ((ispec (parse-autoload #'val #'bindings)))
  381. (parse #'args (cons ispec imports) exports version pure?)))
  382. (_
  383. (syntax-violation 'define-module "missing #:autoload bindings"
  384. head #'(val . args)))))
  385. (_
  386. (syntax-violation 'define-module "unrecognized keyword arg"
  387. head #'kw))))
  388. (_
  389. (syntax-violation 'define-module "missing value for keyword arg"
  390. head #'kw))))
  391. (_
  392. (syntax-violation 'define-module "expected a keyword arg"
  393. head #'kw))))
  394. (_ (syntax-violation 'define-module "invalid form" head)))))
  395. (syntax-case head ()
  396. ((define-module (modname ...) arg ...)
  397. (and-map id? (syntax->datum #'(modname ...)))
  398. (call-with-values (lambda () (parse-define-module-args #'(arg ...)))
  399. (lambda (imports exports version)
  400. (define src
  401. (and (syntax? #'define-module) (syntax-sourcev #'define-module)))
  402. (make-library src (syntax->datum #'(modname ...)) version trusted?
  403. exports imports body))))
  404. (_
  405. (syntax-violation 'define-module "invalid define-module form" head))))
  406. (define (parse-library forms trusted?)
  407. "Parse @var{forms} to a @code{<library>} record."
  408. (syntax-case forms ()
  409. (((library . body))
  410. (symbolic-match? library)
  411. (parse-r6rs-library #'(library . body) trusted?))
  412. (((define-module modname . modargs) . body)
  413. (symbolic-match? define-module)
  414. (parse-guile-library #'(define-module modname . modargs) #'body
  415. trusted?))
  416. (_
  417. (error "invalid module forms" forms))))
  418. (define* (parse-library-group form #:key (include-file includes-forbidden))
  419. "Parse a @code{library-group} form to a @code{<library-group>} record,
  420. processing includes. No other expansion or analysis is performed beyond
  421. syntactic validity."
  422. (define* (parse forms libraries #:key (trusted? #f))
  423. "For each form in @var{forms}, which should be a list of syntax objects,
  424. process any includes, collecting the prefix of @code{<library>} forms
  425. and then parsing the tail @code{<program>}, or @code{#f} if there is no
  426. program."
  427. (syntax-case forms ()
  428. (() (values (reverse libraries) #f))
  429. ((form . forms)
  430. (syntax-case #'form ()
  431. (#:untrusted
  432. (parse #'forms libraries #:trusted? #f))
  433. ((library . _)
  434. (symbolic-match? library)
  435. (parse #'forms (cons (parse-r6rs-library #'form trusted?) libraries)
  436. #:trusted? trusted?))
  437. ((define-library . _)
  438. (symbolic-match? define-library)
  439. (error "R7RS libraries not yet supported"))
  440. ((include filename)
  441. (symbolic-match? include)
  442. (let ((included (include-file (syntax->datum #'filename))))
  443. (syntax-case included ()
  444. (((define-module modname . modargs) . body)
  445. (symbolic-match? define-module)
  446. (parse #'forms
  447. (cons (parse-guile-library
  448. #'(define-module modname . modargs) #'body
  449. trusted?)
  450. libraries)
  451. #:trusted? trusted?))
  452. (_
  453. (parse (append included #'forms) libraries
  454. #:trusted? trusted?)))))
  455. ((import import-spec ...)
  456. (symbolic-match? import)
  457. (values (reverse libraries)
  458. (make-program #f trusted?
  459. (parse-imports
  460. (syntax->datum #'(import-spec ...)))
  461. #'forms)))
  462. ((use-modules import-spec ...)
  463. (symbolic-match? use-modules)
  464. (values (reverse libraries)
  465. (make-program #f trusted?
  466. (finish-guile-imports
  467. (map parse-guile-import #'(import-spec ...))
  468. #:pure? #f)
  469. #'forms)))))))
  470. (syntax-case form ()
  471. ((library-group form ...)
  472. (symbolic-match? library-group)
  473. (let ((src (and (syntax? #'library-group)
  474. (syntax-sourcev #'library-group))))
  475. (call-with-values (lambda () (parse #'(form ...) '() #:trusted? #t))
  476. (lambda (libraries program)
  477. (make-library-group src libraries program)))))
  478. (_
  479. (error "invalid library-group" form))))
  480. (define* (link-library-group group #:key
  481. (load-library (lambda (name) #f))
  482. (allow-dangling-import? (lambda (name) #f)))
  483. (define linked '()) ;; List of libraries.
  484. (define by-name (make-hash-table))
  485. (define (link-library! library)
  486. (let ((name (library-name library)))
  487. (when (hash-ref by-name name)
  488. (error "duplicate library definition" name))
  489. (hash-set! by-name name 'linking)
  490. (for-each link-import! (library-isets library))
  491. (set! linked (cons library linked))
  492. (hash-set! by-name name 'linked)))
  493. (define (link-import! iset)
  494. (let ((name (imported-library-name iset)))
  495. (match (hash-ref by-name name 'unvisited)
  496. ('linked (values))
  497. ('linking (error "cycle in module graph" name))
  498. ('unvisited
  499. (cond
  500. ((load-library name) => link-library!)
  501. ((allow-dangling-import? name) (values))
  502. (else (error "module not found" name)))))))
  503. (match group
  504. (($ <library-group> src libraries program)
  505. (for-each link-library! libraries)
  506. (when program (for-each link-import! (program-isets program)))
  507. (make-library-group src (reverse linked) program))))
  508. (define-record-type <import>
  509. (make-import modname exported-name imported-name)
  510. import?
  511. (modname import-modname)
  512. (exported-name exported-name)
  513. (imported-name imported-name))
  514. (define-record-type <lexical>
  515. (make-lexical sym)
  516. lexical?
  517. (sym lexical-sym))
  518. (define-record-type <primitive>
  519. (make-primitive name)
  520. primitive?
  521. (name primitive-name))
  522. (define-record-type <expand-time-value>
  523. (make-expand-time-value)
  524. expand-time-value?)
  525. ;; <value> := <lexical>
  526. ;; | <primitive>
  527. ;; | <expand-time-value>
  528. (define-record-type <module-definitions>
  529. (make-module-definitions private public)
  530. module-definitions?
  531. ;; Hash table of symbol -> <value>.
  532. (private module-private-definitions)
  533. ;; Hash table of symbol -> <value>.
  534. (public module-public-definitions))
  535. (define-record-type <definition>
  536. (make-definition name sym val)
  537. definition?
  538. (name definition-name)
  539. (sym definition-sym)
  540. (val definition-val))
  541. (define-record-type <statement>
  542. (make-statement exp)
  543. statement?
  544. (exp statement-exp))
  545. ;; FIXME: Get this exported from (language tree-il primitives).
  546. (define (primitive-for-variable box)
  547. (hashq-ref (@@ (language tree-il primitives) *interesting-primitive-vars*)
  548. box))
  549. (define (expand-library call-with-target mod form)
  550. "Expand the syntax object @var{form} in the module @var{mod}.
  551. The term will be expanded twice: once to create the expand-time module,
  552. which will then be evaluated directly, and once to residualize a Tree-IL
  553. term for the compilation unit.
  554. Syntax transformers (macros) will be evaluated at expansion-time, and
  555. not residualized into the compilation unit."
  556. (save-module-excursion
  557. (lambda ()
  558. (set-current-module mod)
  559. (primitive-eval (macroexpand form 'e '(compile eval)))
  560. (call-with-target
  561. (lambda () (macroexpand form 'c '()))))))
  562. (define (expand-program call-with-target mod form)
  563. "Expand the syntax object @var{form} in the module @var{mod}.
  564. Syntax transformers (macros) will be evaluated at expansion-time, and
  565. not residualized into the compilation unit."
  566. (save-module-excursion
  567. (lambda ()
  568. (set-current-module mod)
  569. (call-with-target
  570. (lambda () (macroexpand form 'c '(compile)))))))
  571. (define* (expand-library-group group #:key
  572. (call-with-target (lambda (f) (f)))
  573. (primitives #f))
  574. "Take a @code{<library-group>} record and expand it to a big
  575. @code{letrec*}.
  576. The libraries in the group are expanded one-by-one. Expanding a library
  577. residualises a Tree-IL AST node as part of the compilation unit, and
  578. additionally populates a compile-time host module with definitions. If
  579. expanding a module needs compile-time values from another module, it
  580. uses the bindings in the host module.
  581. All definitions and expressions in the expanded libraries are then
  582. rewritten to be part of a big @code{letrec*}, and top-level and module
  583. references in those definitions and expressions are rewritten to use
  584. lexical references.
  585. The final program in the @code{<library-group>} is given the same
  586. treatment, except that its final expression (if any) is evaluated in
  587. tail position."
  588. ;; A mapping from module,name,public? tuple to <binding> record, for
  589. ;; all modules in the library group.
  590. (define module-definitions (make-hash-table))
  591. (define (add-module-definitions! modname)
  592. (when (hash-ref module-definitions modname)
  593. (error "duplicate module" modname))
  594. (define defs
  595. (make-module-definitions (make-hash-table) (make-hash-table)))
  596. (hash-set! module-definitions modname defs)
  597. defs)
  598. (define (lookup-module-definitions modname)
  599. (or (hash-ref module-definitions modname)
  600. (error "unknown module" modname)))
  601. (define (add-definition! defs name public? value)
  602. (match defs
  603. (($ <module-definitions> private public)
  604. (let ((t (if public? public private)))
  605. (when (hashq-ref t name)
  606. (error "duplicate definition" name))
  607. (hashq-set! t name value)))))
  608. (define (lookup-definition defs name public?)
  609. (match defs
  610. (($ <module-definitions> private public)
  611. (hashq-ref (if public? public private) name))))
  612. ;; Add definitions from primitive module.
  613. (when primitives
  614. (let ((defs (add-module-definitions! primitives)))
  615. (module-for-each
  616. (lambda (name box)
  617. (add-definition! defs name #t
  618. (match (primitive-for-variable box)
  619. (#f (make-expand-time-value))
  620. (name (make-primitive name)))))
  621. (resolve-interface primitives))))
  622. (define (parse-isets isets trusted?)
  623. (define parse-iset
  624. (match-lambda
  625. (($ <iset-only> iset select)
  626. (filter (match-lambda
  627. (($ <import> mod-name exported imported)
  628. (memq imported select)))
  629. (parse-iset iset)))
  630. (($ <iset-except> iset hide)
  631. (filter (match-lambda
  632. (($ <import> mod-name exported imported)
  633. (not (memq imported hide))))
  634. (parse-iset iset)))
  635. (($ <iset-prefix> iset prefix)
  636. (map (match-lambda
  637. (($ <import> mod-name exported imported)
  638. (let ((renamed (symbol-append prefix imported)))
  639. (make-import mod-name exported renamed))))
  640. (parse-iset iset)))
  641. (($ <iset-rename> iset renamings)
  642. (map (match-lambda
  643. (($ <import> mod-name exported imported)
  644. (define renamed
  645. (or (assq-ref renamings imported) imported))
  646. (make-import mod-name exported renamed)))
  647. (parse-iset iset)))
  648. (($ <iset-library> modname version)
  649. (unless (null? version)
  650. (error "version references unsupported"))
  651. (when (equal? modname primitives)
  652. (unless trusted?
  653. (error "untrusted module cannot import primitives")))
  654. (let ((exports (module-public-definitions
  655. (lookup-module-definitions modname))))
  656. (define (id<? a b)
  657. (string<? (symbol->string a) (symbol->string b)))
  658. (define (import<? a b)
  659. (id<? (exported-name a) (exported-name b)))
  660. (sort (hash-map->list (lambda (name binding)
  661. (make-import modname name name))
  662. exports)
  663. import<?)))))
  664. (append-map parse-iset isets))
  665. ;; Because each invocation of expand-library-group gets its own
  666. ;; namespace, we don't have to deal with lingering definitions from
  667. ;; any previous expansion; all modules defined by this compilation
  668. ;; unit are fresh. This also allows expansion to happen in parallel.
  669. (define namespace (gensym "%library-group"))
  670. (define (host-modname? modname)
  671. (match modname
  672. (() #f)
  673. ((head . tail)
  674. (not (eq? namespace head)))))
  675. (define (annotate-modname modname)
  676. (if (equal? modname primitives)
  677. modname
  678. (cons namespace modname)))
  679. (define (strip-modname modname)
  680. (match modname
  681. (((? (lambda (x) (eq? x namespace))) . modname) modname)
  682. (_
  683. (unless (equal? modname primitives)
  684. (error "unexpected modname" modname))
  685. modname)))
  686. (define (make-expand-time-module modname filename version imports exports)
  687. "Create the host module in which to store compile-time library
  688. definitions. The module may import other host libraries."
  689. (define imports-by-module (make-hash-table))
  690. (define (add-import! modname exported imported)
  691. (define tail (hash-ref imports-by-module modname '()))
  692. (define entry (cons exported imported))
  693. (hash-set! imports-by-module modname (cons entry tail)))
  694. (for-each (match-lambda
  695. (($ <import> modname exported imported)
  696. (add-import! modname exported imported)))
  697. imports)
  698. (define (id<? a b)
  699. (string<? (symbol->string a) (symbol->string b)))
  700. (define (modname<? a b)
  701. (match a
  702. (() #t)
  703. ((a . a*) (match b
  704. (() #f)
  705. ((b . b*) (and (id<? a b) (modname<? a* b*)))))))
  706. (define module-import-decls
  707. (sort (hash-map->list (lambda (modname entries)
  708. (list (annotate-modname modname)
  709. #:select
  710. (sort entries
  711. (lambda (a b)
  712. (id<? (car a) (car b))))))
  713. imports-by-module)
  714. (lambda (a b)
  715. (modname<? (car a) (car b)))))
  716. (define-values (module-export-decls module-re-export-decls)
  717. (let ()
  718. (define imports-by-name (make-hash-table))
  719. (for-each (match-lambda
  720. ((and import ($ <import> _ _ imported))
  721. (match (hashq-ref imports-by-name imported)
  722. (#f (hashq-set! imports-by-name imported import))
  723. (existing
  724. (error "duplicate imports" existing import)))))
  725. imports)
  726. (partition (match-lambda
  727. ((local . public) (not (hashq-ref imports-by-name local))))
  728. exports)))
  729. (define-module* (annotate-modname modname)
  730. #:filename filename
  731. #:pure #t
  732. #:version version
  733. #:imports module-import-decls
  734. #:exports module-export-decls
  735. #:re-exports module-re-export-decls
  736. #:declarative? #t))
  737. (define (tree-il->reversed-bindings exp modname imports exports bindings)
  738. "Given the expanded library @var{exp}, as a Tree-IL node, transform it to
  739. a sequence of definitions and expressions, as @code{<binding>} nodes.
  740. Rewrite references to other top-level bindings to refer to primitive or
  741. lexical definitions. Append those @code{<binding>} nodes to
  742. @var{bindings}, in reverse order."
  743. ;; Make defs for module.
  744. (define defs (add-module-definitions! modname))
  745. (define (has-expand-time-value? name)
  746. (module-variable (resolve-module (annotate-modname modname)) name))
  747. ;; Add definitions for imports.
  748. (for-each (match-lambda
  749. (($ <import> imod exported imported)
  750. (match (lookup-definition (lookup-module-definitions imod)
  751. exported #t)
  752. (#f (error "unknown import?" imod exported))
  753. (value (add-definition! defs imported #f value)))))
  754. imports)
  755. (define (tree-il-for-each f exp)
  756. (define fold (make-tree-il-folder))
  757. (fold exp (lambda (exp) (values)) f))
  758. ;; Prohibit set! to imports. Check module on expanded toplevel defs
  759. ;; and uses.
  760. (tree-il-for-each (match-lambda
  761. (($ <toplevel-define> src mod name val)
  762. (unless (equal? (strip-modname mod) modname)
  763. (error "unexpected mod" exp mod modname))
  764. (values))
  765. (($ <toplevel-ref> src mod name)
  766. (unless (equal? (strip-modname mod) modname)
  767. (error "unexpected mod" exp mod modname))
  768. (values))
  769. (($ <toplevel-set> src mod name val)
  770. (unless (equal? (strip-modname mod) modname)
  771. (error "unexpected mod" exp mod modname))
  772. (when (lookup-definition defs name #f)
  773. (error "set! to imported binding" src name))
  774. (values))
  775. (_ (values)))
  776. exp)
  777. ;; Record local definitions and allocate lexicals for them.
  778. (tree-il-for-each (match-lambda
  779. (($ <toplevel-define> src mod name exp)
  780. (when (lookup-definition defs name #f)
  781. (error "duplicate definition" modname name))
  782. (add-definition! defs name #f (make-lexical (gensym "top")))
  783. (values))
  784. (_ (values)))
  785. exp)
  786. ;; Check for unbound top-levels.
  787. (tree-il-for-each (match-lambda
  788. (($ <toplevel-ref> src mod name)
  789. (unless (lookup-definition defs name #f)
  790. (error "unbound top-level" src name))
  791. (values))
  792. (($ <toplevel-set> src mod name val)
  793. (unless (lookup-definition defs name #f)
  794. (error "unbound top-level" src name))
  795. (values))
  796. (($ <module-ref> src mod name public?)
  797. (unless (or (host-modname? mod)
  798. (let ((defs (lookup-module-definitions
  799. (strip-modname mod))))
  800. (lookup-definition defs name public?)))
  801. (error "unbound macro-introduced top-level for module"
  802. src (strip-modname mod) name))
  803. (values))
  804. (($ <module-set> src mod name public? val)
  805. (unless (let ((defs (lookup-module-definitions
  806. (strip-modname mod))))
  807. (lookup-definition defs name public?))
  808. (error "unbound macro-introduced top-level for module"
  809. src (strip-modname mod) name))
  810. (values))
  811. (_ (values)))
  812. exp)
  813. ;; Find local definitions for exports.
  814. (for-each (match-lambda
  815. ((local . exported)
  816. (match (lookup-definition defs local #f)
  817. (#f
  818. ;; An export without a binding in the compilation
  819. ;; unit. Perhaps it is an expansion-time binding.
  820. (unless (has-expand-time-value? local)
  821. (error "missing definition for export"
  822. modname local exported))
  823. (let ((val (make-expand-time-value)))
  824. (add-definition! defs local #f val)
  825. (add-definition! defs exported #t val)))
  826. (val (add-definition! defs exported #t val)))))
  827. exports)
  828. ;; Resolve references to local definitions and residualized
  829. ;; module-private definitions to lexical-ref or primitive-ref.
  830. (define (visit-expr exp)
  831. (post-order
  832. (lambda (exp)
  833. (match exp
  834. (($ <toplevel-ref> src mod name)
  835. (match (lookup-definition defs name #f)
  836. (($ <lexical> sym) (make-lexical-ref src name sym))
  837. (($ <primitive> name) (make-primitive-ref src name))
  838. (($ <expand-time-value>)
  839. (error "reference to expansion-time value in generated code"
  840. src modname name))))
  841. (($ <toplevel-set> src mod name val)
  842. (match (lookup-definition defs name #f)
  843. (($ <lexical> sym) (make-lexical-set src name sym val))
  844. (($ <expand-time-value>)
  845. (error "reference to expansion-time value in generated code"
  846. src modname name))))
  847. (($ <module-ref> src (? host-modname? mod) name #f)
  848. ;; A primitive reference introduced by a primitive syntax
  849. ;; expander.
  850. (match (primitive-for-variable
  851. (module-variable (resolve-module mod) name))
  852. (#f (error "can't find name for primitive reference" mod name))
  853. (name (make-primitive-ref src name))))
  854. (($ <module-ref> src mod name public?)
  855. (let ((defs (lookup-module-definitions (strip-modname mod))))
  856. (match (lookup-definition defs name public?)
  857. (($ <lexical> sym) (make-lexical-ref src name sym))
  858. (($ <primitive> name) (make-primitive-ref src name))
  859. (($ <expand-time-value>)
  860. (error "reference to expansion-time value in generated code"
  861. src mod name)))))
  862. (($ <module-set> src mod name public? val)
  863. (let ((defs (lookup-module-definitions (strip-modname mod))))
  864. (match (lookup-definition defs name public?)
  865. (($ <lexical> sym) (make-lexical-set src name sym val))
  866. (($ <expand-time-value>)
  867. (error "reference to expansion-time value in generated code"
  868. src mod name)))))
  869. (($ <toplevel-define>)
  870. (error "unexpected nested toplevel define" exp))
  871. (($ <call> src ($ <primitive-ref> _ name) args)
  872. (expand-primcall (make-primcall src name args)))
  873. (_ exp)))
  874. exp))
  875. ;; Walk the chain of <seq> and <toplevel-define> to extract
  876. ;; definitions and statements.
  877. (define (visit-top-level exp bindings)
  878. (match exp
  879. (($ <toplevel-define> src mod name val)
  880. (match (lookup-definition defs name #f)
  881. (($ <lexical> sym)
  882. (cons (make-definition name sym (visit-expr val))
  883. bindings))))
  884. (($ <seq> src head tail)
  885. (visit-top-level tail (visit-top-level head bindings)))
  886. ;; Could fold in let and letrec* bindings. Dunno.
  887. (_ (cons (make-statement (visit-expr exp)) bindings))))
  888. (visit-top-level exp bindings))
  889. (define (srcv-filename srcv)
  890. (match srcv
  891. (#f #f)
  892. (#(filename line column) filename)))
  893. (define (library->reversed-bindings library bindings)
  894. "Given the R6RS library @var{form}, as a syntax object, parse out the
  895. imports and exports, create a compile-time module, and expand the body
  896. of the library within that module. Add the residual definitions and
  897. expressions from the module to @var{bindings}, as in
  898. @code{tree-il->reversed-bindings}."
  899. (match library
  900. (($ <library> src modname version trusted? exports isets body)
  901. (define filename (srcv-filename src))
  902. (define imports (parse-isets isets trusted?))
  903. (define ctmod
  904. (make-expand-time-module modname filename version imports exports))
  905. (define expanded
  906. (expand-library call-with-target ctmod #`(begin . #,body)))
  907. (tree-il->reversed-bindings expanded modname imports exports
  908. bindings))))
  909. (define (program->reversed-bindings program bindings)
  910. "Same as @code{r6rs-library->reversed-bindings}, but for a program.
  911. @var{imports} is already parsed, as a list of @code{<import>}. A new
  912. module with a fresh name will be defined for the purposes of expanding "
  913. (match program
  914. (#f (cons (make-statement (make-void #f)) bindings))
  915. (($ <program> src trusted? isets body)
  916. (define modname (list (gensym "library-group-program")))
  917. (define filename (srcv-filename src))
  918. (define imports (parse-isets isets trusted?))
  919. (define ctmod
  920. (make-expand-time-module modname filename '() imports '()))
  921. (define expanded
  922. (expand-program call-with-target ctmod #`(begin . #,body)))
  923. (tree-il->reversed-bindings expanded modname imports '() bindings))))
  924. (define (ensure-tail-expression reversed-bindings)
  925. (match reversed-bindings
  926. ((($ <statement>) . _) reversed-bindings)
  927. (_
  928. (cons (make-statement (make-void #f)) reversed-bindings))))
  929. (define reversed-bindings
  930. (match group
  931. (($ <library-group> src libraries program)
  932. (ensure-tail-expression
  933. (program->reversed-bindings
  934. program
  935. (fold library->reversed-bindings '() libraries))))))
  936. (match reversed-bindings
  937. ((($ <statement> tail) . bindings)
  938. (let ((bindings (reverse bindings)))
  939. (make-letrec (library-group-src group)
  940. #t ; in-order?
  941. (map (match-lambda
  942. (($ <definition> name sym val) name)
  943. (($ <statement> exp) '_))
  944. bindings)
  945. (map (match-lambda
  946. (($ <definition> name sym val) sym)
  947. (($ <statement> exp) (gensym "_")))
  948. bindings)
  949. (map (match-lambda
  950. (($ <definition> name sym val) val)
  951. (($ <statement> exp)
  952. (if (void? exp)
  953. exp
  954. (make-seq #f exp (make-void #f)))))
  955. bindings)
  956. tail)))))