primitives.scm 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. ;;; open-coding primitive procedures
  2. ;; Copyright (C) 2009-2015, 2017-2023 Free Software Foundation, Inc.
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 3 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. ;;; Code:
  17. (define-module (language tree-il primitives)
  18. #:use-module (system base pmatch)
  19. #:use-module (ice-9 match)
  20. #:use-module (ice-9 threads)
  21. #:use-module (rnrs bytevectors)
  22. #:use-module (system base syntax)
  23. #:use-module (language tree-il)
  24. #:use-module (srfi srfi-4)
  25. #:use-module (srfi srfi-16)
  26. #:export (resolve-primitives add-interesting-primitive!
  27. expand-primcall expand-primitives
  28. effect-free-primitive? effect+exception-free-primitive?
  29. constructor-primitive?
  30. singly-valued-primitive? equality-primitive?
  31. bailout-primitive?
  32. negate-primitive))
  33. ;; When adding to this, be sure to update *multiply-valued-primitives*
  34. ;; if appropriate.
  35. (define *interesting-primitive-names*
  36. '(apply
  37. call-with-values
  38. call-with-current-continuation
  39. call/cc
  40. dynamic-wind
  41. values
  42. eq? eqv? equal?
  43. memq memv
  44. = < > <= >= zero? positive? negative?
  45. + * - / 1- 1+ quotient remainder modulo exact->inexact
  46. expt
  47. ash logand logior logxor lognot logtest logbit?
  48. sqrt abs floor ceiling sin cos tan asin acos atan
  49. not
  50. pair? null? list? symbol? vector? string? struct? number? char? nil?
  51. eof-object?
  52. bytevector? keyword? bitvector?
  53. symbol->string string->symbol
  54. procedure? thunk?
  55. complex? real? rational? inf? nan? integer? exact? inexact? even? odd?
  56. exact-integer?
  57. char<? char<=? char>=? char>?
  58. integer->char char->integer number->string string->number
  59. acons cons cons*
  60. list vector
  61. car cdr
  62. set-car! set-cdr!
  63. caar cadr cdar cddr
  64. caaar caadr cadar caddr cdaar cdadr cddar cdddr
  65. caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
  66. cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
  67. length
  68. make-vector vector-length vector-ref vector-set!
  69. variable? variable-ref variable-set!
  70. variable-bound?
  71. current-module define!
  72. current-thread fluid-ref fluid-set! with-fluid* with-dynamic-state
  73. call-with-prompt
  74. abort-to-prompt* abort-to-prompt
  75. make-prompt-tag
  76. throw error scm-error
  77. string-length string-ref string-set!
  78. make-struct/simple struct-vtable struct-ref struct-set!
  79. bytevector-length
  80. bytevector-u8-ref bytevector-u8-set!
  81. bytevector-s8-ref bytevector-s8-set!
  82. u8vector-ref u8vector-set! s8vector-ref s8vector-set!
  83. bytevector-u16-ref bytevector-u16-set!
  84. bytevector-u16-native-ref bytevector-u16-native-set!
  85. bytevector-s16-ref bytevector-s16-set!
  86. bytevector-s16-native-ref bytevector-s16-native-set!
  87. u16vector-ref u16vector-set! s16vector-ref s16vector-set!
  88. bytevector-u32-ref bytevector-u32-set!
  89. bytevector-u32-native-ref bytevector-u32-native-set!
  90. bytevector-s32-ref bytevector-s32-set!
  91. bytevector-s32-native-ref bytevector-s32-native-set!
  92. u32vector-ref u32vector-set! s32vector-ref s32vector-set!
  93. bytevector-u64-ref bytevector-u64-set!
  94. bytevector-u64-native-ref bytevector-u64-native-set!
  95. bytevector-s64-ref bytevector-s64-set!
  96. bytevector-s64-native-ref bytevector-s64-native-set!
  97. u64vector-ref u64vector-set! s64vector-ref s64vector-set!
  98. bytevector-ieee-single-ref bytevector-ieee-single-set!
  99. bytevector-ieee-single-native-ref bytevector-ieee-single-native-set!
  100. bytevector-ieee-double-ref bytevector-ieee-double-set!
  101. bytevector-ieee-double-native-ref bytevector-ieee-double-native-set!
  102. f32vector-ref f32vector-set! f64vector-ref f64vector-set!))
  103. (define (add-interesting-primitive! name)
  104. (hashq-set! *interesting-primitive-vars*
  105. (or (module-variable (current-module) name)
  106. (error "unbound interesting primitive" name))
  107. name))
  108. (define *interesting-primitive-vars* (make-hash-table))
  109. (for-each add-interesting-primitive! *interesting-primitive-names*)
  110. (define *primitive-constructors*
  111. ;; Primitives that return a fresh object.
  112. '(acons cons cons* list vector make-vector
  113. make-struct/simple
  114. make-prompt-tag))
  115. (define *primitive-accessors*
  116. ;; Primitives that are pure, but whose result depends on the mutable
  117. ;; memory pointed to by their operands.
  118. ;;
  119. ;; Note: if you add an accessor here, be sure to add a corresponding
  120. ;; case in (language tree-il effects)!
  121. '(vector-ref
  122. car cdr
  123. memq memv
  124. struct-ref
  125. string-ref
  126. bytevector-u8-ref bytevector-s8-ref
  127. bytevector-u16-ref bytevector-u16-native-ref
  128. bytevector-s16-ref bytevector-s16-native-ref
  129. bytevector-u32-ref bytevector-u32-native-ref
  130. bytevector-s32-ref bytevector-s32-native-ref
  131. bytevector-u64-ref bytevector-u64-native-ref
  132. bytevector-s64-ref bytevector-s64-native-ref
  133. bytevector-ieee-single-ref bytevector-ieee-single-native-ref
  134. bytevector-ieee-double-ref bytevector-ieee-double-native-ref))
  135. (define *effect-free-primitives*
  136. `(values
  137. eq? eqv? equal?
  138. = < > <= >= zero? positive? negative?
  139. expt ash logand logior logxor lognot logtest logbit?
  140. + * - / 1- 1+ sqrt abs quotient remainder modulo exact->inexact
  141. floor ceiling sin cos tan asin acos atan
  142. not
  143. pair? null? nil? list?
  144. symbol? variable? vector? struct? string? number? char?
  145. bytevector? keyword? bitvector? atomic-box?
  146. complex? real? rational? inf? nan? integer? exact? inexact? even? odd?
  147. exact-integer?
  148. char<? char<=? char>=? char>?
  149. integer->char char->integer number->string string->number
  150. symbol->string string->symbol
  151. struct-vtable
  152. length string-length vector-length bytevector-length
  153. ;; These all should get expanded out by expand-primitives.
  154. caar cadr cdar cddr
  155. caaar caadr cadar caddr cdaar cdadr cddar cdddr
  156. caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
  157. cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
  158. ,@*primitive-constructors*
  159. ,@*primitive-accessors*))
  160. ;; Like *effect-free-primitives* above, but further restricted in that they
  161. ;; cannot raise exceptions.
  162. (define *effect+exception-free-primitives*
  163. '(values
  164. eq? eqv? equal?
  165. not
  166. pair? null? nil? list?
  167. symbol? variable? vector? struct? string? number? char? eof-object?
  168. exact-integer?
  169. bytevector? keyword? bitvector?
  170. procedure? thunk? atomic-box?
  171. acons cons cons* list vector))
  172. ;; Primitives that don't always return one value.
  173. (define *multiply-valued-primitives*
  174. '(apply
  175. call-with-values
  176. call-with-current-continuation
  177. call/cc
  178. dynamic-wind
  179. values
  180. call-with-prompt
  181. @abort abort-to-prompt))
  182. ;; Procedures that cause a nonlocal, non-resumable abort.
  183. (define *bailout-primitives*
  184. '(throw error scm-error))
  185. ;; Negatable predicates.
  186. (define *negatable-primitives*
  187. '((even? . odd?)
  188. (exact? . inexact?)
  189. ;; (< <= > >=) are not negatable because of NaNs.
  190. (char<? . char>=?)
  191. (char>? . char<=?)))
  192. (define *equality-primitives*
  193. '(eq? eqv? equal?))
  194. (define *effect-free-primitive-table* (make-hash-table))
  195. (define *effect+exceptions-free-primitive-table* (make-hash-table))
  196. (define *equality-primitive-table* (make-hash-table))
  197. (define *multiply-valued-primitive-table* (make-hash-table))
  198. (define *bailout-primitive-table* (make-hash-table))
  199. (define *negatable-primitive-table* (make-hash-table))
  200. (for-each (lambda (x)
  201. (hashq-set! *effect-free-primitive-table* x #t))
  202. *effect-free-primitives*)
  203. (for-each (lambda (x)
  204. (hashq-set! *effect+exceptions-free-primitive-table* x #t))
  205. *effect+exception-free-primitives*)
  206. (for-each (lambda (x)
  207. (hashq-set! *equality-primitive-table* x #t))
  208. *equality-primitives*)
  209. (for-each (lambda (x)
  210. (hashq-set! *multiply-valued-primitive-table* x #t))
  211. *multiply-valued-primitives*)
  212. (for-each (lambda (x)
  213. (hashq-set! *bailout-primitive-table* x #t))
  214. *bailout-primitives*)
  215. (for-each (lambda (x)
  216. (hashq-set! *negatable-primitive-table* (car x) (cdr x))
  217. (hashq-set! *negatable-primitive-table* (cdr x) (car x)))
  218. *negatable-primitives*)
  219. (define (constructor-primitive? prim)
  220. (memq prim *primitive-constructors*))
  221. (define (effect-free-primitive? prim)
  222. (hashq-ref *effect-free-primitive-table* prim))
  223. (define (effect+exception-free-primitive? prim)
  224. (hashq-ref *effect+exceptions-free-primitive-table* prim))
  225. (define (equality-primitive? prim)
  226. (hashq-ref *equality-primitive-table* prim))
  227. (define (singly-valued-primitive? prim)
  228. (not (hashq-ref *multiply-valued-primitive-table* prim)))
  229. (define (bailout-primitive? prim)
  230. (hashq-ref *bailout-primitive-table* prim))
  231. (define (negate-primitive prim)
  232. (hashq-ref *negatable-primitive-table* prim))
  233. (define (resolve-primitives x mod)
  234. (define local-definitions
  235. (make-hash-table))
  236. ;; Assume that any definitions with primitive names in the root module
  237. ;; have the same semantics as the primitives.
  238. (unless (eq? mod the-root-module)
  239. (let collect-local-definitions ((x x))
  240. (record-case x
  241. ((<toplevel-define> name)
  242. (hashq-set! local-definitions name #t))
  243. ((<seq> head tail)
  244. (collect-local-definitions head)
  245. (collect-local-definitions tail))
  246. (else #f))))
  247. (post-order
  248. (lambda (x)
  249. (or
  250. (record-case x
  251. ((<toplevel-ref> src name)
  252. (and=> (and (not (hashq-ref local-definitions name))
  253. (hashq-ref *interesting-primitive-vars*
  254. (module-variable mod name)))
  255. (lambda (name) (make-primitive-ref src name))))
  256. ((<module-ref> src mod name public?)
  257. ;; for the moment, we're disabling primitive resolution for
  258. ;; public refs because resolve-interface can raise errors.
  259. (and=> (and=> (resolve-module mod)
  260. (if public?
  261. module-public-interface
  262. identity))
  263. (lambda (m)
  264. (and=> (hashq-ref *interesting-primitive-vars*
  265. (module-variable m name))
  266. (lambda (name)
  267. (make-primitive-ref src name))))))
  268. ((<call> src proc args)
  269. (and (primitive-ref? proc)
  270. (make-primcall src (primitive-ref-name proc) args)))
  271. (else #f))
  272. x))
  273. x))
  274. (define *primitive-expand-table* (make-hash-table))
  275. (define (expand-primcall x)
  276. (record-case x
  277. ((<primcall> src name args)
  278. (let ((expand (hashq-ref *primitive-expand-table* name)))
  279. (or (and expand (apply expand src args))
  280. x)))
  281. (else x)))
  282. (define (expand-primitives x)
  283. (pre-order expand-primcall x))
  284. (define-syntax-rule (define-primitive-expander! sym proc)
  285. (hashq-set! *primitive-expand-table* sym proc))
  286. (define-syntax primitive-expander
  287. (lambda (stx)
  288. (define (expand-args args)
  289. (syntax-case args ()
  290. (() #''())
  291. ((a . b) #`(cons #,(expand-expr #'a) #,(expand-args #'b)))
  292. (a (expand-expr #'a))))
  293. (define (expand-expr body)
  294. (syntax-case body (quote)
  295. (id (identifier? #'id) #'id)
  296. ((quote x) #'(make-const src 'x))
  297. ((op . args) #`(make-primcall src 'op #,(expand-args #'args)))
  298. (x (self-evaluating? (syntax->datum #'x)) #'(make-const src x))))
  299. (define (match-clauses args+body)
  300. (syntax-case args+body (if)
  301. (() '())
  302. ((args body . args+body)
  303. (cons #`(args #,(expand-expr #'body))
  304. (match-clauses #'args+body)))))
  305. (syntax-case stx ()
  306. ((_ args+body ...)
  307. #`(lambda (src . args)
  308. (match args
  309. #,@(match-clauses #'(args+body ...))
  310. (_ #f)))))))
  311. (define-syntax-rule (define-primitive-expander sym . clauses)
  312. (define-primitive-expander! 'sym (primitive-expander . clauses)))
  313. ;; Oddly, scm-error is just an explicitly 5-argument `throw'. Weird.
  314. (define-primitive-expander scm-error (key who message args data)
  315. (throw key who message args data))
  316. (define (escape-format-directives str)
  317. (string-join (string-split str #\~) "~~"))
  318. (define-primitive-expander! 'error
  319. (match-lambda*
  320. ((src)
  321. (make-primcall src 'throw
  322. (list (make-const src 'misc-error)
  323. (make-const src #f)
  324. (make-const src "?")
  325. (make-const src #f)
  326. (make-const src #f))))
  327. ((src ($ <const> src2 (? string? message)) . args)
  328. (let ((msg (string-join (cons (escape-format-directives message)
  329. (make-list (length args) "~S")))))
  330. (make-primcall src 'throw
  331. (list (make-const src 'misc-error)
  332. (make-const src #f)
  333. (make-const src2 msg)
  334. (make-primcall src 'list args)
  335. (make-const src #f)))))
  336. ((src message . args)
  337. (let ((msg (string-join (cons "~A" (make-list (length args) "~S")))))
  338. (make-primcall src 'throw
  339. (list (make-const src 'misc-error)
  340. (make-const src #f)
  341. (make-const src msg)
  342. (make-primcall src 'list (cons message args))
  343. (make-const src #f)))))))
  344. (define-primitive-expander define! (sym val)
  345. (%variable-set! (module-ensure-local-variable! (current-module) sym) val))
  346. (define-primitive-expander module-define! (mod sym val)
  347. (%variable-set! (module-ensure-local-variable! mod sym) val))
  348. (define-primitive-expander! 'eof-object?
  349. (match-lambda*
  350. ((src obj)
  351. (make-primcall src 'eq? (list obj (make-const #f the-eof-object))))
  352. (_ #f)))
  353. (define-primitive-expander zero? (x)
  354. (= x 0))
  355. (define-primitive-expander positive? (x)
  356. (> x 0))
  357. (define-primitive-expander negative? (x)
  358. (< x 0))
  359. ;; FIXME: All the code that uses `const?' is redundant with `peval'.
  360. (define-primitive-expander 1+ (x)
  361. (+ x 1))
  362. (define-primitive-expander 1- (x)
  363. (- x 1))
  364. (define-primitive-expander +
  365. () 0
  366. (x) (values x)
  367. (x y) (+ x y)
  368. (x y z ... last) (+ (+ x y . z) last))
  369. (define-primitive-expander *
  370. () 1
  371. (x) (values x)
  372. (x y z ... last) (* (* x y . z) last))
  373. (define-primitive-expander -
  374. (x) (- 0 x)
  375. (x y) (- x y)
  376. (x y z ... last) (- (- x y . z) last))
  377. (define-primitive-expander /
  378. (x) (/ 1 x)
  379. (x y z ... last) (/ (/ x y . z) last))
  380. (define-primitive-expander atan
  381. (x) (atan x)
  382. (x y) (atan2 x y))
  383. (define-primitive-expander logior
  384. () 0
  385. (x) (logior x 0)
  386. (x y) (logior x y)
  387. (x y z ... last) (logior (logior x y . z) last))
  388. (define-primitive-expander logand
  389. () -1
  390. (x) (logand x -1)
  391. (x y) (logand x y)
  392. (x y z ... last) (logand (logand x y . z) last))
  393. (define-primitive-expander! 'make-vector
  394. (match-lambda*
  395. ((src len)
  396. (make-primcall src 'make-vector (list len (make-const src *unspecified*))))
  397. ((src len init)
  398. (make-primcall src 'make-vector (list len init)))
  399. ((src . args) ;wrong number of arguments
  400. #f)))
  401. (define-primitive-expander caar (x) (car (car x)))
  402. (define-primitive-expander cadr (x) (car (cdr x)))
  403. (define-primitive-expander cdar (x) (cdr (car x)))
  404. (define-primitive-expander cddr (x) (cdr (cdr x)))
  405. (define-primitive-expander caaar (x) (car (car (car x))))
  406. (define-primitive-expander caadr (x) (car (car (cdr x))))
  407. (define-primitive-expander cadar (x) (car (cdr (car x))))
  408. (define-primitive-expander caddr (x) (car (cdr (cdr x))))
  409. (define-primitive-expander cdaar (x) (cdr (car (car x))))
  410. (define-primitive-expander cdadr (x) (cdr (car (cdr x))))
  411. (define-primitive-expander cddar (x) (cdr (cdr (car x))))
  412. (define-primitive-expander cdddr (x) (cdr (cdr (cdr x))))
  413. (define-primitive-expander caaaar (x) (car (car (car (car x)))))
  414. (define-primitive-expander caaadr (x) (car (car (car (cdr x)))))
  415. (define-primitive-expander caadar (x) (car (car (cdr (car x)))))
  416. (define-primitive-expander caaddr (x) (car (car (cdr (cdr x)))))
  417. (define-primitive-expander cadaar (x) (car (cdr (car (car x)))))
  418. (define-primitive-expander cadadr (x) (car (cdr (car (cdr x)))))
  419. (define-primitive-expander caddar (x) (car (cdr (cdr (car x)))))
  420. (define-primitive-expander cadddr (x) (car (cdr (cdr (cdr x)))))
  421. (define-primitive-expander cdaaar (x) (cdr (car (car (car x)))))
  422. (define-primitive-expander cdaadr (x) (cdr (car (car (cdr x)))))
  423. (define-primitive-expander cdadar (x) (cdr (car (cdr (car x)))))
  424. (define-primitive-expander cdaddr (x) (cdr (car (cdr (cdr x)))))
  425. (define-primitive-expander cddaar (x) (cdr (cdr (car (car x)))))
  426. (define-primitive-expander cddadr (x) (cdr (cdr (car (cdr x)))))
  427. (define-primitive-expander cdddar (x) (cdr (cdr (cdr (car x)))))
  428. (define-primitive-expander cddddr (x) (cdr (cdr (cdr (cdr x)))))
  429. (define-primitive-expander cons*
  430. (x) (values x)
  431. (x y) (cons x y)
  432. (x y . rest) (cons x (cons* y . rest)))
  433. (define-primitive-expander acons (x y z)
  434. (cons (cons x y) z))
  435. (define-primitive-expander call/cc (proc)
  436. (call-with-current-continuation proc))
  437. (define-primitive-expander u8vector-ref (vec i)
  438. (bytevector-u8-ref vec i))
  439. (define-primitive-expander u8vector-set! (vec i x)
  440. (bytevector-u8-set! vec i x))
  441. (define-primitive-expander s8vector-ref (vec i)
  442. (bytevector-s8-ref vec i))
  443. (define-primitive-expander s8vector-set! (vec i x)
  444. (bytevector-s8-set! vec i x))
  445. (define-primitive-expander u16vector-ref (vec i)
  446. (bytevector-u16-native-ref vec (* i 2)))
  447. (define-primitive-expander u16vector-set! (vec i x)
  448. (bytevector-u16-native-set! vec (* i 2) x))
  449. (define-primitive-expander s16vector-ref (vec i)
  450. (bytevector-s16-native-ref vec (* i 2)))
  451. (define-primitive-expander s16vector-set! (vec i x)
  452. (bytevector-s16-native-set! vec (* i 2) x))
  453. (define-primitive-expander u32vector-ref (vec i)
  454. (bytevector-u32-native-ref vec (* i 4)))
  455. (define-primitive-expander u32vector-set! (vec i x)
  456. (bytevector-u32-native-set! vec (* i 4) x))
  457. (define-primitive-expander s32vector-ref (vec i)
  458. (bytevector-s32-native-ref vec (* i 4)))
  459. (define-primitive-expander s32vector-set! (vec i x)
  460. (bytevector-s32-native-set! vec (* i 4) x))
  461. (define-primitive-expander u64vector-ref (vec i)
  462. (bytevector-u64-native-ref vec (* i 8)))
  463. (define-primitive-expander u64vector-set! (vec i x)
  464. (bytevector-u64-native-set! vec (* i 8) x))
  465. (define-primitive-expander s64vector-ref (vec i)
  466. (bytevector-s64-native-ref vec (* i 8)))
  467. (define-primitive-expander s64vector-set! (vec i x)
  468. (bytevector-s64-native-set! vec (* i 8) x))
  469. (define-primitive-expander f32vector-ref (vec i)
  470. (bytevector-ieee-single-native-ref vec (* i 4)))
  471. (define-primitive-expander f32vector-set! (vec i x)
  472. (bytevector-ieee-single-native-set! vec (* i 4) x))
  473. (define-primitive-expander f32vector-ref (vec i)
  474. (bytevector-ieee-single-native-ref vec (* i 4)))
  475. (define-primitive-expander f32vector-set! (vec i x)
  476. (bytevector-ieee-single-native-set! vec (* i 4) x))
  477. (define-primitive-expander f64vector-ref (vec i)
  478. (bytevector-ieee-double-native-ref vec (* i 8)))
  479. (define-primitive-expander f64vector-set! (vec i x)
  480. (bytevector-ieee-double-native-set! vec (* i 8) x))
  481. (define-primitive-expander f64vector-ref (vec i)
  482. (bytevector-ieee-double-native-ref vec (* i 8)))
  483. (define-primitive-expander f64vector-set! (vec i x)
  484. (bytevector-ieee-double-native-set! vec (* i 8) x))
  485. (define (bind-lexicals src exps k)
  486. (match exps
  487. (() (k '()))
  488. ((exp . exps)
  489. (with-lexicals src (exp)
  490. (bind-lexicals src exps (lambda (exps) (k (cons exp exps))))))))
  491. (define (expand-eq prim)
  492. (case-lambda
  493. ((src) (make-const src #t))
  494. ((src a) (make-const src #t))
  495. ((src a b) #f)
  496. ((src . args)
  497. (bind-lexicals
  498. src args
  499. (lambda (args)
  500. (match args
  501. ((a . args)
  502. (let lp ((args args))
  503. (match args
  504. ((b)
  505. (make-primcall src prim (list a b)))
  506. ((b . args)
  507. (make-conditional src (make-primcall src prim (list a b))
  508. (lp args)
  509. (make-const src #f))))))))))))
  510. (define-primitive-expander! 'eq? (expand-eq 'eq?))
  511. (define-primitive-expander! 'eqv? (expand-eq 'eqv?))
  512. (define-primitive-expander! 'equal? (expand-eq 'equal?))
  513. (define (expand-chained-comparisons prim)
  514. (case-lambda
  515. ((src) (make-const src #t))
  516. ((src a)
  517. ;; (< x) -> (begin (< x 0) #t). Residualizes side-effects from x
  518. ;; and, for numeric comparisons, checks that x is a number.
  519. (make-seq src
  520. (make-primcall src prim (list a (make-const src 0)))
  521. (make-const src #t)))
  522. ((src a b) #f)
  523. ((src . args)
  524. (bind-lexicals
  525. src args
  526. (lambda (args)
  527. (let lp ((args args))
  528. (match args
  529. ((a b)
  530. (make-primcall src prim (list a b)))
  531. ((a b . args)
  532. (make-conditional src (make-primcall src prim (list a b))
  533. (lp (cons b args))
  534. (make-const src #f))))))))
  535. (else #f)))
  536. (for-each (lambda (prim)
  537. (define-primitive-expander! prim
  538. (expand-chained-comparisons prim)))
  539. '(< <= = >= > eq?))
  540. (define (character-comparison-expander char< <)
  541. (lambda (src . args)
  542. (expand-primcall
  543. (make-primcall src <
  544. (map (lambda (arg)
  545. (make-primcall src 'char->integer (list arg)))
  546. args)))))
  547. (for-each (match-lambda
  548. ((char< . <)
  549. (define-primitive-expander! char<
  550. (character-comparison-expander char< <))))
  551. '((char<? . <)
  552. (char>? . >)
  553. (char<=? . <=)
  554. (char>=? . >=)
  555. (char=? . =)))
  556. (define-primitive-expander! 'call-with-prompt
  557. (case-lambda
  558. ((src tag thunk handler)
  559. (match handler
  560. (($ <lambda> _ _ ($ <lambda-case> _ _ #f _ #f () _ _ #f))
  561. (make-prompt src #f tag thunk handler))
  562. (_
  563. ;; Eta-convert prompts without inline handlers.
  564. (let ((h (gensym "h "))
  565. (args (gensym "args ")))
  566. (define-syntax-rule (primcall name . args)
  567. (make-primcall src 'name (list . args)))
  568. (define-syntax-rule (const val)
  569. (make-const src val))
  570. (with-lexicals src (handler)
  571. (make-conditional
  572. src
  573. (primcall procedure? handler)
  574. (make-prompt
  575. src #f tag thunk
  576. (make-lambda
  577. src '()
  578. (make-lambda-case
  579. src '() #f 'args #f '() (list args)
  580. (primcall apply handler (make-lexical-ref #f 'args args))
  581. #f)))
  582. (primcall throw
  583. (const 'wrong-type-arg)
  584. (const "call-with-prompt")
  585. (const "Wrong type (expecting procedure): ~S")
  586. (primcall list handler)
  587. (primcall list handler))))))))
  588. (else #f)))
  589. (define-primitive-expander! 'abort-to-prompt*
  590. (case-lambda
  591. ((src tag tail-args)
  592. (make-abort src tag '() tail-args))
  593. (else #f)))
  594. (define-primitive-expander! 'abort-to-prompt
  595. (case-lambda
  596. ((src tag . args)
  597. (make-abort src tag args (make-const #f '())))
  598. (else #f)))