primitives.scm 17 KB

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