test-ffi.scm 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. ;;; Copyright (C) 2023, 2024 David Thompson <dave@spritely.institute>
  2. ;;;
  3. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  4. ;;; you may not use this file except in compliance with the License.
  5. ;;; You may obtain a copy of the License at
  6. ;;;
  7. ;;; http://www.apache.org/licenses/LICENSE-2.0
  8. ;;;
  9. ;;; Unless required by applicable law or agreed to in writing, software
  10. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  11. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. ;;; See the License for the specific language governing permissions and
  13. ;;; limitations under the License.
  14. ;;; Commentary:
  15. ;;;
  16. ;;; FFI tests.
  17. ;;;
  18. ;;; Code:
  19. (use-modules (ice-9 binary-ports)
  20. (ice-9 exceptions)
  21. (ice-9 popen)
  22. (ice-9 textual-ports)
  23. (srfi srfi-64)
  24. (test utils)
  25. (hoot compile)
  26. (hoot reflect)
  27. (wasm parse))
  28. (test-begin "test-ffi")
  29. (define-syntax-rule (test-ffi name expected source imports)
  30. (test-equal name
  31. expected
  32. (compile-value 'source
  33. #:imports (cons '(hoot ffi) %default-program-imports)
  34. #:wasm-imports imports)))
  35. (test-ffi
  36. "i32 param and result"
  37. 16
  38. (let ()
  39. (define-foreign fsquare
  40. "math" "square"
  41. i32 -> i32)
  42. (square 4))
  43. `(("math" . (("square" . ,(lambda (x) (* x x)))))))
  44. (test-ffi
  45. "i64 param and result"
  46. 16
  47. (let ()
  48. (define-foreign fsquare
  49. "math" "square"
  50. i64 -> i64)
  51. (square 4))
  52. `(("math" . (("square" . ,(lambda (x) (* x x)))))))
  53. (test-ffi
  54. "f32 param and result"
  55. 16.0
  56. (let ()
  57. (define-foreign fsquare
  58. "math" "fsquare"
  59. f32 -> f32)
  60. (fsquare 4.0))
  61. `(("math" . (("fsquare" . ,(lambda (x) (* x x)))))))
  62. (test-ffi
  63. "f64 param and result"
  64. 16.0
  65. (let ()
  66. (define-foreign fsquare
  67. "math" "fsquare"
  68. f64 -> f64)
  69. (fsquare 4.0))
  70. `(("math" . (("fsquare" . ,(lambda (x) (* x x)))))))
  71. (test-ffi
  72. "string param and result"
  73. "Hello, owl!"
  74. (let ()
  75. (define-foreign hello
  76. "host" "hello"
  77. (ref string) -> (ref string))
  78. (hello "owl"))
  79. `(("host" .
  80. (("hello" . ,(lambda (name) (string-append "Hello, " name "!")))))))
  81. (test-ffi
  82. "eq param and result"
  83. "hello"
  84. (let ()
  85. (define-foreign echo
  86. "host" "echo"
  87. (ref eq) -> (ref eq))
  88. (echo "hello"))
  89. `(("host" .
  90. (("echo" . ,(lambda (x) x))))))
  91. (test-ffi
  92. "maybe null string result; null case"
  93. #f
  94. (let ()
  95. (define-foreign maybe-cool
  96. "host" "maybeCool"
  97. i32 -> (ref null string))
  98. (maybe-cool 1))
  99. `(("host" .
  100. (("maybeCool" . ,(lambda (x) (and (even? x) "cool")))))))
  101. (test-ffi
  102. "maybe null string result; string case"
  103. "cool"
  104. (let ()
  105. (define-foreign maybe-cool
  106. "host" "maybeCool"
  107. i32 -> (ref null string))
  108. (maybe-cool 2))
  109. `(("host" .
  110. (("maybeCool" . ,(lambda (x) (and (even? x) "cool")))))))
  111. (test-ffi
  112. "extern param"
  113. #t
  114. (begin
  115. (define-foreign special-value
  116. "host" "getSpecialValue"
  117. -> (ref extern))
  118. (define-foreign %special-value?
  119. "host" "isSpecialValue"
  120. (ref extern) -> i32)
  121. (define (special-value? x)
  122. (= (%special-value? x) 1))
  123. (special-value? (special-value)))
  124. (let ((special '(special value)))
  125. `(("host" . (("getSpecialValue" . ,(lambda () special))
  126. ("isSpecialValue" . ,(lambda (x) (eq? x special))))))))
  127. (test-ffi
  128. "external?"
  129. #t
  130. (let ()
  131. (define-foreign get-extern
  132. "host" "getExtern"
  133. -> (ref null extern))
  134. (external? (get-extern)))
  135. `(("host" . (("getExtern" . ,(lambda () '(external value)))))))
  136. (test-ffi
  137. "external-null?"
  138. #t
  139. (let ()
  140. (define-foreign get-null
  141. "host" "getNull"
  142. -> (ref null extern))
  143. (external-null? (get-null)))
  144. `(("host" . (("getNull" . ,(lambda () #f))))))
  145. (test-ffi
  146. "external-non-null?"
  147. #t
  148. (let ()
  149. (define-foreign get-non-null
  150. "host" "getNonNull"
  151. -> (ref extern))
  152. (external-non-null? (get-non-null)))
  153. `(("host" . (("getNonNull" . ,(lambda () #t))))))
  154. (test-ffi
  155. "procedure->extern"
  156. 1
  157. (let ((counter 0))
  158. (define-foreign callback
  159. "host" "callback"
  160. (ref null extern) -> none)
  161. (callback
  162. (procedure->external
  163. (lambda () (set! counter (+ counter 1)))))
  164. counter)
  165. `(("host" .
  166. (("callback" . ,(lambda (f) (f) *unspecified*))))))
  167. (test-ffi
  168. "define-external-type"
  169. #t
  170. (begin
  171. (define-foreign make-widget
  172. "host" "makeWidget"
  173. -> (ref extern))
  174. (define-external-type <widget>
  175. widget? wrap-widget unwrap-widget)
  176. (define w (wrap-widget (make-widget)))
  177. (and (widget? w)
  178. (external? (unwrap-widget w))))
  179. `(("host" .
  180. (("makeWidget" . ,(lambda () (list 'widget)))))))
  181. (test-end* "test-ffi")