base.scm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. ;;; R7RS compatibility libraries
  2. ;;; Copyright (C) 2019-2021 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 ports)
  36. #:use-module (ice-9 textual-ports)
  37. #:use-module (ice-9 binary-ports)
  38. #:use-module (rnrs bytevectors)
  39. #:export (error-object-message error-object-irritants
  40. file-error?
  41. (r7:error . error)
  42. (r7:cond-expand . cond-expand)
  43. (r7:include . include)
  44. (r7:include-ci . include-ci)
  45. (r7:let-syntax . let-syntax)
  46. member assoc list-copy map for-each
  47. binary-port? textual-port?
  48. open-input-bytevector
  49. open-output-bytevector get-output-bytevector
  50. peek-u8 read-u8 read-bytevector read-bytevector!
  51. read-string read-line
  52. write-u8 write-bytevector write-string flush-output-port
  53. (r7:string-map . string-map)
  54. bytevector bytevector-append
  55. string->vector vector->string
  56. (r7:string->utf8 . string->utf8)
  57. (r7:vector->list . vector->list)
  58. vector-append vector-for-each vector-map
  59. (r7:bytevector-copy . bytevector-copy)
  60. (r7:bytevector-copy! . bytevector-copy!)
  61. (r7:utf8->string . utf8->string)
  62. square
  63. (r7:expt . expt)
  64. boolean=? symbol=?
  65. features
  66. input-port-open? output-port-open?)
  67. #:re-export
  68. (_
  69. ... => else
  70. * + - / < <= = > >= abs and append apply assq assv begin
  71. boolean?
  72. bytevector-length
  73. bytevector-u8-ref bytevector-u8-set! bytevector? caar cadr
  74. call-with-current-continuation call-with-port call-with-values
  75. call/cc car case cdar cddr cdr ceiling char->integer char-ready?
  76. char<=? char<? char=? char>=? char>? char? close-input-port
  77. close-output-port close-port complex? cond cons
  78. current-error-port current-input-port current-output-port define
  79. define-record-type define-syntax define-values denominator do
  80. dynamic-wind eof-object eof-object? eq? equal? eqv?
  81. (exception? . error-object?)
  82. even?
  83. (inexact->exact . exact)
  84. (exact->inexact . inexact)
  85. exact-integer-sqrt exact-integer? exact?
  86. floor floor-quotient floor-remainder floor/
  87. gcd
  88. get-output-string guard if inexact?
  89. input-port? integer->char integer? lambda lcm
  90. length let let* let*-values let-values letrec letrec*
  91. letrec-syntax list list->string list->vector list-ref
  92. list-set! list-tail list? make-bytevector make-list make-parameter
  93. make-string make-vector max memq memv min modulo
  94. negative? newline not null? number->string number? numerator odd?
  95. open-input-string
  96. open-output-string or output-port? pair?
  97. parameterize peek-char port? positive? procedure?
  98. quasiquote quote quotient
  99. (raise-exception . raise)
  100. raise-continuable
  101. rational?
  102. rationalize read-char
  103. (lexical-error? . read-error?)
  104. real? remainder reverse round set!
  105. set-car! set-cdr! string string->list string->number
  106. string->symbol string-append
  107. string-copy string-copy! string-fill! string-for-each
  108. string-length string-ref string-set! string<=? string<?
  109. string=? string>=? string>? string? substring symbol->string
  110. symbol? syntax-error syntax-rules truncate
  111. truncate-quotient truncate-remainder truncate/
  112. (char-ready? . u8-ready?)
  113. unless
  114. unquote unquote-splicing values
  115. vector vector-copy vector-copy! vector-fill!
  116. vector-length vector-ref vector-set! vector?
  117. when with-exception-handler write-char
  118. zero?))
  119. (define* (member x ls #:optional (= equal?))
  120. (cond
  121. ((eq? = eq?) (memq x ls))
  122. ((eq? = eqv?) (memv x ls))
  123. (else
  124. (unless (procedure? =)
  125. (error "not a procedure" =))
  126. (let lp ((ls ls))
  127. (cond
  128. ((null? ls) #f)
  129. ((= (car ls) x) ls)
  130. (else (lp (cdr ls))))))))
  131. (define* (assoc x ls #:optional (= equal?))
  132. (cond
  133. ((eq? = eq?) (assq x ls))
  134. ((eq? = eqv?) (assv x ls))
  135. (else
  136. (unless (procedure? =)
  137. (error "not a procedure" =))
  138. (let lp ((ls ls))
  139. (cond
  140. ((null? ls) #f)
  141. ((= (caar ls) x) (car ls))
  142. (else (lp (cdr ls))))))))
  143. (define (list-copy x)
  144. (if (pair? x)
  145. (cons (car x) (list-copy (cdr x)))
  146. x))
  147. (define (circular-list? x)
  148. (and (pair? x)
  149. (let lp ((hare (cdr x)) (tortoise x))
  150. (and (pair? hare)
  151. (let ((hare (cdr hare)))
  152. (and (pair? hare)
  153. (or (eq? hare tortoise)
  154. (lp (cdr hare) (cdr tortoise)))))))))
  155. (define map
  156. (case-lambda
  157. ((f l)
  158. (unless (or (list? l)
  159. (circular-list? l))
  160. (scm-error 'wrong-type-arg "map" "Not a list: ~S"
  161. (list l) #f))
  162. (let map1 ((l l))
  163. (if (pair? l)
  164. (cons (f (car l)) (map1 (cdr l)))
  165. '())))
  166. ((f l1 l2)
  167. (cond
  168. ((list? l1)
  169. (unless (or (list? l2) (circular-list? l2))
  170. (scm-error 'wrong-type-arg "map" "Not a list: ~S"
  171. (list l2) #f)))
  172. ((circular-list? l1)
  173. (unless (list? l2)
  174. (scm-error 'wrong-type-arg "map" "Not a finite list: ~S"
  175. (list l2) #f)))
  176. (else
  177. (scm-error 'wrong-type-arg "map" "Not a list: ~S"
  178. (list l1) #f)))
  179. (let map2 ((l1 l1) (l2 l2))
  180. (if (and (pair? l1) (pair? l2))
  181. (cons (f (car l1) (car l2))
  182. (map2 (cdr l1) (cdr l2)))
  183. '())))
  184. ((f l1 . rest)
  185. (let ((lists (cons l1 rest)))
  186. (unless (and-map list? lists)
  187. (unless (or-map list? lists)
  188. (scm-error 'wrong-type-arg "map"
  189. "Arguments do not contain a finite list" '() #f))
  190. (for-each (lambda (x)
  191. (unless (or (list? x) (circular-list? x))
  192. (scm-error 'wrong-type-arg "map" "Not a list: ~S"
  193. (list x) #f)))
  194. lists))
  195. (let mapn ((lists lists))
  196. (if (and-map pair? lists)
  197. (cons (apply f (map car lists)) (mapn (map cdr lists)))
  198. '()))))))
  199. (define for-each
  200. (case-lambda
  201. ((f l)
  202. (unless (or (list? l)
  203. (circular-list? l))
  204. (scm-error 'wrong-type-arg "for-each" "Not a list: ~S"
  205. (list l) #f))
  206. (let for-each1 ((l l))
  207. (when (pair? l)
  208. (f (car l))
  209. (for-each1 (cdr l)))))
  210. ((f l1 l2)
  211. (cond
  212. ((list? l1)
  213. (unless (or (list? l2) (circular-list? l2))
  214. (scm-error 'wrong-type-arg "for-each" "Not a list: ~S"
  215. (list l2) #f)))
  216. ((circular-list? l1)
  217. (unless (list? l2)
  218. (scm-error 'wrong-type-arg "for-each" "Not a finite list: ~S"
  219. (list l2) #f)))
  220. (else
  221. (scm-error 'wrong-type-arg "for-each" "Not a list: ~S"
  222. (list l1) #f)))
  223. (let for-each2 ((l1 l1) (l2 l2))
  224. (when (and (pair? l1) (pair? l2))
  225. (f (car l1) (car l2))
  226. (for-each2 (cdr l1) (cdr l2)))))
  227. ((f l1 . rest)
  228. (let ((lists (cons l1 rest)))
  229. (unless (and-map list? lists)
  230. (unless (or-map list? lists)
  231. (scm-error 'wrong-type-arg "for-each"
  232. "Arguments do not contain a finite list" '() #f))
  233. (for-each (lambda (x)
  234. (unless (or (list? x) (circular-list? x))
  235. (scm-error 'wrong-type-arg "for-each" "Not a list: ~S"
  236. (list x) #f)))
  237. lists))
  238. (let for-eachn ((lists lists))
  239. (when (and-map pair? lists)
  240. (apply f (map car lists))
  241. (for-eachn (map cdr lists))))))))
  242. ;; FIXME.
  243. (define (file-error? x) #f)
  244. (define (error-object-message obj)
  245. (and (exception-with-message? obj)
  246. (exception-message obj)))
  247. (define (error-object-irritants obj)
  248. (and (exception-with-irritants? obj)
  249. (exception-irritants obj)))
  250. (define (r7:error message . irritants)
  251. (raise-exception
  252. (let ((exn (make-exception-with-message message)))
  253. (if (null? irritants)
  254. exn
  255. (make-exception exn
  256. (make-exception-with-irritants irritants))))))
  257. (define-syntax r7:cond-expand
  258. (lambda (x)
  259. (define (has-req? req)
  260. (syntax-case req (and or not library)
  261. ((and req ...)
  262. (and-map has-req? #'(req ...)))
  263. ((or req ...)
  264. (or-map has-req? #'(req ...)))
  265. ((not req)
  266. (not (has-req? #'req)))
  267. ((library lib-name)
  268. (->bool (resolve-interface (syntax->datum #'lib-name))))
  269. (id
  270. (identifier? #'id)
  271. (memq (syntax->datum #'id) (features)))))
  272. (syntax-case x (else)
  273. ((_)
  274. (syntax-violation 'cond-expand "Unfulfilled cond-expand" x))
  275. ((_ (else body ...))
  276. #'(begin body ...))
  277. ((_ (req body ...) more-clauses ...)
  278. (if (has-req? #'req)
  279. #'(begin body ...)
  280. #'(r7:cond-expand more-clauses ...))))))
  281. (define-syntax-rule (r7:include fn* ...)
  282. (begin (include fn*) ...))
  283. (define-syntax-rule (r7:include-ci fn* ...)
  284. (begin (include-ci fn*) ...))
  285. (define-syntax-rule (r7:let-syntax ((vars trans) ...) . expr)
  286. (let-syntax ((vars trans) ...)
  287. (let () . expr)))
  288. (define (boolean=? x y . y*)
  289. (unless (boolean? x) (error "not a boolean" x))
  290. (unless (boolean? y) (error "not a boolean" y))
  291. (and (eq? x y)
  292. (or (null? y*)
  293. (apply boolean=? x y*))))
  294. (define (symbol=? x y . y*)
  295. (unless (symbol? x) (error "not a symbol" x))
  296. (unless (symbol? y) (error "not a symbol" y))
  297. (and (symbol? x)
  298. (eq? x y)
  299. (or (null? y*)
  300. (apply symbol=? x y*))))
  301. (define (binary-port? p) (port? p))
  302. (define (textual-port? p) (port? p))
  303. (define (open-input-bytevector bv) (open-bytevector-input-port bv))
  304. (define (open-output-bytevector)
  305. (let-values (((p extract) (open-bytevector-output-port)))
  306. (define pos 0)
  307. (define buf #vu8())
  308. (define (read! target target-start count)
  309. (when (zero? (- (bytevector-length buf) pos))
  310. (set! buf (bytevector-append buf (extract)))) ;resets p
  311. (let ((count (min count (- (bytevector-length buf) pos))))
  312. (bytevector-copy! buf pos
  313. target target-start count)
  314. (set! pos (+ pos count))
  315. count))
  316. (define (write! bv start count)
  317. (put-bytevector p bv start count)
  318. (set! pos (+ pos count))
  319. count)
  320. (define (get-position)
  321. pos)
  322. (define (set-position! new-pos)
  323. (set! pos new-pos))
  324. (define (close)
  325. (close-port p))
  326. ;; It's actually an input/output port, but only
  327. ;; get-output-bytevector should ever read from it. If it was just
  328. ;; an output port then there would be no good way for
  329. ;; get-output-bytevector to read the data. -weinholt
  330. (make-custom-binary-input/output-port
  331. "bytevector" read! write! get-position set-position! close)))
  332. (define (get-output-bytevector port)
  333. ;; R7RS says "It is an error if port was not created with
  334. ;; open-output-bytevector.", so we can safely assume that the port
  335. ;; was created by open-output-bytevector. -weinholt
  336. (seek port 0 SEEK_SET)
  337. (let ((bv (get-bytevector-all port)))
  338. (if (eof-object? bv)
  339. #vu8()
  340. bv)))
  341. (define* (peek-u8 #:optional (port (current-input-port)))
  342. (lookahead-u8 port))
  343. (define* (read-u8 #:optional (port (current-output-port)))
  344. (get-u8 port))
  345. (define* (read-bytevector len #:optional (port (current-input-port)))
  346. (get-bytevector-n port len))
  347. (define* (read-string len #:optional (port (current-input-port)))
  348. (get-string-n port len))
  349. (define* (read-bytevector! bv #:optional (port (current-input-port))
  350. (start 0) (end (bytevector-length bv)))
  351. (get-bytevector-n! port bv start (- end start)))
  352. (define* (read-line #:optional (port (current-input-port)))
  353. (get-line port))
  354. (define* (write-u8 obj #:optional (port (current-output-port)))
  355. (put-u8 port obj))
  356. (define* (write-bytevector bv #:optional (port (current-output-port))
  357. (start 0) (end (bytevector-length bv)))
  358. (put-bytevector port bv start (- end start)))
  359. (define* (write-string str #:optional (port (current-output-port))
  360. (start 0) (end (string-length str)))
  361. (put-string port str start (- end start)))
  362. (define* (flush-output-port #:optional (port (current-output-port)))
  363. (force-output port))
  364. (define (r7:string-map proc s . s*)
  365. (if (null? s*)
  366. (string-map proc s)
  367. (list->string (apply map proc (string->list s) (map string->list s*)))))
  368. (define (bytevector . lis)
  369. (u8-list->bytevector lis))
  370. (define (call-with-bytevector-output-port proc)
  371. (call-with-values (lambda () (open-bytevector-output-port))
  372. (lambda (port get)
  373. (proc port)
  374. (get))))
  375. (define (bytevector-append . bvs)
  376. (call-with-bytevector-output-port
  377. (lambda (p)
  378. (for-each (lambda (bv) (put-bytevector p bv)) bvs))))
  379. (define string->vector
  380. (case-lambda
  381. ((str) (list->vector (string->list str)))
  382. ((str start) (string->vector (substring str start)))
  383. ((str start end) (string->vector (substring str start end)))))
  384. (define r7:string->utf8
  385. (case-lambda
  386. ((str) (string->utf8 str))
  387. ((str start) (string->utf8 (substring str start)))
  388. ((str start end) (string->utf8 (substring str start end)))))
  389. ;;; vector
  390. (define r7:vector->list
  391. (case-lambda*
  392. ((v) (vector->list v))
  393. ((v start #:optional (end (vector-length v)))
  394. (vector->list (vector-copy v start end)))))
  395. (define vector-map
  396. (case-lambda*
  397. ((f v)
  398. (let* ((len (vector-length v))
  399. (out (make-vector len #f)))
  400. (let lp ((i 0))
  401. (when (< i len)
  402. (vector-set! out i (f (vector-ref v i)))
  403. (lp (1+ i))))
  404. out))
  405. ((f v . v*)
  406. (list->vector (apply map f (map vector->list (cons v v*)))))))
  407. (define vector-for-each
  408. (case-lambda*
  409. ((f v)
  410. (let lp ((i 0))
  411. (when (< i (vector-length v))
  412. (f (vector-ref v i))
  413. (lp (1+ i)))))
  414. ((f v . v*)
  415. (let ((len (apply min (vector-length v) (map vector-length v*))))
  416. (let lp ((i 0))
  417. (when (< i len)
  418. (apply f (vector-ref v i) (map (lambda (v) (vector-ref v i)) v*))
  419. (lp (1+ i))))))))
  420. (define (vector-append . vectors)
  421. (if (null? vectors)
  422. #()
  423. (let* ((len (let lp ((vectors vectors))
  424. (if (null? vectors)
  425. 0
  426. (+ (vector-length (car vectors)) (lp (cdr vectors))))))
  427. (out (make-vector len #f)))
  428. (let lp ((i 0) (j 0) (v (car vectors)) (v* (cdr vectors)))
  429. (cond
  430. ((< j (vector-length v))
  431. (vector-set! out i (vector-ref v j))
  432. (lp (1+ i) (1+ j) v v*))
  433. ((null? v*)
  434. out)
  435. (else
  436. (lp i 0 (car v*) (cdr v*))))))))
  437. (define vector->string
  438. (case-lambda*
  439. ((v) (list->string (vector->list v)))
  440. ((v start #:optional (end (vector-length v)))
  441. (vector->string (vector-copy v start end)))))
  442. (define (%subbytevector bv start end)
  443. (define mlen (- end start))
  444. (define out (make-bytevector mlen))
  445. (bytevector-copy! bv start out 0 mlen)
  446. out)
  447. (define (%subbytevector1 bv start)
  448. (%subbytevector bv start (bytevector-length bv)))
  449. (define r7:bytevector-copy!
  450. (case-lambda*
  451. ((to at from #:optional
  452. (start 0)
  453. (end (+ start
  454. (min (- (bytevector-length from) start)
  455. (- (bytevector-length to) at)))))
  456. (bytevector-copy! from start to at (- end start)))))
  457. (define r7:bytevector-copy
  458. (case-lambda*
  459. ((bv) (bytevector-copy bv))
  460. ((bv start #:optional (end (bytevector-length bv)))
  461. (%subbytevector bv start end))))
  462. (define r7:utf8->string
  463. (case-lambda*
  464. ((bv) (utf8->string bv))
  465. ((bv start #:optional (end (bytevector-length bv)))
  466. (utf8->string (%subbytevector bv start end)))))
  467. (define (square x) (* x x))
  468. (define (r7:expt x y)
  469. (if (eqv? x 0.0)
  470. (exact->inexact (expt x y))
  471. (expt x y)))
  472. (define (features)
  473. (append
  474. (case (native-endianness)
  475. ((big) '(big-endian))
  476. ((little) '(little-endian))
  477. (else '()))
  478. %cond-expand-features))
  479. (define (input-port-open? port)
  480. (and (not (port-closed? port)) (input-port? port)))
  481. (define (output-port-open? port)
  482. (and (not (port-closed? port)) (output-port? port)))