base.scm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. ;;; R7RS compatibility libraries
  2. ;;; Copyright (C) 2019 Free Software Foundation, Inc.
  3. ;;;
  4. ;;; This library is free software: you can redistribute it and/or modify
  5. ;;; it under the terms of the GNU Lesser General Public License as
  6. ;;; published by the Free Software Foundation, either version 3 of the
  7. ;;; License, or (at your option) any later version.
  8. ;;;
  9. ;;; This library is distributed in the hope that it will be useful, but
  10. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;; Lesser General Public License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU Lesser General Public
  15. ;;; License along with this program. If not, see
  16. ;;; <http://www.gnu.org/licenses/>.
  17. ;;; Based on code from https://gitlab.com/akku/akku-scm, written
  18. ;;; 2018-2019 by Göran Weinholt <goran@weinholt.se>, as well as
  19. ;;; https://github.com/okuoku/yuni, written 2014-2018 by OKUMURA Yuki
  20. ;;; <mjt@cltn.org>. This code was originally released under the
  21. ;;; following terms:
  22. ;;;
  23. ;;; To the extent possible under law, the author(s) have dedicated
  24. ;;; all copyright and related and neighboring rights to this
  25. ;;; software to the public domain worldwide. This software is
  26. ;;; distributed without any warranty.
  27. ;;;
  28. ;;; See <http://creativecommons.org/publicdomain/zero/1.0/>, for a
  29. ;;; copy of the CC0 Public Domain Dedication.
  30. (define-module (scheme base)
  31. #:use-module (srfi srfi-9)
  32. #:use-module (srfi srfi-11)
  33. #:use-module (ice-9 exceptions)
  34. #:use-module ((srfi srfi-34) #:select (guard))
  35. #:use-module (ice-9 textual-ports)
  36. #:use-module (ice-9 binary-ports)
  37. #:use-module (rnrs bytevectors)
  38. #:export (error-object-message error-object-irritants
  39. file-error?
  40. (r7:error . error)
  41. (r7:cond-expand . cond-expand)
  42. (r7:include . include)
  43. (r7:include-ci . include-ci)
  44. (r7:let-syntax . let-syntax)
  45. member assoc list-copy map for-each
  46. binary-port? textual-port?
  47. open-input-bytevector
  48. open-output-bytevector get-output-bytevector
  49. peek-u8 read-u8 read-bytevector read-bytevector!
  50. read-string read-line
  51. write-u8 write-bytevector write-string flush-output-port
  52. (r7:string-map . string-map)
  53. bytevector bytevector-append
  54. string->vector vector->string
  55. (r7:string->utf8 . string->utf8)
  56. (r7:vector-copy . vector-copy)
  57. (r7:vector->list . vector->list)
  58. (r7:vector-fill! . vector-fill!)
  59. vector-copy! vector-append vector-for-each vector-map
  60. (r7:bytevector-copy . bytevector-copy)
  61. (r7:bytevector-copy! . bytevector-copy!)
  62. (r7:utf8->string . utf8->string)
  63. square
  64. (r7:expt . expt)
  65. boolean=? symbol=?
  66. call-with-port
  67. features
  68. input-port-open? output-port-open?)
  69. #:re-export
  70. (_
  71. ... => else
  72. * + - / < <= = > >= abs and append apply assq assv begin
  73. boolean?
  74. bytevector-length
  75. bytevector-u8-ref bytevector-u8-set! bytevector? caar cadr
  76. call-with-current-continuation call-with-values
  77. call/cc car case cdar cddr cdr ceiling char->integer char-ready?
  78. char<=? char<? char=? char>=? char>? char? close-input-port
  79. close-output-port close-port complex? cond cons
  80. current-error-port current-input-port current-output-port define
  81. define-record-type define-syntax define-values denominator do
  82. dynamic-wind eof-object eof-object? eq? equal? eqv?
  83. (exception? . error-object?)
  84. even?
  85. (inexact->exact . exact)
  86. (exact->inexact . inexact)
  87. exact-integer-sqrt exact-integer? exact?
  88. floor floor-quotient floor-remainder floor/
  89. gcd
  90. get-output-string guard if inexact?
  91. input-port? integer->char integer? lambda lcm
  92. length let let* let*-values let-values letrec letrec*
  93. letrec-syntax list list->string list->vector list-ref
  94. list-set! list-tail list? make-bytevector make-list make-parameter
  95. make-string make-vector max memq memv min modulo
  96. negative? newline not null? number->string number? numerator odd?
  97. open-input-string
  98. open-output-string or output-port? pair?
  99. parameterize peek-char port? positive? procedure?
  100. quasiquote quote quotient
  101. (raise-exception . raise)
  102. raise-continuable
  103. rational?
  104. rationalize read-char
  105. (lexical-error? . read-error?)
  106. real? remainder reverse round set!
  107. set-car! set-cdr! string string->list string->number
  108. string->symbol string-append
  109. string-copy string-copy! string-fill! string-for-each
  110. string-length string-ref string-set! string<=? string<?
  111. string=? string>=? string>? string? substring symbol->string
  112. symbol? syntax-error syntax-rules truncate
  113. truncate-quotient truncate-remainder truncate/
  114. (char-ready? . u8-ready?)
  115. unless
  116. unquote unquote-splicing values
  117. vector
  118. vector-length vector-ref vector-set! vector?
  119. when with-exception-handler write-char
  120. zero?))
  121. (define* (member x ls #:optional (= equal?))
  122. (cond
  123. ((eq? = eq?) (memq x ls))
  124. ((eq? = eqv?) (memv x ls))
  125. (else
  126. (unless (procedure? =)
  127. (error "not a procedure" =))
  128. (let lp ((ls ls))
  129. (if (or (null? ls) (= (car ls) x))
  130. ls
  131. (lp (cdr ls)))))))
  132. (define* (assoc x ls #:optional (= equal?))
  133. (cond
  134. ((eq? = eq?) (assq x ls))
  135. ((eq? = eqv?) (assv x ls))
  136. (else
  137. (unless (procedure? =)
  138. (error "not a procedure" =))
  139. (let lp ((ls ls))
  140. (cond
  141. ((null? ls) #f)
  142. ((= (caar ls) x) (car ls))
  143. (else (lp (cdr ls))))))))
  144. (define (list-copy x)
  145. (if (pair? x)
  146. (cons (car x) (list-copy (cdr x)))
  147. x))
  148. (define (circular-list? x)
  149. (and (pair? x)
  150. (let lp ((hare (cdr x)) (tortoise x))
  151. (and (pair? hare)
  152. (let ((hare (cdr hare)))
  153. (and (pair? hare)
  154. (or (eq? hare tortoise)
  155. (lp (cdr hare) (cdr tortoise)))))))))
  156. (define map
  157. (case-lambda
  158. ((f l)
  159. (unless (or (list? l)
  160. (circular-list? l))
  161. (scm-error 'wrong-type-arg "map" "Not a list: ~S"
  162. (list l) #f))
  163. (let map1 ((l l))
  164. (if (pair? l)
  165. (cons (f (car l)) (map1 (cdr l)))
  166. '())))
  167. ((f l1 l2)
  168. (cond
  169. ((list? l1)
  170. (unless (or (list? l2) (circular-list? l2))
  171. (scm-error 'wrong-type-arg "map" "Not a list: ~S"
  172. (list l2) #f)))
  173. ((circular-list? l1)
  174. (unless (list? l2)
  175. (scm-error 'wrong-type-arg "map" "Not a finite list: ~S"
  176. (list l2) #f)))
  177. (else
  178. (scm-error 'wrong-type-arg "map" "Not a list: ~S"
  179. (list l1) #f)))
  180. (let map2 ((l1 l1) (l2 l2))
  181. (if (and (pair? l1) (pair? l2))
  182. (cons (f (car l1) (car l2))
  183. (map2 (cdr l1) (cdr l2)))
  184. '())))
  185. ((f l1 . rest)
  186. (let ((lists (cons l1 rest)))
  187. (unless (and-map list? lists)
  188. (unless (or-map list? lists)
  189. (scm-error 'wrong-type-arg "map"
  190. "Arguments do not contain a finite list" '() #f))
  191. (for-each (lambda (x)
  192. (unless (or (list? x) (circular-list? x))
  193. (scm-error 'wrong-type-arg "map" "Not a list: ~S"
  194. (list x) #f)))
  195. lists))
  196. (let mapn ((lists lists))
  197. (if (and-map pair? lists)
  198. (cons (apply f (map car lists)) (mapn (map cdr lists)))
  199. '()))))))
  200. (define for-each
  201. (case-lambda
  202. ((f l)
  203. (unless (or (list? l)
  204. (circular-list? l))
  205. (scm-error 'wrong-type-arg "for-each" "Not a list: ~S"
  206. (list l) #f))
  207. (let for-each1 ((l l))
  208. (when (pair? l)
  209. (f (car l))
  210. (for-each1 (cdr l)))))
  211. ((f l1 l2)
  212. (cond
  213. ((list? l1)
  214. (unless (or (list? l2) (circular-list? l2))
  215. (scm-error 'wrong-type-arg "for-each" "Not a list: ~S"
  216. (list l2) #f)))
  217. ((circular-list? l1)
  218. (unless (list? l2)
  219. (scm-error 'wrong-type-arg "for-each" "Not a finite list: ~S"
  220. (list l2) #f)))
  221. (else
  222. (scm-error 'wrong-type-arg "for-each" "Not a list: ~S"
  223. (list l1) #f)))
  224. (let for-each2 ((l1 l1) (l2 l2))
  225. (when (and (pair? l1) (pair? l2))
  226. (f (car l1) (car l2))
  227. (for-each2 (cdr l1) (cdr l2)))))
  228. ((f l1 . rest)
  229. (let ((lists (cons l1 rest)))
  230. (unless (and-map list? lists)
  231. (unless (or-map list? lists)
  232. (scm-error 'wrong-type-arg "for-each"
  233. "Arguments do not contain a finite list" '() #f))
  234. (for-each (lambda (x)
  235. (unless (or (list? x) (circular-list? x))
  236. (scm-error 'wrong-type-arg "for-each" "Not a list: ~S"
  237. (list x) #f)))
  238. lists))
  239. (let for-eachn ((lists lists))
  240. (when (and-map pair? lists)
  241. (apply f (map car lists))
  242. (for-eachn (map cdr lists))))))))
  243. ;; FIXME.
  244. (define (file-error? x) #f)
  245. (define (error-object-message obj)
  246. (and (exception-with-message? obj)
  247. (exception-message obj)))
  248. (define (error-object-irritants obj)
  249. (and (exception-with-irritants? obj)
  250. (exception-irritants obj)))
  251. (define (r7:error message . irritants)
  252. (raise-exception
  253. (let ((exn (make-exception-with-message message)))
  254. (if (null? irritants)
  255. exn
  256. (make-exception exn
  257. (make-exception-with-irritants irritants))))))
  258. (define-syntax r7:cond-expand
  259. (lambda (x)
  260. (define (has-req? req)
  261. (syntax-case req (and or not library)
  262. ((and req ...)
  263. (and-map has-req? #'(req ...)))
  264. ((or req ...)
  265. (or-map has-req? #'(req ...)))
  266. ((not req)
  267. (not (has-req? #'req)))
  268. ((library lib-name)
  269. (->bool (resolve-interface (syntax->datum #'lib-name))))
  270. (id
  271. (identifier? #'id)
  272. (memq (syntax->datum #'id) (features)))))
  273. (syntax-case x (else)
  274. ((_)
  275. (syntax-violation 'cond-expand "Unfulfilled cond-expand" x))
  276. ((_ (else body ...))
  277. #'(begin body ...))
  278. ((_ (req body ...) more-clauses ...)
  279. (if (has-req? #'req)
  280. #'(begin body ...)
  281. #'(r7:cond-expand more-clauses ...))))))
  282. (define-syntax-rule (r7:include k fn* ...)
  283. (begin (include k fn*) ...))
  284. ;; FIXME
  285. (define-syntax-rule (r7:include-ci k fn* ...)
  286. (r7:include k fn* ...))
  287. (define-syntax-rule (r7:let-syntax ((vars trans) ...) . expr)
  288. (let-syntax ((vars trans) ...)
  289. (let () . expr)))
  290. (define (boolean=? x y . y*)
  291. (unless (boolean? x) (error "not a boolean" x))
  292. (unless (boolean? y) (error "not a boolean" y))
  293. (and (eq? x y)
  294. (or (null? y*)
  295. (apply boolean=? x y*))))
  296. (define (symbol=? x y . y*)
  297. (unless (symbol? x) (error "not a symbol" x))
  298. (unless (symbol? y) (error "not a symbol" y))
  299. (and (symbol? x)
  300. (eq? x y)
  301. (or (null? y*)
  302. (apply symbol=? x y*))))
  303. (define (binary-port? p) (port? p))
  304. (define (textual-port? p) (port? p))
  305. (define (open-input-bytevector bv) (open-bytevector-input-port bv))
  306. (define (open-output-bytevector)
  307. (let-values (((p extract) (open-bytevector-output-port)))
  308. (define pos 0)
  309. (define buf #vu8())
  310. (define (read! target target-start count)
  311. (when (zero? (- (bytevector-length buf) pos))
  312. (set! buf (bytevector-append buf (extract)))) ;resets p
  313. (let ((count (min count (- (bytevector-length buf) pos))))
  314. (bytevector-copy! buf pos
  315. target target-start count)
  316. (set! pos (+ pos count))
  317. count))
  318. (define (write! bv start count)
  319. (put-bytevector p bv start count)
  320. (set! pos (+ pos count))
  321. count)
  322. (define (get-position)
  323. pos)
  324. (define (set-position! new-pos)
  325. (set! pos new-pos))
  326. (define (close)
  327. (close-port p))
  328. ;; It's actually an input/output port, but only
  329. ;; get-output-bytevector should ever read from it. If it was just
  330. ;; an output port then there would be no good way for
  331. ;; get-output-bytevector to read the data. -weinholt
  332. (make-custom-binary-input/output-port
  333. "bytevector" read! write! get-position set-position! close)))
  334. (define (get-output-bytevector port)
  335. ;; R7RS says "It is an error if port was not created with
  336. ;; open-output-bytevector.", so we can safely assume that the port
  337. ;; was created by open-output-bytevector. -weinholt
  338. (seek port 0 SEEK_SET)
  339. (let ((bv (get-bytevector-all port)))
  340. (if (eof-object? bv)
  341. #vu8()
  342. bv)))
  343. (define* (peek-u8 #:optional (port (current-input-port)))
  344. (lookahead-u8 port))
  345. (define* (read-u8 #:optional (port (current-output-port)))
  346. (get-u8 port))
  347. (define* (read-bytevector len #:optional (port (current-input-port)))
  348. (get-bytevector-n port len))
  349. (define* (read-string len #:optional (port (current-input-port)))
  350. (get-string-n port len))
  351. (define* (read-bytevector! bv #:optional (port (current-input-port))
  352. (start 0) (end (bytevector-length bv)))
  353. (get-bytevector-n! port bv start (- end start)))
  354. (define* (read-line #:optional (port (current-input-port)))
  355. (get-line port))
  356. (define* (write-u8 obj #:optional (port (current-output-port)))
  357. (put-u8 port obj))
  358. (define* (write-bytevector bv #:optional (port (current-output-port))
  359. (start 0) (end (bytevector-length bv)))
  360. (put-bytevector port bv start (- end start)))
  361. (define* (write-string str #:optional (port (current-output-port))
  362. (start 0) (end (string-length str)))
  363. (put-string port str start (- end start)))
  364. (define* (flush-output-port #:optional (port (current-output-port)))
  365. (force-output port))
  366. (define (r7:string-map proc s . s*)
  367. (if (null? s*)
  368. (string-map proc s)
  369. (list->string (apply map proc (string->list s) (map string->list s*)))))
  370. (define (bytevector . lis)
  371. (u8-list->bytevector lis))
  372. (define (call-with-bytevector-output-port proc)
  373. (call-with-values (lambda () (open-bytevector-output-port))
  374. (lambda (port get)
  375. (proc port)
  376. (get))))
  377. (define (bytevector-append . bvs)
  378. (call-with-bytevector-output-port
  379. (lambda (p)
  380. (for-each (lambda (bv) (put-bytevector p bv)) bvs))))
  381. (define string->vector
  382. (case-lambda
  383. ((str) (list->vector (string->list str)))
  384. ((str start) (string->vector (substring str start)))
  385. ((str start end) (string->vector (substring str start end)))))
  386. (define r7:string->utf8
  387. (case-lambda
  388. ((str) (string->utf8 str))
  389. ((str start) (string->utf8 (substring str start)))
  390. ((str start end) (string->utf8 (substring str start end)))))
  391. ;;; vector
  392. (define (%subvector v start end)
  393. (define mlen (- end start))
  394. (define out (make-vector (- end start)))
  395. (define (itr r)
  396. (if (= r mlen)
  397. out
  398. (begin
  399. (vector-set! out r (vector-ref v (+ start r)))
  400. (itr (+ r 1)))))
  401. (itr 0))
  402. (define r7:vector-copy
  403. (case-lambda*
  404. ((v) (vector-copy v))
  405. ((v start #:optional (end (vector-length v)))
  406. (%subvector v start end))))
  407. (define* (vector-copy! target tstart source
  408. #:optional (sstart 0) (send (vector-length source)))
  409. "Copy a block of elements from SOURCE to TARGET, both of which must be
  410. vectors, starting in TARGET at TSTART and starting in SOURCE at SSTART,
  411. ending when SEND - SSTART elements have been copied. It is an error for
  412. TARGET to have a length less than TSTART + (SEND - SSTART). SSTART
  413. defaults to 0 and SEND defaults to the length of SOURCE."
  414. (let ((tlen (vector-length target))
  415. (slen (vector-length source)))
  416. (if (< tstart sstart)
  417. (vector-move-left! source sstart send target tstart)
  418. (vector-move-right! source sstart send target tstart))))
  419. (define r7:vector->list
  420. (case-lambda*
  421. ((v) (vector->list v))
  422. ((v start #:optional (end (vector-length v)))
  423. (vector->list (%subvector v start end)))))
  424. (define vector-map
  425. (case-lambda*
  426. ((f v)
  427. (let* ((len (vector-length v))
  428. (out (make-vector len #f)))
  429. (let lp ((i 0))
  430. (when (< i len)
  431. (vector-set! out i (f (vector-ref v i)))
  432. (lp (1+ i))))
  433. out))
  434. ((f v . v*)
  435. (list->vector (apply map f (map vector->list (cons v v*)))))))
  436. (define vector-for-each
  437. (case-lambda*
  438. ((f v)
  439. (let lp ((i 0))
  440. (when (< i (vector-length v))
  441. (f (vector-ref v i))
  442. (lp (1+ i)))))
  443. ((f v . v*)
  444. (let ((len (apply min (vector-length v) (map vector-length v*))))
  445. (let lp ((i 0))
  446. (when (< i len)
  447. (apply f (vector-ref v i) (map (lambda (v) (vector-ref v i)) v*))
  448. (lp (1+ i))))))))
  449. (define (vector-append . vectors)
  450. (if (null? vectors)
  451. #()
  452. (let* ((len (let lp ((vectors vectors))
  453. (if (null? vectors)
  454. 0
  455. (+ (vector-length (car vectors)) (lp (cdr vectors))))))
  456. (out (make-vector len #f)))
  457. (let lp ((i 0) (j 0) (v (car vectors)) (v* (cdr vectors)))
  458. (cond
  459. ((< j (vector-length v))
  460. (vector-set! out i (vector-ref v j))
  461. (lp (1+ i) (1+ j) v v*))
  462. ((null? v*)
  463. out)
  464. (else
  465. (lp i 0 (car v*) (cdr v*))))))))
  466. (define vector->string
  467. (case-lambda*
  468. ((v) (list->string (vector->list v)))
  469. ((v start #:optional (end (vector-length v)))
  470. (vector->string (%subvector v start end)))))
  471. (define r7:vector-fill!
  472. (case-lambda*
  473. ((vec fill) (vector-fill! vec fill))
  474. ((vec fill start #:optional (end (vector-length vec)))
  475. (let lp ((r start))
  476. (unless (= r end)
  477. (vector-set! vec r fill)
  478. (lp (+ r 1)))))))
  479. (define (%subbytevector bv start end)
  480. (define mlen (- end start))
  481. (define out (make-bytevector mlen))
  482. (bytevector-copy! bv start out 0 mlen)
  483. out)
  484. (define (%subbytevector1 bv start)
  485. (%subbytevector bv start (bytevector-length bv)))
  486. (define r7:bytevector-copy!
  487. (case-lambda*
  488. ((to at from #:optional
  489. (start 0)
  490. (end (+ start
  491. (min (- (bytevector-length from) start)
  492. (- (bytevector-length to) at)))))
  493. (bytevector-copy! from start to at (- end start)))))
  494. (define r7:bytevector-copy
  495. (case-lambda*
  496. ((bv) (bytevector-copy bv))
  497. ((bv start #:optional (end (bytevector-length bv)))
  498. (%subbytevector bv start end))))
  499. (define r7:utf8->string
  500. (case-lambda*
  501. ((bv) (utf8->string bv))
  502. ((bv start #:optional (end (bytevector-length bv)))
  503. (utf8->string (%subbytevector bv start end)))))
  504. (define (square x) (* x x))
  505. (define (r7:expt x y)
  506. (if (eqv? x 0.0)
  507. (exact->inexact (expt x y))
  508. (expt x y)))
  509. (define (call-with-port port proc)
  510. "Call @var{proc}, passing it @var{port} and closing @var{port} upon exit of
  511. @var{proc}. Return the return values of @var{proc}."
  512. (call-with-values
  513. (lambda () (proc port))
  514. (lambda vals
  515. (close-port port)
  516. (apply values vals))))
  517. (define (features)
  518. (append
  519. %cond-expand-features
  520. (case (native-endianness)
  521. ((big) '(big-endian))
  522. ((little) '(little-endian))
  523. (else '()))
  524. '(r6rs
  525. syntax-case
  526. r7rs exact-closed ieee-float full-unicode ratios)))
  527. (define (input-port-open? port)
  528. (and (not (port-closed? port)) (input-port? port)))
  529. (define (output-port-open? port)
  530. (and (not (port-closed? port)) (output-port? port)))