library-group.scm 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251
  1. ;;; Library-group expander
  2. ;;; Copyright (C) 2024, 2025 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 fold-right))
  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? duplicate-handler exports isets body)
  59. library?
  60. (src library-src)
  61. (name library-name)
  62. (version library-version)
  63. (trusted? library-trusted?)
  64. (duplicate-handler library-duplicate-handler)
  65. (exports library-exports)
  66. (isets library-isets)
  67. (body library-body))
  68. (define-record-type <program>
  69. (make-program src trusted? duplicate-handler isets body)
  70. program?
  71. (src program-src)
  72. (trusted? program-trusted?)
  73. (duplicate-handler program-duplicate-handler)
  74. (isets program-isets)
  75. (body program-body))
  76. (define-record-type <library-group>
  77. (make-library-group src libraries program)
  78. library-group?
  79. (src library-group-src)
  80. (libraries library-group-libraries)
  81. (program library-group-program))
  82. (define imported-library-name
  83. (match-lambda
  84. (($ <iset-only> iset select) (imported-library-name iset))
  85. (($ <iset-except> iset hide) (imported-library-name iset))
  86. (($ <iset-rename> iset renamings) (imported-library-name iset))
  87. (($ <iset-prefix> iset prefix) (imported-library-name iset))
  88. (($ <iset-library> name version) name)))
  89. (define (id? x) (symbol? x))
  90. (define (name-component? x) (id? x))
  91. (define (version-component? x) (and (exact-integer? x) (not (negative? x))))
  92. (define (name-matches? stx sym)
  93. (eq? (syntax->datum stx) sym))
  94. (define-syntax-rule (symbolic-match? name)
  95. (name-matches? #'name 'name))
  96. (define parse-name+version
  97. (match-lambda
  98. (((? name-component? name) ... ((? version-component? version) ...))
  99. (values name version))
  100. (((? name-component? name) ...)
  101. (values name '()))))
  102. (define (includes-forbidden filename)
  103. (error "library-group include clause forbidden" filename))
  104. (define (parse-imports import-sets)
  105. (define parse-import-set
  106. (match-lambda
  107. ((head . tail)
  108. (match head
  109. ('only
  110. (match tail
  111. ((iset (? id? select) ...)
  112. (make-iset-only (parse-import-set iset) select))))
  113. ('except
  114. (match tail
  115. ((iset (? id? hide) ...)
  116. (make-iset-except (parse-import-set iset) hide))))
  117. ('prefix
  118. (match tail
  119. ((iset (? id? prefix))
  120. (make-iset-prefix (parse-import-set iset) prefix))))
  121. ('rename
  122. (match tail
  123. ((iset ((? id? from) (? id? to)) ...)
  124. (make-iset-rename (parse-import-set iset) (map cons from to)))))
  125. ('library
  126. (match tail
  127. ((name+version)
  128. (call-with-values (lambda ()
  129. (parse-name+version name+version))
  130. (lambda (name version)
  131. (make-iset-library name version))))))
  132. (_
  133. (parse-import-set `(library (,head . ,tail))))))))
  134. (map (match-lambda
  135. ;; Strip level.
  136. (('for iset level ...) (parse-import-set iset))
  137. (iset (parse-import-set iset)))
  138. import-sets))
  139. (define (parse-r6rs-library form trusted?)
  140. "Given the R6RS library @var{form}, as a syntax object, parse out the
  141. imports and exports to a @code{library}."
  142. (define (parse-exports exports)
  143. ;; -> ((local . public) ...)
  144. (map (match-lambda
  145. ((? id? id) (cons id id))
  146. (('rename (? id? from) (? id? to)) (cons from to)))
  147. exports))
  148. (syntax-case form ()
  149. ((library (name ...)
  150. (export export-spec ...)
  151. (import import-spec ...)
  152. body ...)
  153. (and (symbolic-match? library)
  154. (symbolic-match? export)
  155. (symbolic-match? import))
  156. (let ()
  157. (define src
  158. (and (syntax? #'library) (syntax-sourcev #'library)))
  159. (define-values (modname version)
  160. (parse-name+version (syntax->datum #'(name ...))))
  161. (define exports
  162. (parse-exports (syntax->datum #'(export-spec ...))))
  163. (define imports
  164. (parse-imports (syntax->datum #'(import-spec ...))))
  165. (make-library src modname version trusted? forbid-duplicate-bindings
  166. exports imports #'(body ...))))))
  167. (define (parse-r7rs-library form trusted? include-file features)
  168. "Given the R7RS library @var{form}, as a syntax object, parse out the
  169. imports and exports to a @code{library}."
  170. (define (parse-exports exports)
  171. ;; -> ((local . public) ...)
  172. (map (match-lambda
  173. ((? id? id) (cons id id))
  174. (('rename (? id? from) (? id? to)) (cons from to)))
  175. exports))
  176. (define (include-files filenames tail)
  177. (fold-right (lambda (filename tail)
  178. (append (include-file filename) tail))
  179. tail
  180. filenames))
  181. (define (resolve-cond-expand form)
  182. (define (has-req? req)
  183. (match req
  184. (('and req ...)
  185. (and-map has-req? req))
  186. (('or req ...)
  187. (or-map has-req? req))
  188. (('not req)
  189. (not (has-req? req)))
  190. (('library lib-name)
  191. ;; FIXME: No libraries, for the time being.
  192. #f)
  193. ((? symbol? req)
  194. (memq req features))))
  195. (syntax-case form ()
  196. ((_ ce-clause ...)
  197. (let lp ((clauses #'(ce-clause ...)))
  198. (syntax-case clauses ()
  199. (()
  200. (syntax-violation 'cond-expand "Unfulfilled cond-expand" #'form))
  201. (((else decl ...))
  202. (symbolic-match? else)
  203. #'(decl ...))
  204. (((req decl ...) . clauses)
  205. (if (has-req? (syntax->datum #'req))
  206. #'(decl ...)
  207. (lp #'clauses))))))))
  208. (syntax-case form ()
  209. ((define-library (name ...) clause ...)
  210. (symbolic-match? define-library)
  211. (let ((src (and (syntax? #'library) (syntax-sourcev #'library))))
  212. (define-values (modname version)
  213. (parse-name+version (syntax->datum #'(name ...))))
  214. (let lp ((clauses #'(clause ...)) (exports '()) (imports '()) (body '()))
  215. (syntax-case clauses ()
  216. (()
  217. (make-library src modname version trusted? forbid-duplicate-bindings
  218. exports imports body))
  219. (((export spec ...) . clauses)
  220. (symbolic-match? export)
  221. (lp #'clauses
  222. (append (parse-exports (syntax->datum #'(spec ...))) exports)
  223. imports
  224. body))
  225. (((import spec ...) . clauses)
  226. (symbolic-match? import)
  227. (lp #'clauses
  228. exports
  229. (append (parse-imports (syntax->datum #'(spec ...)))
  230. imports)
  231. body))
  232. (((begin form ...) . clauses)
  233. (symbolic-match? begin)
  234. (lp #'clauses
  235. exports
  236. imports
  237. #`(form ... . #,body)))
  238. (((include filename ...) . clauses)
  239. (and (symbolic-match? include)
  240. (and-map string? #'(filename ...)))
  241. (lp #'clauses
  242. exports
  243. imports
  244. (include-files (syntax->datum #'(filename ...)) body)))
  245. (((include-ci filename ...) . clauses)
  246. (and (symbolic-match? include-ci)
  247. (and-map string? #'(filename ...)))
  248. (lp #'clauses
  249. exports
  250. imports
  251. ;; FIXME: Actually be case-insensitive!
  252. (include-files (syntax->datum #'(filename ...)) body)))
  253. (((include-library-definitions filename ...) . clauses)
  254. (and (symbolic-match? include-library-definitions)
  255. (and-map string? #'(filename ...)))
  256. (lp (include-files (syntax->datum #'(filename ...)) #'clauses)
  257. exports
  258. imports
  259. body))
  260. (((cond-expand . ce-clauses) . clauses)
  261. (symbolic-match? cond-expand)
  262. (lp (append (resolve-cond-expand #'(cond-expand . ce-clauses))
  263. #'clauses)
  264. exports
  265. imports
  266. body))))))))
  267. (define (convert-sloppy-keyword x)
  268. (if (symbol? x)
  269. (let ((str (symbol->string x)))
  270. (if (string-prefix? ":" str)
  271. (symbol->keyword (string->symbol (substring str 1)))
  272. x))
  273. x))
  274. (define (parse-guile-import ispec)
  275. (define (parse-args args)
  276. (let lp ((args args) (select #f) (hide #f) (prefix #f) (version #f))
  277. (match args
  278. (()
  279. (values select (or hide '()) prefix (or version '())))
  280. (((= convert-sloppy-keyword kw) . args)
  281. (unless (keyword? kw)
  282. (syntax-violation 'use-module "expected a keyword argument" ispec
  283. (datum->syntax ispec kw)))
  284. (match args
  285. ((val . args)
  286. (match kw
  287. (#:select
  288. (when select
  289. (syntax-violation 'use-module "too many #:select clauses"
  290. ispec))
  291. (lp args
  292. (match val
  293. (((or (? id?) ((? id?) . (? id?))) ...) val)
  294. (_
  295. (syntax-violation 'use-module "bad #:select declaration"
  296. ispec val)))
  297. hide prefix version))
  298. (#:hide
  299. (when hide
  300. (syntax-violation 'use-module "too many #:hide clauses"
  301. ispec))
  302. (lp args select
  303. (match val
  304. (((or (? id?) ((? id?) . (? id?))) ...) val)
  305. (_
  306. (syntax-violation 'use-module "bad #:select declaration"
  307. ispec val)))
  308. prefix version))
  309. (#:renamer
  310. (when prefix
  311. (syntax-violation 'use-module "too many #:renamer/#:prefix clauses"
  312. ispec))
  313. (lp args select hide
  314. (match val
  315. (#f #f)
  316. (('symbol-prefix-proc ('quote prefix)) prefix)
  317. (else
  318. (syntax-violation 'use-module "unsupported #:renamer clause"
  319. ispec val)))
  320. version))
  321. (#:prefix
  322. (when prefix
  323. (syntax-violation 'use-module "too many #:renamer/#:prefix clauses"
  324. ispec))
  325. (lp args select hide
  326. (match val
  327. (#f #f)
  328. ((? id?) val)
  329. (else
  330. (syntax-violation 'use-module "invalid #:prefix"
  331. ispec val)))
  332. version))
  333. (#:version
  334. (when version
  335. (syntax-violation 'use-module "too many #:version clauses"
  336. ispec))
  337. (lp args select hide prefix
  338. (match val
  339. (((? version-component?) ...) val)
  340. (else
  341. (syntax-violation 'use-module "invalid #:version"
  342. ispec val)))))
  343. (_
  344. (syntax-violation 'use-module "unrecognized keyword arg"
  345. ispec kw))))
  346. (_
  347. (syntax-violation 'use-module "missing keyword argument" ispec
  348. kw)))))))
  349. (match (syntax->datum ispec)
  350. (((? id? mod) ...)
  351. (make-iset-library mod '()))
  352. ((((? id? mod) ...) arg ...)
  353. (call-with-values (lambda () (parse-args arg))
  354. (lambda (select hide prefix version)
  355. (let* ((iset (make-iset-library mod version))
  356. (iset (if (null? hide)
  357. iset
  358. (make-iset-except iset hide)))
  359. (iset (if select
  360. (make-iset-only
  361. iset
  362. (map (match-lambda
  363. ((from . to) from)
  364. (var var))
  365. select))
  366. iset))
  367. (iset (if (and select (or-map pair? select))
  368. (make-iset-rename
  369. iset
  370. (filter pair? select))
  371. iset))
  372. (iset (if prefix
  373. (make-iset-prefix iset prefix)
  374. iset)))
  375. iset))))
  376. (_
  377. (syntax-violation 'use-module "invalid guile module import" ispec))))
  378. (define* (finish-guile-imports imports #:key pure?)
  379. (if pure?
  380. imports
  381. (cons (make-iset-library '(guile) '()) imports)))
  382. (define (make-guile-duplicate-handler duplicates)
  383. (define (symbol->duplicate-handler sym)
  384. (match sym
  385. ('check
  386. (lambda (name old new prev)
  387. (forbid-duplicate-bindings name old new)))
  388. ('first (lambda (name old new prev) (or prev old)))
  389. ('last (lambda (name old new prev) new))
  390. ('noop (lambda (name old new prev) #f))
  391. ;; FIXME: Implement Guile's replace logic.
  392. ('replace (lambda (name old new prev) new))
  393. ;; FIXME: Print warnings. As of writing, warnings will be
  394. ;; printed *twice* due to how library compilation works.
  395. ;; Also, we don't have the necessary data to know if we are
  396. ;; overriding a core binding.
  397. ('warn (lambda (name old new prev) #f))
  398. ('warn-override-core (lambda (name old new prev) #f))
  399. ;; TODO: We don't support GOOPS yet.
  400. ('merge-generics
  401. (lambda (name old new prev) (error "GOOPS is unsupported")))
  402. ('merge-accessors
  403. (lambda (name old new prev) (error "GOOPS is unsupported")))))
  404. (let ((handlers (map symbol->duplicate-handler duplicates)))
  405. (lambda (name old new)
  406. (let lp ((prev #f) (handlers handlers))
  407. (match handlers
  408. (() (or prev (error "unresolved duplicate definition" name)))
  409. ((handler . rest)
  410. (match (handler name old new prev)
  411. (#f (lp prev rest))
  412. (binding (lp binding rest)))))))))
  413. (define %default-guile-duplicate-handlers '(replace warn-override-core warn last))
  414. (define (parse-guile-library head body trusted?)
  415. (define (parse-exports exports)
  416. ;; -> ((local . public) ...)
  417. (map (match-lambda
  418. ((? id? id) (cons id id))
  419. (((? id? from) . (? id? to)) (cons from to)))
  420. exports))
  421. (define (parse-autoload modname bindings)
  422. (match (syntax->datum modname)
  423. (((? id? modname) ...)
  424. (match (syntax->datum bindings)
  425. (((? id? bindings) ...)
  426. (make-iset-only (make-iset-library modname '()) bindings))
  427. (_
  428. (syntax-violation 'define-module "bad #:autoload bindings"
  429. head bindings))))
  430. (_
  431. (syntax-violation 'define-module "bad #:autoload module name"
  432. head modname))))
  433. (define (duplicate-resolver? x)
  434. (memq x '(check first last noop replace warn warn-override-core
  435. merge-generics merge-accessors)))
  436. (define (parse-define-module-args args)
  437. (let parse ((args args)
  438. (imports '()) (exports '()) (version #f) (pure? #f)
  439. (duplicates %default-guile-duplicate-handlers))
  440. (syntax-case args ()
  441. (()
  442. (values (finish-guile-imports (reverse imports) #:pure? pure?)
  443. (reverse exports)
  444. version
  445. (make-guile-duplicate-handler duplicates)))
  446. ((kw . args)
  447. (match (convert-sloppy-keyword (syntax->datum #'kw))
  448. (#:pure
  449. (parse #'args imports exports version #t duplicates))
  450. (#:no-backtrace
  451. ;; Ignore.
  452. (parse #'args imports exports version pure? duplicates))
  453. ((? keyword? kw')
  454. (syntax-case #'args ()
  455. ((val . args)
  456. (match kw'
  457. (#:version
  458. (when version
  459. (syntax-violation 'define-module "duplicate #:version"
  460. head #'val))
  461. (match (syntax->datum #'val)
  462. (((? version-component? version) ...)
  463. (parse #'args imports exports version pure? duplicates))
  464. (_
  465. (syntax-violation 'define-module "invalid #:version"
  466. head #'val))))
  467. (#:duplicates
  468. (match (syntax->datum #'val)
  469. ((and ((? duplicate-resolver?) ..1) duplicates)
  470. (parse #'args imports exports version pure? duplicates))
  471. (_
  472. (syntax-violation 'define-module "invalid #:duplicates"
  473. head #'val))))
  474. (#:filename
  475. ;; Ignore.
  476. (parse #'args imports exports version pure? duplicates))
  477. (#:declarative?
  478. (syntax-case #'val ()
  479. (#t (parse #'args imports exports version pure? duplicates))
  480. (_
  481. (syntax-violation
  482. 'define-module
  483. "library-group only supports modules with #:declarative? #t"
  484. head #'val))))
  485. (#:use-module
  486. (let ((ispec (parse-guile-import #'val)))
  487. (parse #'args (cons ispec imports) exports version pure? duplicates)))
  488. (#:use-syntax
  489. (syntax-violation 'define-module "#:use-syntax not supported"
  490. head #'val))
  491. ((or #:export #:re-export
  492. #:export-syntax #:re-export-syntax
  493. #:replace #:replace-syntax
  494. #:re-export-and-replace)
  495. (syntax-case #'val ()
  496. ((spec ...)
  497. (parse
  498. #'args imports
  499. (fold
  500. (lambda (spec exports)
  501. (syntax-case spec ()
  502. (id
  503. (id? (syntax->datum #'id))
  504. (acons (syntax->datum #'id) (syntax->datum #'id)
  505. exports))
  506. ((from . to)
  507. (and (id? (syntax->datum #'from))
  508. (id? (syntax->datum #'to)))
  509. (acons (syntax->datum #'from) (syntax->datum #'to)
  510. exports))
  511. (_
  512. (syntax-violation 'define-module "invalid export"
  513. head spec))))
  514. exports #'(spec ...))
  515. version pure? duplicates))
  516. (_
  517. (syntax-violation 'define-module "invalid export list"
  518. head #'val))))
  519. (#:autoload
  520. (syntax-case #'args ()
  521. ((bindings . args)
  522. (let ((ispec (parse-autoload #'val #'bindings)))
  523. (parse #'args (cons ispec imports) exports version pure? duplicates)))
  524. (_
  525. (syntax-violation 'define-module "missing #:autoload bindings"
  526. head #'(val . args)))))
  527. (_
  528. (syntax-violation 'define-module "unrecognized keyword arg"
  529. head #'kw))))
  530. (_
  531. (syntax-violation 'define-module "missing value for keyword arg"
  532. head #'kw))))
  533. (_
  534. (syntax-violation 'define-module "expected a keyword arg"
  535. head #'kw))))
  536. (_ (syntax-violation 'define-module "invalid form" head)))))
  537. (syntax-case head ()
  538. ((define-module (modname ...) arg ...)
  539. (and-map id? (syntax->datum #'(modname ...)))
  540. (call-with-values (lambda () (parse-define-module-args #'(arg ...)))
  541. (lambda (imports exports version duplicate-handler)
  542. (define src
  543. (and (syntax? #'define-module) (syntax-sourcev #'define-module)))
  544. (make-library src (syntax->datum #'(modname ...)) version trusted?
  545. duplicate-handler exports imports body))))
  546. (_
  547. (syntax-violation 'define-module "invalid define-module form" head))))
  548. (define* (parse-library forms trusted? #:key (include-file includes-forbidden)
  549. (features '()))
  550. "Parse @var{forms} to a @code{<library>} record."
  551. (syntax-case forms ()
  552. (((library . body))
  553. (symbolic-match? library)
  554. (parse-r6rs-library #'(library . body) trusted?))
  555. (((define-library . body))
  556. (symbolic-match? define-library)
  557. (parse-r7rs-library #'(define-library . body) trusted? include-file
  558. features))
  559. (((define-module modname . modargs) . body)
  560. (symbolic-match? define-module)
  561. (parse-guile-library #'(define-module modname . modargs) #'body
  562. trusted?))
  563. (_
  564. (error "invalid module forms" forms))))
  565. (define* (parse-library-group form #:key (include-file includes-forbidden)
  566. (features '()))
  567. "Parse a @code{library-group} form to a @code{<library-group>} record,
  568. processing includes. No other expansion or analysis is performed beyond
  569. syntactic validity."
  570. (define* (parse forms libraries #:key (trusted? #f))
  571. "For each form in @var{forms}, which should be a list of syntax objects,
  572. process any includes, collecting the prefix of @code{<library>} forms
  573. and then parsing the tail @code{<program>}, or @code{#f} if there is no
  574. program."
  575. (syntax-case forms ()
  576. (() (values (reverse libraries) #f))
  577. ((form . forms)
  578. (syntax-case #'form ()
  579. (#:untrusted
  580. (parse #'forms libraries #:trusted? #f))
  581. ((library . _)
  582. (symbolic-match? library)
  583. (parse #'forms (cons (parse-r6rs-library #'form trusted?) libraries)
  584. #:trusted? trusted?))
  585. ((define-library . _)
  586. (symbolic-match? define-library)
  587. (parse #'forms
  588. (cons (parse-r7rs-library #'form trusted? include-file
  589. features)
  590. libraries)
  591. #:trusted? trusted?))
  592. ((include filename)
  593. (symbolic-match? include)
  594. (let ((included (include-file (syntax->datum #'filename))))
  595. (syntax-case included ()
  596. (((define-module modname . modargs) . body)
  597. (symbolic-match? define-module)
  598. (parse #'forms
  599. (cons (parse-guile-library
  600. #'(define-module modname . modargs) #'body
  601. trusted?)
  602. libraries)
  603. #:trusted? trusted?))
  604. (_
  605. (parse (append included #'forms) libraries
  606. #:trusted? trusted?)))))
  607. ((import import-spec ...)
  608. (symbolic-match? import)
  609. (values (reverse libraries)
  610. (make-program #f trusted? forbid-duplicate-bindings
  611. (parse-imports
  612. (syntax->datum #'(import-spec ...)))
  613. #'forms)))
  614. ((use-modules import-spec ...)
  615. (symbolic-match? use-modules)
  616. (values (reverse libraries)
  617. (make-program #f trusted?
  618. (make-guile-duplicate-handler
  619. %default-guile-duplicate-handlers)
  620. (finish-guile-imports
  621. (map parse-guile-import #'(import-spec ...))
  622. #:pure? #f)
  623. #'forms)))))))
  624. (syntax-case form ()
  625. ((library-group form ...)
  626. (symbolic-match? library-group)
  627. (let ((src (and (syntax? #'library-group)
  628. (syntax-sourcev #'library-group))))
  629. (call-with-values (lambda () (parse #'(form ...) '() #:trusted? #t))
  630. (lambda (libraries program)
  631. (make-library-group src libraries program)))))
  632. (_
  633. (error "invalid library-group" form))))
  634. (define* (link-library-group group #:key
  635. (load-library (lambda* (name #:key (features '()))
  636. #f))
  637. (features '())
  638. (allow-dangling-import? (lambda (name) #f)))
  639. (define linked '()) ;; List of libraries.
  640. (define by-name (make-hash-table))
  641. (define (link-library! library)
  642. (let ((name (library-name library)))
  643. (when (hash-ref by-name name)
  644. (error "duplicate library definition" name))
  645. (hash-set! by-name name 'linking)
  646. (for-each link-import! (library-isets library))
  647. (set! linked (cons library linked))
  648. (hash-set! by-name name 'linked)))
  649. (define (link-import! iset)
  650. (let ((name (imported-library-name iset)))
  651. (match (hash-ref by-name name 'unvisited)
  652. ('linked (values))
  653. ('linking (error "cycle in module graph" name))
  654. ('unvisited
  655. (cond
  656. ((load-library name #:features features) => link-library!)
  657. ((allow-dangling-import? name) (values))
  658. (else (error "module not found" name)))))))
  659. (match group
  660. (($ <library-group> src libraries program)
  661. (for-each link-library! libraries)
  662. (when program (for-each link-import! (program-isets program)))
  663. (make-library-group src (reverse linked) program))))
  664. (define-record-type <import>
  665. (make-import modname exported-name imported-name)
  666. import?
  667. (modname import-modname)
  668. (exported-name exported-name)
  669. (imported-name imported-name))
  670. (define-record-type <lexical>
  671. (make-lexical sym)
  672. lexical?
  673. (sym lexical-sym))
  674. (define-record-type <primitive>
  675. (make-primitive name)
  676. primitive?
  677. (name primitive-name))
  678. (define-record-type <expand-time-value>
  679. (make-expand-time-value)
  680. expand-time-value?)
  681. ;; <value> := <lexical>
  682. ;; | <primitive>
  683. ;; | <expand-time-value>
  684. (define-record-type <module-definitions>
  685. (make-module-definitions private public)
  686. module-definitions?
  687. ;; Hash table of symbol -> <value>.
  688. (private module-private-definitions)
  689. ;; Hash table of symbol -> <value>.
  690. (public module-public-definitions))
  691. (define-record-type <definition>
  692. (make-definition name sym val)
  693. definition?
  694. (name definition-name)
  695. (sym definition-sym)
  696. (val definition-val))
  697. (define-record-type <statement>
  698. (make-statement exp)
  699. statement?
  700. (exp statement-exp))
  701. (define (forbid-duplicate-bindings name old new)
  702. (match old
  703. ((? import?) (error "duplicate imports" old new))
  704. (_ (error "duplicate definition" name))))
  705. ;; FIXME: Get this exported from (language tree-il primitives).
  706. (define (primitive-for-variable box)
  707. (hashq-ref (@@ (language tree-il primitives) *interesting-primitive-vars*)
  708. box))
  709. (define (expand-library call-with-target mod form)
  710. "Expand the syntax object @var{form} in the module @var{mod}.
  711. The term will be expanded twice: once to create the expand-time module,
  712. which will then be evaluated directly, and once to residualize a Tree-IL
  713. term for the compilation unit.
  714. Syntax transformers (macros) will be evaluated at expansion-time, and
  715. not residualized into the compilation unit."
  716. (save-module-excursion
  717. (lambda ()
  718. (set-current-module mod)
  719. (primitive-eval (macroexpand form 'e '(compile eval)))
  720. (call-with-target
  721. (lambda () (macroexpand form 'c '()))))))
  722. (define (expand-program call-with-target mod form)
  723. "Expand the syntax object @var{form} in the module @var{mod}.
  724. Syntax transformers (macros) will be evaluated at expansion-time, and
  725. not residualized into the compilation unit."
  726. (save-module-excursion
  727. (lambda ()
  728. (set-current-module mod)
  729. (call-with-target
  730. (lambda () (macroexpand form 'c '(compile)))))))
  731. (define* (expand-library-group group #:key
  732. (call-with-target (lambda (f) (f)))
  733. (rewrite-primitive
  734. (lambda (exp make-module-ref) exp))
  735. (rewrite-host-reference
  736. (lambda (exp make-module-ref)
  737. (error "unknown host reference" exp)))
  738. (missing-library (lambda (modname) #f))
  739. (primitives #f))
  740. "Take a @code{<library-group>} record and expand it to a big
  741. @code{letrec*}.
  742. The libraries in the group are expanded one-by-one. Expanding a library
  743. residualises a Tree-IL AST node as part of the compilation unit, and
  744. additionally populates a compile-time host module with definitions. If
  745. expanding a module needs compile-time values from another module, it
  746. uses the bindings in the host module.
  747. All definitions and expressions in the expanded libraries are then
  748. rewritten to be part of a big @code{letrec*}, and top-level and module
  749. references in those definitions and expressions are rewritten to use
  750. lexical references.
  751. The final program in the @code{<library-group>} is given the same
  752. treatment, except that its final expression (if any) is evaluated in
  753. tail position."
  754. ;; A mapping from module,name,public? tuple to <binding> record, for
  755. ;; all modules in the library group.
  756. (define module-definitions (make-hash-table))
  757. (define (add-module-definitions! modname)
  758. (when (hash-ref module-definitions modname)
  759. (error "duplicate module" modname))
  760. (define defs
  761. (make-module-definitions (make-hash-table) (make-hash-table)))
  762. (hash-set! module-definitions modname defs)
  763. defs)
  764. (define (lookup-module-definitions modname)
  765. (or (hash-ref module-definitions modname)
  766. (begin
  767. (missing-library modname)
  768. (error "unknown module modname"))))
  769. (define (add-definition! defs name public? duplicate-handler value)
  770. (match defs
  771. (($ <module-definitions> private public)
  772. (let* ((t (if public? public private))
  773. (existing (hashq-ref t name))
  774. (value (if existing
  775. (duplicate-handler name existing value)
  776. value)))
  777. (match (hashq-ref t name)
  778. (#f (hashq-set! t name value))
  779. (existing
  780. (hashq-set! t name (duplicate-handler name existing value))))))))
  781. (define (lookup-definition defs name public?)
  782. (match defs
  783. (($ <module-definitions> private public)
  784. (hashq-ref (if public? public private) name))))
  785. ;; Add definitions from primitive module.
  786. (when primitives
  787. (let ((defs (add-module-definitions! primitives)))
  788. (module-for-each
  789. (lambda (name box)
  790. (add-definition! defs name #t #f
  791. (match (primitive-for-variable box)
  792. (#f (make-expand-time-value))
  793. (name (make-primitive name)))))
  794. (resolve-interface primitives))))
  795. (define (parse-isets isets trusted?)
  796. (define parse-iset
  797. (match-lambda
  798. (($ <iset-only> iset select)
  799. (filter (match-lambda
  800. (($ <import> mod-name exported imported)
  801. (memq imported select)))
  802. (parse-iset iset)))
  803. (($ <iset-except> iset hide)
  804. (filter (match-lambda
  805. (($ <import> mod-name exported imported)
  806. (not (memq imported hide))))
  807. (parse-iset iset)))
  808. (($ <iset-prefix> iset prefix)
  809. (map (match-lambda
  810. (($ <import> mod-name exported imported)
  811. (let ((renamed (symbol-append prefix imported)))
  812. (make-import mod-name exported renamed))))
  813. (parse-iset iset)))
  814. (($ <iset-rename> iset renamings)
  815. (map (match-lambda
  816. (($ <import> mod-name exported imported)
  817. (define renamed
  818. (or (assq-ref renamings imported) imported))
  819. (make-import mod-name exported renamed)))
  820. (parse-iset iset)))
  821. (($ <iset-library> modname version)
  822. (unless (null? version)
  823. (error "version references unsupported"))
  824. (when (equal? modname primitives)
  825. (unless trusted?
  826. (error "untrusted module cannot import primitives")))
  827. (let ((exports (module-public-definitions
  828. (lookup-module-definitions modname))))
  829. (define (id<? a b)
  830. (string<? (symbol->string a) (symbol->string b)))
  831. (define (import<? a b)
  832. (id<? (exported-name a) (exported-name b)))
  833. (sort (hash-map->list (lambda (name binding)
  834. (make-import modname name name))
  835. exports)
  836. import<?)))))
  837. (append-map parse-iset isets))
  838. ;; Because each invocation of expand-library-group gets its own
  839. ;; namespace, we don't have to deal with lingering definitions from
  840. ;; any previous expansion; all modules defined by this compilation
  841. ;; unit are fresh. This also allows expansion to happen in parallel.
  842. (define namespace (gensym "%library-group"))
  843. (define (host-modname? modname)
  844. (match modname
  845. (('% (? (lambda (ns) (eq? ns namespace))) . tail) #f)
  846. (_ #t)))
  847. (define (annotate-modname modname)
  848. (if (equal? modname primitives)
  849. modname
  850. (cons* '% namespace modname)))
  851. (define (strip-modname modname)
  852. (match modname
  853. (('% (? (lambda (x) (eq? x namespace))) . modname) modname)
  854. (_
  855. (unless (equal? modname primitives)
  856. (error "unexpected modname" modname))
  857. modname)))
  858. (define (make-expand-time-module modname filename version imports exports
  859. duplicate-handler)
  860. "Create the host module in which to store compile-time library
  861. definitions. The module may import other host libraries."
  862. (define imports-by-module (make-hash-table))
  863. (define (add-import! modname exported imported)
  864. (define tail (hash-ref imports-by-module modname '()))
  865. (define entry (cons exported imported))
  866. (hash-set! imports-by-module modname (cons entry tail)))
  867. (for-each (match-lambda
  868. (($ <import> modname exported imported)
  869. (add-import! modname exported imported)))
  870. imports)
  871. (define (id<? a b)
  872. (string<? (symbol->string a) (symbol->string b)))
  873. (define (modname<? a b)
  874. (match a
  875. (() #t)
  876. ((a . a*) (match b
  877. (() #f)
  878. ((b . b*) (and (id<? a b) (modname<? a* b*)))))))
  879. (define module-import-decls
  880. (sort (hash-map->list (lambda (modname entries)
  881. (list (annotate-modname modname)
  882. #:select
  883. (sort entries
  884. (lambda (a b)
  885. (id<? (car a) (car b))))))
  886. imports-by-module)
  887. (lambda (a b)
  888. (modname<? (car a) (car b)))))
  889. (define-values (module-export-decls module-re-export-decls)
  890. (let ()
  891. (define imports-by-name (make-hash-table))
  892. (for-each (match-lambda
  893. ((and import ($ <import> _ _ imported))
  894. (match (hashq-ref imports-by-name imported)
  895. (#f (hashq-set! imports-by-name imported import))
  896. (existing
  897. (hashq-set! imports-by-name imported
  898. (duplicate-handler imported existing import))))))
  899. imports)
  900. (partition (match-lambda
  901. ((local . public) (not (hashq-ref imports-by-name local))))
  902. exports)))
  903. (define-module* (annotate-modname modname)
  904. #:filename filename
  905. #:pure #t
  906. #:version version
  907. #:imports module-import-decls
  908. #:exports module-export-decls
  909. #:re-exports module-re-export-decls
  910. #:declarative? #t))
  911. (define (tree-il->reversed-bindings exp modname imports exports bindings
  912. duplicate-handler)
  913. "Given the expanded library @var{exp}, as a Tree-IL node, transform it to
  914. a sequence of definitions and expressions, as @code{<binding>} nodes.
  915. Rewrite references to other top-level bindings to refer to primitive
  916. or lexical definitions. Append those @code{<binding>} nodes to
  917. @var{bindings}, in reverse order. The @var{duplicate-handler}
  918. procedure is called to resolve issues of duplicate definitions."
  919. ;; Make defs for module.
  920. (define defs (add-module-definitions! modname))
  921. (define (has-expand-time-value? name)
  922. (module-variable (resolve-module (annotate-modname modname)) name))
  923. ;; Add definitions for imports.
  924. (for-each (match-lambda
  925. (($ <import> imod exported imported)
  926. (match (lookup-definition (lookup-module-definitions imod)
  927. exported #t)
  928. (#f (error "unknown import?" imod exported))
  929. (value (add-definition! defs imported #f duplicate-handler
  930. value)))))
  931. imports)
  932. (define (tree-il-for-each f exp)
  933. (define fold (make-tree-il-folder))
  934. (fold exp (lambda (exp) (values)) f))
  935. ;; Prohibit set! to imports. Check module on expanded toplevel defs
  936. ;; and uses.
  937. (tree-il-for-each (match-lambda
  938. (($ <toplevel-define> src mod name val)
  939. (unless (equal? (strip-modname mod) modname)
  940. (error "unexpected mod" exp mod modname))
  941. (values))
  942. (($ <toplevel-ref> src mod name)
  943. (unless (equal? (strip-modname mod) modname)
  944. (error "unexpected mod" exp mod modname))
  945. (values))
  946. (($ <toplevel-set> src mod name val)
  947. (unless (equal? (strip-modname mod) modname)
  948. (error "unexpected mod" exp mod modname))
  949. (when (lookup-definition defs name #f)
  950. (error "set! to imported binding" src name))
  951. (values))
  952. (_ (values)))
  953. exp)
  954. ;; Record local definitions and allocate lexicals for them.
  955. (tree-il-for-each (match-lambda
  956. (($ <toplevel-define> src mod name exp)
  957. (add-definition! defs name #f duplicate-handler
  958. (make-lexical (gensym "top")))
  959. (values))
  960. (_ (values)))
  961. exp)
  962. ;; Check for unbound top-levels.
  963. (tree-il-for-each (match-lambda
  964. (($ <toplevel-ref> src mod name)
  965. (unless (lookup-definition defs name #f)
  966. (error "unbound top-level" src name))
  967. (values))
  968. (($ <toplevel-set> src mod name val)
  969. (unless (lookup-definition defs name #f)
  970. (error "unbound top-level" src name))
  971. (values))
  972. (($ <module-ref> src mod name public?)
  973. (unless (or (host-modname? mod)
  974. (let ((defs (lookup-module-definitions
  975. (strip-modname mod))))
  976. (lookup-definition defs name public?)))
  977. (error "unbound macro-introduced top-level for module"
  978. src (strip-modname mod) name))
  979. (values))
  980. (($ <module-set> src mod name public? val)
  981. (unless (let ((defs (lookup-module-definitions
  982. (strip-modname mod))))
  983. (lookup-definition defs name public?))
  984. (error "unbound macro-introduced top-level for module"
  985. src (strip-modname mod) name))
  986. (values))
  987. (_ (values)))
  988. exp)
  989. ;; Find local definitions for exports.
  990. (for-each (match-lambda
  991. ((local . exported)
  992. (match (lookup-definition defs local #f)
  993. (#f
  994. ;; An export without a binding in the compilation
  995. ;; unit. Perhaps it is an expansion-time binding.
  996. (unless (has-expand-time-value? local)
  997. (error "missing definition for export"
  998. modname local exported))
  999. (let ((val (make-expand-time-value)))
  1000. (add-definition! defs local #f duplicate-handler val)
  1001. (add-definition! defs exported #t duplicate-handler val)))
  1002. (val (add-definition! defs exported #t duplicate-handler val)))))
  1003. exports)
  1004. ;; Resolve references to local definitions and residualized
  1005. ;; module-private definitions to lexical-ref or primitive-ref.
  1006. (define (visit-expr exp)
  1007. (post-order
  1008. (lambda (exp)
  1009. (match exp
  1010. (($ <toplevel-ref> src mod name)
  1011. (match (lookup-definition defs name #f)
  1012. (($ <lexical> sym) (make-lexical-ref src name sym))
  1013. (($ <primitive> name) (make-primitive-ref src name))
  1014. (($ <expand-time-value>)
  1015. (error "reference to expansion-time value in generated code"
  1016. src modname name))))
  1017. (($ <toplevel-set> src mod name val)
  1018. (match (lookup-definition defs name #f)
  1019. (($ <lexical> sym) (make-lexical-set src name sym val))
  1020. (($ <expand-time-value>)
  1021. (error "reference to expansion-time value in generated code"
  1022. src modname name))))
  1023. (($ <module-ref> src mod name public?)
  1024. (let ((defs (lookup-module-definitions (strip-modname mod))))
  1025. (match (lookup-definition defs name public?)
  1026. (($ <lexical> sym) (make-lexical-ref src name sym))
  1027. (($ <primitive> name) (make-primitive-ref src name))
  1028. (($ <expand-time-value>)
  1029. (error "reference to expansion-time value in generated code"
  1030. src mod name)))))
  1031. (($ <module-set> src mod name public? val)
  1032. (let ((defs (lookup-module-definitions (strip-modname mod))))
  1033. (match (lookup-definition defs name public?)
  1034. (($ <lexical> sym) (make-lexical-set src name sym val))
  1035. (($ <expand-time-value>)
  1036. (error "reference to expansion-time value in generated code"
  1037. src mod name)))))
  1038. (($ <toplevel-define>)
  1039. (error "unexpected nested toplevel define" exp))
  1040. (($ <call> src ($ <primitive-ref> _ name) args)
  1041. (expand-primcall (make-primcall src name args)))
  1042. (_ exp)))
  1043. exp))
  1044. ;; Walk the chain of <seq> and <toplevel-define> to extract
  1045. ;; definitions and statements.
  1046. (define (visit-top-level exp bindings)
  1047. (match exp
  1048. (($ <toplevel-define> src mod name val)
  1049. (match (lookup-definition defs name #f)
  1050. (($ <lexical> sym)
  1051. (cons (make-definition name sym (visit-expr val))
  1052. bindings))))
  1053. (($ <seq> src head tail)
  1054. (visit-top-level tail (visit-top-level head bindings)))
  1055. ;; Could fold in let and letrec* bindings. Dunno.
  1056. (_ (cons (make-statement (visit-expr exp)) bindings))))
  1057. (define (patch-primitives exp)
  1058. ;; Fix up two kinds of anamolies in expanded code:
  1059. ;;
  1060. ;; 1. Primcalls introduced by the expander, but which might not
  1061. ;; correspond to primitives for the target. For example,
  1062. ;; list->vector as emitted by #'#(foo).
  1063. ;;
  1064. ;; 2. Reference to top-level host bindings in the expander
  1065. ;; itself, as in #'(list->vector foo). This happens a lot in
  1066. ;; Guile's expander.
  1067. (define (make-namespaced-module-ref src mod name public?)
  1068. (make-module-ref src (annotate-modname mod) name public?))
  1069. (define (patch exp)
  1070. (match exp
  1071. (($ <primitive-ref> src name)
  1072. (match (rewrite-primitive exp make-namespaced-module-ref)
  1073. (#f (error "bad rewrite-primitive return"))
  1074. ((and exp ($ <primitive-ref>)) exp)
  1075. (exp (patch exp))))
  1076. (($ <primcall> src name args)
  1077. (match (patch (make-primitive-ref src name))
  1078. (($ <primitive-ref> src name)
  1079. (make-primcall src name args))
  1080. (exp (make-call src exp args))))
  1081. (($ <module-ref> src (? host-modname? mod) name #f)
  1082. ;; A primitive reference introduced by a primitive syntax
  1083. ;; expander.
  1084. (match (rewrite-host-reference exp make-namespaced-module-ref)
  1085. (#f (error "bad rewrite-host-reference return"))
  1086. (($ <module-ref> src (? host-modname? mod) name #f)
  1087. (error "residual host reference after rewrite" src mod name))
  1088. (exp (patch exp))))
  1089. (($ <call> src ($ <primitive-ref> _ name) args)
  1090. (make-primcall src name args))
  1091. (_ exp)))
  1092. (post-order patch exp))
  1093. (visit-top-level (patch-primitives exp) bindings))
  1094. (define (srcv-filename srcv)
  1095. (match srcv
  1096. (#f #f)
  1097. (#(filename line column) filename)))
  1098. (define (library->reversed-bindings library bindings)
  1099. "Given the R6RS library @var{form}, as a syntax object, parse out the
  1100. imports and exports, create a compile-time module, and expand the body
  1101. of the library within that module. Add the residual definitions and
  1102. expressions from the module to @var{bindings}, as in
  1103. @code{tree-il->reversed-bindings}."
  1104. (match library
  1105. (($ <library> src modname version trusted? duplicate-handler exports
  1106. isets body)
  1107. (define filename (srcv-filename src))
  1108. (define imports (parse-isets isets trusted?))
  1109. (define ctmod
  1110. (make-expand-time-module modname filename version imports exports
  1111. duplicate-handler))
  1112. (define expanded
  1113. (expand-library call-with-target ctmod #`(begin . #,body)))
  1114. (tree-il->reversed-bindings expanded modname imports exports
  1115. bindings duplicate-handler))))
  1116. (define (program->reversed-bindings program bindings)
  1117. "Same as @code{r6rs-library->reversed-bindings}, but for a program.
  1118. @var{imports} is already parsed, as a list of @code{<import>}. A new
  1119. module with a fresh name will be defined for the purposes of expanding "
  1120. (match program
  1121. (#f (cons (make-statement (make-void #f)) bindings))
  1122. (($ <program> src trusted? duplicate-handler isets body)
  1123. (define modname (list (gensym "library-group-program")))
  1124. (define filename (srcv-filename src))
  1125. (define imports (parse-isets isets trusted?))
  1126. (define ctmod
  1127. (make-expand-time-module modname filename '() imports '()
  1128. duplicate-handler))
  1129. (define expanded
  1130. (expand-program call-with-target ctmod #`(begin . #,body)))
  1131. (tree-il->reversed-bindings expanded modname imports '() bindings
  1132. duplicate-handler))))
  1133. (define (ensure-tail-expression reversed-bindings)
  1134. (match reversed-bindings
  1135. ((($ <statement>) . _) reversed-bindings)
  1136. (_
  1137. (cons (make-statement (make-void #f)) reversed-bindings))))
  1138. (define reversed-bindings
  1139. (match group
  1140. (($ <library-group> src libraries program)
  1141. (ensure-tail-expression
  1142. (program->reversed-bindings
  1143. program
  1144. (fold library->reversed-bindings '() libraries))))))
  1145. ;; Remove the modules we just expanded from the global module tree.
  1146. (hashq-remove! (module-submodules (resolve-module '(%))) namespace)
  1147. (match reversed-bindings
  1148. ((($ <statement> tail) . bindings)
  1149. (let ((bindings (reverse bindings)))
  1150. (make-letrec (library-group-src group)
  1151. #t ; in-order?
  1152. (map (match-lambda
  1153. (($ <definition> name sym val) name)
  1154. (($ <statement> exp) '_))
  1155. bindings)
  1156. (map (match-lambda
  1157. (($ <definition> name sym val) sym)
  1158. (($ <statement> exp) (gensym "_")))
  1159. bindings)
  1160. (map (match-lambda
  1161. (($ <definition> name sym val) val)
  1162. (($ <statement> exp)
  1163. (if (void? exp)
  1164. exp
  1165. (make-seq #f exp (make-void #f)))))
  1166. bindings)
  1167. tail)))))