primitives.scm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. ;;; Hoot primitives
  2. ;;; Copyright (C) 2023, 2024 Igalia, S.L.
  3. ;;;
  4. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  5. ;;; you may not use this file except in compliance with the License.
  6. ;;; You may obtain a copy of the License at
  7. ;;;
  8. ;;; http://www.apache.org/licenses/LICENSE-2.0
  9. ;;;
  10. ;;; Unless required by applicable law or agreed to in writing, software
  11. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  12. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ;;; See the License for the specific language governing permissions and
  14. ;;; limitations under the License.
  15. ;;; Commentary:
  16. ;;;
  17. ;;; This file exists only to be a place to define primitives for use by
  18. ;;; Hoot user code. It also exports implementation-detail primitives
  19. ;;; for use by the Hoot standard library; eventually this will change to
  20. ;;; avoid exposing these nonstandard primitives to users.
  21. ;;;
  22. ;;; Code:
  23. (define-module (hoot primitives)
  24. #:pure
  25. #:use-module (hoot frontend)
  26. #:use-module ((guile)
  27. #:select
  28. (canonicalize-path
  29. search-path
  30. define-syntax-rule
  31. syntax-case syntax quasisyntax unsyntax unsyntax-splicing
  32. syntax->datum datum->syntax identifier?
  33. generate-temporaries free-identifier=? bound-identifier=?
  34. with-syntax identifier-syntax make-variable-transformer
  35. syntax-violation procedure-property
  36. lambda* case-lambda* define*
  37. call-with-prompt abort-to-prompt
  38. ash logand logior logxor lognot logtest logbit?
  39. keyword?
  40. bitvector?
  41. cons*
  42. fluid? fluid-ref fluid-set! with-fluid* with-dynamic-state
  43. make-variable variable-ref variable-set!
  44. keyword->symbol symbol->keyword
  45. exact->inexact
  46. error
  47. raise-exception
  48. eval-when
  49. make-struct/simple struct? struct-vtable
  50. struct-ref struct-set!
  51. gensym
  52. string-utf8-length
  53. make-record-type record-type-parents
  54. struct-vtable? vtable-index-printer
  55. make-fluid
  56. make-parameter parameter? parameter-fluid parameter-converter
  57. hashq hashv hash
  58. make-regexp regexp? regexp-exec
  59. string-copy
  60. ;; Helpers for syntax-module-bindings.
  61. resolve-module variable-bound? macro?
  62. module-for-each module-uses))
  63. #:use-module ((system syntax internal)
  64. #:select (syntax-local-binding
  65. make-syntax syntax?
  66. syntax-expression syntax-wrap
  67. syntax-module syntax-sourcev))
  68. #:use-module ((system base target) #:select (target-runtime))
  69. ;; A bug in Guile: the public interface of (guile) uses (ice-9 ports),
  70. ;; which should re-export all its bindings, but #:select doesn't work
  71. ;; on interfaces that use interfaces. For now, import the-eof-object
  72. ;; from (ice-9 ports) instead.
  73. #:use-module ((ice-9 ports) #:select (the-eof-object %make-void-port))
  74. #:use-module ((ice-9 atomic)
  75. #:select
  76. (make-atomic-box
  77. atomic-box-ref atomic-box-set!
  78. atomic-box-swap! atomic-box-compare-and-swap!))
  79. #:use-module ((ice-9 regex)
  80. #:select (regexp-match?
  81. match:string
  82. match:start
  83. match:end
  84. match:count
  85. match:substring))
  86. #:use-module ((rnrs bytevectors)
  87. #:select
  88. (make-bytevector
  89. bytevector?
  90. bytevector-copy!
  91. bytevector-length
  92. bytevector-u8-ref bytevector-u8-set!
  93. bytevector-s8-ref bytevector-s8-set!
  94. bytevector-u16-native-ref bytevector-u16-native-set!
  95. bytevector-s16-native-ref bytevector-s16-native-set!
  96. bytevector-u32-native-ref bytevector-u32-native-set!
  97. bytevector-s32-native-ref bytevector-s32-native-set!
  98. bytevector-u64-native-ref bytevector-u64-native-set!
  99. bytevector-s64-native-ref bytevector-s64-native-set!
  100. bytevector-ieee-single-native-ref
  101. bytevector-ieee-single-native-set!
  102. bytevector-ieee-double-native-ref
  103. bytevector-ieee-double-native-set!
  104. string->utf8 utf8->string))
  105. #:use-module ((scheme base)
  106. #:select
  107. (_
  108. ... => else
  109. lambda
  110. define let let* letrec letrec*
  111. or and
  112. begin
  113. if cond case when unless
  114. do
  115. set!
  116. quote quasiquote unquote unquote-splicing
  117. include include-ci
  118. define-syntax let-syntax letrec-syntax
  119. syntax-rules syntax-error
  120. guard
  121. ;; R7RS control
  122. dynamic-wind
  123. ;; R7RS values
  124. values
  125. call-with-values
  126. apply
  127. ;; R7RS pairs
  128. pair?
  129. cons
  130. car
  131. cdr
  132. set-car!
  133. set-cdr!
  134. ;; R7RS lists
  135. null?
  136. append
  137. ;; R7RS numerics
  138. *
  139. +
  140. -
  141. /
  142. <
  143. <=
  144. =
  145. >
  146. >=
  147. abs
  148. floor
  149. ceiling
  150. number?
  151. complex?
  152. real?
  153. rational?
  154. integer?
  155. exact-integer?
  156. exact?
  157. inexact?
  158. quotient
  159. remainder
  160. modulo
  161. ;; R7RS chars
  162. char->integer
  163. integer->char
  164. char?
  165. ;; R7RS ports
  166. eof-object?
  167. ;; R7RS equality
  168. eq?
  169. eqv?
  170. ;; R7RS strings
  171. string?
  172. string-length
  173. string-ref
  174. string->list
  175. ;; Symbols
  176. symbol?
  177. symbol->string
  178. string->symbol
  179. ;; R7RS vectors
  180. vector?
  181. make-vector
  182. vector
  183. vector-length
  184. vector-ref
  185. vector-set!
  186. procedure?))
  187. #:use-module ((scheme case-lambda)
  188. #:select (case-lambda))
  189. #:use-module ((scheme inexact)
  190. #:select (inexact sin cos tan asin acos atan sqrt))
  191. #:re-export
  192. ( ;; R7RS syntax
  193. _
  194. ... => else
  195. lambda case-lambda
  196. define let let* letrec letrec*
  197. or and
  198. begin
  199. if cond case when unless
  200. do
  201. set!
  202. quote quasiquote unquote unquote-splicing
  203. include include-ci
  204. define-syntax let-syntax letrec-syntax
  205. syntax-rules syntax-error
  206. ;; FIXME: These two need Hoot support.
  207. ;; guard
  208. ;; Most primitives can only appear in primcalls, so we expose them as
  209. ;; %foo instead of foo, relying on the prelude to wrap them in
  210. ;; lambdas to ensure they are always called with the right number of
  211. ;; arguments, even when used as a value. The three exceptions are
  212. ;; `apply`, `abort-to-prompt`, and `values`.
  213. ;; Guile syntax extensions
  214. define-syntax-rule
  215. syntax-case syntax quasisyntax unsyntax unsyntax-splicing
  216. (syntax->datum . %syntax->datum)
  217. (datum->syntax . %datum->syntax)
  218. identifier? generate-temporaries free-identifier=? bound-identifier=?
  219. with-syntax identifier-syntax make-variable-transformer
  220. syntax-local-binding syntax-violation procedure-property
  221. target-runtime
  222. gensym
  223. lambda* case-lambda* define*
  224. ;; Guile VM primitives
  225. (make-record-type . guile:make-record-type)
  226. (record-type-parents . guile:record-type-parents)
  227. (vtable-index-printer . guile:vtable-index-printer)
  228. (struct-vtable? . guile:struct-vtable?)
  229. (make-fluid . guile:make-fluid)
  230. (fluid? . guile:fluid?)
  231. (make-parameter . guile:make-parameter)
  232. (parameter? . guile:parameter?)
  233. (parameter-fluid . guile:parameter-fluid)
  234. (parameter-converter . guile:parameter-converter)
  235. (%make-void-port . guile:make-void-port)
  236. (hashq . guile:hashq)
  237. (hashv . guile:hashv)
  238. (hash . guile:hash)
  239. (make-bytevector . guile:make-bytevector)
  240. (bytevector-copy! . guile:bytevector-copy!)
  241. (string->list . guile:string->list)
  242. (string-copy . guile:string-copy)
  243. (syntax? . guile:syntax?)
  244. (make-syntax . guile:make-syntax)
  245. (syntax-expression . guile:syntax-expression)
  246. (syntax-wrap . guile:syntax-wrap)
  247. (syntax-module . guile:syntax-module)
  248. (syntax-sourcev . guile:syntax-sourcev)
  249. (make-regexp . guile:make-regexp)
  250. (regexp? . guile:regexp?)
  251. (regexp-exec . guile:regexp-exec)
  252. (regexp-match? . guile:regexp-match?)
  253. (match:string . guile:match:string)
  254. (match:start . guile:match:start)
  255. (match:end . guile:match:end)
  256. (match:count . guile:match:count)
  257. (match:substring . guile:match:substring)
  258. ;; R7RS control
  259. (dynamic-wind . %dynamic-wind)
  260. ;; R7RS values
  261. (values . %values)
  262. (call-with-values . %call-with-values)
  263. apply
  264. ;; R7RS pairs
  265. (pair? . %pair?)
  266. (cons . %cons)
  267. (car . %car)
  268. (cdr . %cdr)
  269. (set-car! . %set-car!)
  270. (set-cdr! . %set-cdr!)
  271. ;; R7RS lists
  272. (null? . %null?)
  273. (append . %append)
  274. ;; R7RS bytevectors
  275. (bytevector-length . %bytevector-length)
  276. (bytevector-u8-ref . %bytevector-u8-ref)
  277. (bytevector-u8-set! . %bytevector-u8-set!)
  278. (bytevector? . %bytevector?)
  279. (string->utf8 . %string->utf8)
  280. (utf8->string . %utf8->string)
  281. (string-utf8-length . %string-utf8-length)
  282. ;; R7RS numerics
  283. (* . %*)
  284. (+ . %+)
  285. (- . %-)
  286. (/ . %/)
  287. (< . %<)
  288. (<= . %<=)
  289. (= . %=)
  290. (> . %>)
  291. (>= . %>=)
  292. (abs . %abs)
  293. (floor . %floor)
  294. (ceiling . %ceiling)
  295. (number? . %number?)
  296. (complex? . %complex?)
  297. (real? . %real?)
  298. (rational? . %rational?)
  299. (integer? . %integer?)
  300. (exact-integer? . %exact-integer?)
  301. (exact? . %exact?)
  302. (inexact? . %inexact?)
  303. ;; FIXME: we should actually be using the R7RS variants which are
  304. ;; slightly different than Guile's.
  305. (inexact . %inexact)
  306. (quotient . %quotient)
  307. (remainder . %remainder)
  308. (modulo . %modulo)
  309. (sin . %sin)
  310. (cos . %cos)
  311. (tan . %tan)
  312. (asin . %asin)
  313. (acos . %acos)
  314. (atan . %atan)
  315. (sqrt . %sqrt)
  316. ;; R7RS chars
  317. (char->integer . %char->integer)
  318. (integer->char . %integer->char)
  319. (char? . %char?)
  320. ;; R7RS ports
  321. (eof-object? . %eof-object?)
  322. ;; Parameters
  323. ;; R7RS equality
  324. (eq? . %eq?)
  325. (eqv? . %eqv?)
  326. ;; R7RS strings
  327. (string? . %string?)
  328. (string-length . %string-length)
  329. (string-ref . %string-ref)
  330. ;; Symbols
  331. (symbol? . %symbol?)
  332. (symbol->string . %symbol->string)
  333. (string->symbol . %string->symbol)
  334. ;; Keywords
  335. (symbol->keyword . %symbol->keyword)
  336. (keyword->symbol . %keyword->symbol)
  337. ;; R7RS vectors
  338. (vector? . %vector?)
  339. (make-vector . %make-vector)
  340. (vector . %vector)
  341. (vector-length . %vector-length)
  342. (vector-ref . %vector-ref)
  343. (vector-set! . %vector-set!)
  344. ;; Error handling
  345. (error . %error)
  346. (raise-exception . %raise-exception)
  347. (procedure? . %procedure?)
  348. ;; guile extensions
  349. (call-with-prompt . %call-with-prompt)
  350. (abort-to-prompt . %abort-to-prompt)
  351. (ash . %ash)
  352. (logand . %logand)
  353. (logior . %logior)
  354. (logxor . %logxor)
  355. (lognot . %lognot)
  356. (logtest . %logtest)
  357. (logbit? . %logbit?)
  358. (keyword? . %keyword?)
  359. (bitvector? . %bitvector?)
  360. (cons* . %cons*)
  361. (fluid-ref . %fluid-ref)
  362. (fluid-set! . %fluid-set!)
  363. (with-fluid* . %with-fluid*)
  364. (with-dynamic-state . %with-dynamic-state)
  365. (make-atomic-box . %make-atomic-box)
  366. (atomic-box-ref . %atomic-box-ref)
  367. (atomic-box-set! . %atomic-box-set!)
  368. (atomic-box-swap! . %atomic-box-swap!)
  369. (atomic-box-compare-and-swap! . %atomic-box-compare-and-swap!)
  370. (bytevector-s8-ref . %bytevector-s8-ref)
  371. (bytevector-s8-set! . %bytevector-s8-set!)
  372. (bytevector-u16-native-ref . %bytevector-u16-native-ref)
  373. (bytevector-u16-native-set! . %bytevector-u16-native-set!)
  374. (bytevector-s16-native-ref . %bytevector-s16-native-ref)
  375. (bytevector-s16-native-set! . %bytevector-s16-native-set!)
  376. (bytevector-u32-native-ref . %bytevector-u32-native-ref)
  377. (bytevector-u32-native-set! . %bytevector-u32-native-set!)
  378. (bytevector-s32-native-ref . %bytevector-s32-native-ref)
  379. (bytevector-s32-native-set! . %bytevector-s32-native-set!)
  380. (bytevector-u64-native-ref . %bytevector-u64-native-ref)
  381. (bytevector-u64-native-set! . %bytevector-u64-native-set!)
  382. (bytevector-s64-native-ref . %bytevector-s64-native-ref)
  383. (bytevector-s64-native-set! . %bytevector-s64-native-set!)
  384. (bytevector-ieee-single-native-ref . %bytevector-ieee-single-native-ref)
  385. (bytevector-ieee-single-native-set! . %bytevector-ieee-single-native-set!)
  386. (bytevector-ieee-double-native-ref . %bytevector-ieee-double-native-ref)
  387. (bytevector-ieee-double-native-set! . %bytevector-ieee-double-native-set!)
  388. (the-eof-object . %the-eof-object)
  389. (make-variable . %make-box)
  390. (variable-ref . %box-ref)
  391. (variable-set! . %box-set!)
  392. (make-struct/simple . %make-struct)
  393. (struct? . %struct?)
  394. (struct-vtable . %struct-vtable)
  395. (struct-ref . %struct-ref)
  396. (struct-set! . %struct-set!))
  397. #:export (%inline-wasm
  398. %wasm-import
  399. include-from-path
  400. (syntax-module-bindings . guile:syntax-module-bindings))
  401. ;; Mark as non-declarative, as we should not have inlinable exports.
  402. #:declarative? #f)
  403. (define (%inline-wasm code . args)
  404. "Emit inline WebAssembly code. @var{code} is a WebAssembly module
  405. expressed in WebAssembly's s-expression syntax. The backend expects the
  406. parsed module to contain a single function. The arguments
  407. @var{arg}... should correspond to the parameters of the function. The
  408. number of result values is also determined from the function signature."
  409. (error "target-only primitive"))
  410. (define (%wasm-import code)
  411. "Emit WebAssembly import. @var{code} is a WebAssembly module
  412. expressed in WebAssembly's s-expression syntax. The backend expects the
  413. parsed module to contain a single import."
  414. (error "target-only primitive"))
  415. (define (syntax-module-bindings id)
  416. (define local '())
  417. (define imported '())
  418. (define mod (resolve-module (cdr (syntax-module id))))
  419. (define (exclude-imported-binding? sym)
  420. ;; This is a hack.
  421. (case sym
  422. ((bound-identifier=? free-identifier=? datum->syntax
  423. syntax->datum generate-temporaries identifier?) #t)
  424. (else #f)))
  425. (define (exclude-binding? var)
  426. (if (variable-bound? var)
  427. (macro? (variable-ref var))
  428. #t))
  429. (define (for-each f l)
  430. (unless (null? l)
  431. (f (car l))
  432. (for-each f (cdr l))))
  433. (define (map f l)
  434. (if (null? l)
  435. '()
  436. (cons (f (car l)) (map f (cdr l)))))
  437. (module-for-each (lambda (sym var)
  438. (unless (exclude-binding? var)
  439. (set! local (cons sym local))))
  440. mod)
  441. (define (visit-imported-bindings m f)
  442. (for-each (lambda (i)
  443. (visit-imported-bindings i f)
  444. (module-for-each f i))
  445. (module-uses m)))
  446. (visit-imported-bindings mod
  447. (lambda (sym var)
  448. (unless (or (exclude-imported-binding? sym)
  449. (exclude-binding? var))
  450. (set! imported (cons sym imported)))))
  451. (define (bless sym) (datum->syntax id sym))
  452. (values (map bless local) (map bless imported)))
  453. (define-syntax include-from-path
  454. (lambda (x)
  455. (syntax-case x ()
  456. ((k filename)
  457. (let ((fn (syntax->datum #'filename)))
  458. (with-syntax ((fn (datum->syntax
  459. #'filename
  460. (canonicalize-path
  461. (or (search-path (append (hoot-system-load-path)
  462. (hoot-load-path))
  463. fn
  464. (hoot-load-extensions))
  465. (syntax-violation 'include-from-path
  466. "file not found in path"
  467. x #'filename))))))
  468. #'(include fn)))))))
  469. ;(add-interesting-primitive! '%inline-asm)