wat.scm 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  1. ;;; WebAssembly text format parser and unparser
  2. ;;; Copyright (C) 2023 Igalia, S.L.
  3. ;;; Copyright (C) 2023 Robin Templeton <robin@spritely.institute>
  4. ;;; Copyright (C) 2023 David Thompson <dave@spritely.institute>
  5. ;;;
  6. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  7. ;;; you may not use this file except in compliance with the License.
  8. ;;; You may obtain a copy of the License at
  9. ;;;
  10. ;;; http://www.apache.org/licenses/LICENSE-2.0
  11. ;;;
  12. ;;; Unless required by applicable law or agreed to in writing, software
  13. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  14. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. ;;; See the License for the specific language governing permissions and
  16. ;;; limitations under the License.
  17. ;;; Commentary:
  18. ;;;
  19. ;;; Converts WAT to WASM and vice versa.
  20. ;;;
  21. ;;; Code:
  22. (define-module (wasm wat)
  23. #:use-module (ice-9 binary-ports)
  24. #:use-module (ice-9 match)
  25. #:use-module (rnrs bytevectors)
  26. #:use-module ((srfi srfi-1) #:select (append-map filter-map))
  27. #:use-module (srfi srfi-11)
  28. #:use-module (wasm types)
  29. #:export (wat->wasm wasm->wat))
  30. ;; to-do:
  31. ;; - support reftypes
  32. ;; - support bulk memory instructions
  33. ;; - tail calls
  34. ;; - stringref
  35. ;; differences from standard: scheme comments / no block comments.
  36. ;; strings have guile string syntax; bytevectors also for data. could
  37. ;; write standard-compliant parser instead (port from wassemble).
  38. (define (natural-alignment inst)
  39. (case inst
  40. ((i32.load8_s
  41. i32.load8_u
  42. i64.load8_s
  43. i64.load8_u
  44. i32.store8
  45. i64.store8)
  46. 0)
  47. ((i32.load16_s
  48. i32.load16_u
  49. i64.load16_s
  50. i64.load16_u
  51. i32.store16
  52. i64.store16)
  53. 1)
  54. ((i32.load
  55. f32.load
  56. i64.load32_s
  57. i64.load32_u
  58. i32.store
  59. f32.store
  60. i64.store32)
  61. 2)
  62. ((i64.load
  63. f64.load
  64. i64.store
  65. f64.store)
  66. 3)
  67. (else (error "unrecognized instruction" inst))))
  68. (define (wat->wasm expr)
  69. (define (id? x)
  70. (and (symbol? x) (eqv? (string-ref (symbol->string x) 0) #\$)))
  71. (define (kw? x)
  72. (and (symbol? x) (not (id? x))))
  73. (define (u32? x)
  74. (and (exact-integer? x) (<= 0 x (1- (ash 1 32)))))
  75. (define (s32? x)
  76. (and (exact-integer? x) (<= (ash -1 31) x (1- (ash 1 31)))))
  77. (define (u64? x)
  78. (and (exact-integer? x) (<= 0 x (1- (ash 1 64)))))
  79. (define (s64? x)
  80. (and (exact-integer? x) (<= (ash -1 63) x (1- (ash 1 63)))))
  81. (define (id-or-idx? x) (or (id? x) (u32? x)))
  82. (define (assert-true x msg)
  83. (or x (error msg)))
  84. ;; Identifiers with a space can't be in the source program.
  85. (define fresh-idx 0)
  86. (define (fresh-id!)
  87. (let ((id (string->symbol
  88. (string-append "$fresh " (number->string fresh-idx)))))
  89. (set! fresh-idx (1+ fresh-idx))
  90. id))
  91. (define (partition-clauses x)
  92. (define id #f)
  93. (define types '())
  94. (define imports '())
  95. (define funcs '())
  96. (define tables '())
  97. (define memories '())
  98. (define globals '())
  99. (define exports '())
  100. (define start #f)
  101. (define elems '())
  102. (define datas '())
  103. (define tags '())
  104. (define strings '())
  105. (define (collect-raw x)
  106. (match x
  107. (('type . x) (set! types (cons x types)))
  108. (('import . x) (set! imports (cons x imports)))
  109. (('func . x) (set! funcs (cons x funcs)))
  110. (('table . x) (set! tables (cons x tables)))
  111. (('memory . x) (set! memories (cons x memories)))
  112. (('global . x) (set! globals (cons x globals)))
  113. (('export . x) (set! exports (cons x exports)))
  114. (('start . x) (begin
  115. (when start (error "multiple start clauses"))
  116. (set! start x)))
  117. (('elem . x) (set! elems (cons x elems)))
  118. (('data . x) (set! datas (cons x datas)))
  119. (('tag . x) (set! tags (cons x tags)))
  120. (('strings . x) (set! strings (append strings x)))
  121. (('rec . _) (set! types (cons x types)))
  122. (_ (error "unexpected form in module" x))))
  123. (match x
  124. (('module (? id? mod-id) . clauses)
  125. (set! id mod-id)
  126. (for-each collect-raw clauses))
  127. (('module . clauses) (for-each collect-raw clauses))
  128. ((clauses ...) (for-each collect-raw clauses))
  129. (_ (error "unexpected module" x)))
  130. (make-wasm id (reverse types) (reverse imports) (reverse funcs)
  131. (reverse tables) (reverse memories) (reverse globals)
  132. (reverse exports) start (reverse elems)
  133. (reverse datas) (reverse tags) strings '()))
  134. (define (valid-heap-type? x)
  135. (match x
  136. ((or 'func 'extern 'any 'none 'noextern 'nofunc 'eq 'struct 'array 'i31
  137. 'string 'stringview_iter 'stringview_wtf8 'stringview_wtf16
  138. (? id-or-idx?))
  139. #t)
  140. (_ #f)))
  141. (define (parse-heap-type x)
  142. (if (valid-heap-type? x)
  143. x
  144. (error "bad heaptype" x)))
  145. (define* (parse-ref-type x #:key (error-message "bad reftype"))
  146. (match x
  147. (('ref 'null ht) (make-ref-type #t (parse-heap-type ht)))
  148. (('ref ht) (make-ref-type #f (parse-heap-type ht)))
  149. ('funcref (make-ref-type #t 'func))
  150. ('externref (make-ref-type #t 'extern))
  151. ('anyref (make-ref-type #t 'any))
  152. ('nullref (make-ref-type #t 'none))
  153. ('nullexternref (make-ref-type #t 'noextern))
  154. ('nullfuncref (make-ref-type #t 'nofunc))
  155. ('eqref (make-ref-type #t 'eq))
  156. ('structref (make-ref-type #t 'struct))
  157. ('arrayref (make-ref-type #t 'array))
  158. ('i31ref (make-ref-type #t 'i31))
  159. (_ (error error-message x))))
  160. (define (parse-val-type x)
  161. (match x
  162. ((or 'i32 'i64 'f32 'f64 'v128) x)
  163. (_ (parse-ref-type x #:error-message "bad valtype"))))
  164. (define (parse-storage-type x)
  165. (match x
  166. ((or 'i8 'i16) x)
  167. (_ (parse-val-type x))))
  168. (define (parse-params x)
  169. (match x
  170. (((? id? id) vt) (list (make-param id (parse-val-type vt))))
  171. ((vt ...) (map (lambda (vt) (make-param #f (parse-val-type vt))) vt))))
  172. (define (parse-results x)
  173. (match x
  174. ((vt ...) (map parse-val-type vt))))
  175. (define (parse-func-sig x)
  176. (let lp ((x x) (params '()))
  177. (match x
  178. ((('param . tail) . x)
  179. (lp x (append params (parse-params tail))))
  180. (_
  181. (let lp ((x x) (results '()))
  182. (match x
  183. ((('result . tail) . x)
  184. (lp x (append results (parse-results tail))))
  185. (_ (values (make-func-sig params results) x))))))))
  186. (define (parse-func-type x)
  187. (let-values (((sig tail) (parse-func-sig x)))
  188. (unless (null? tail) "unexpected tail on func type" tail)
  189. sig))
  190. (define (parse-type-use x)
  191. (define (parse-sig idx x)
  192. (let-values (((sig x) (parse-func-sig x)))
  193. (values (make-type-use idx sig) x)))
  194. (match x
  195. ((('type idx) . sig)
  196. (parse-sig idx sig))
  197. (sig (parse-sig #f sig))))
  198. (define (parse-block-type x)
  199. (match x
  200. ;; cf. emit-block-type in (@ (wasm assemble) assemble-wasm)
  201. (((and t (or (? symbol?) ('ref . _))) . tail)
  202. (values
  203. (make-type-use #f (make-func-sig '() (list (parse-val-type t))))
  204. tail))
  205. (_ (parse-type-use x))))
  206. (define (parse-limits x)
  207. (match x
  208. (((? u32? min) (? u32? max) . tail)
  209. (values (make-limits min max) tail))
  210. (((? u32? min) . tail)
  211. (values (make-limits min #f) tail))))
  212. (define (parse-elem-type x)
  213. (match x
  214. (('funcref) 'funcref)
  215. ((x) (parse-ref-type x #:error-message "bad elem type"))
  216. (_ (error "bad elem type"))))
  217. (define (parse-table-type x)
  218. (let-values (((limits x) (parse-limits x)))
  219. (make-table-type limits (parse-elem-type x))))
  220. (define (parse-mem-type x)
  221. (let-values (((limits x) (parse-limits x)))
  222. (match x
  223. (() (make-mem-type limits)))))
  224. (define (parse-global-type x)
  225. (match x
  226. (('mut vt) (make-global-type #t (parse-val-type vt)))
  227. (vt (make-global-type #f (parse-val-type vt)))))
  228. (define (parse-id-or-idx x)
  229. (match x
  230. (((? id-or-idx? id) . x) (values id x))
  231. (_ (values #f x))))
  232. (define (parse-id x)
  233. (match x
  234. (((? id? id) . x) (values id x))
  235. (_ (values #f x))))
  236. (define (parse-array-type x)
  237. (match x
  238. (('mut t) (make-array-type #t (parse-storage-type t)))
  239. (t (make-array-type #f (parse-storage-type t)))))
  240. (define (parse-field x)
  241. (match x
  242. (('field (? id? id) ('mut t))
  243. (make-field id #t (parse-storage-type t)))
  244. (('field (? id? id) t)
  245. (make-field id #f (parse-storage-type t)))
  246. (('mut t)
  247. (make-field #f #t (parse-storage-type t)))
  248. (t
  249. (make-field #f #f (parse-storage-type t)))))
  250. (define (parse-struct-type x)
  251. (make-struct-type (map parse-field x)))
  252. (define (parse-sub-type type)
  253. (match type
  254. (('sub 'final (? id-or-idx? super) ... type)
  255. (make-sub-type #t super (parse-prim-type type)))
  256. (('sub (? id-or-idx? super) ... type)
  257. (make-sub-type #f super (parse-prim-type type)))
  258. (type
  259. (parse-prim-type type))))
  260. (define (parse-prim-type x)
  261. (match x
  262. (('func . sig) (parse-func-sig sig))
  263. (('array sig) (parse-array-type sig))
  264. (('struct . sig) (parse-struct-type sig))))
  265. (define (parse-type x)
  266. (match x
  267. (('sub id sub)
  268. (make-sub-type #f (list id) (parse-prim-type sub)))
  269. (_ (parse-prim-type x))))
  270. (define (parse-type-def def)
  271. (define (parse-def def)
  272. (match def
  273. (((? id-or-idx? id) type) (make-type id (parse-sub-type type)))
  274. ((type) (make-type #f (parse-sub-type type)))))
  275. (match def
  276. (('rec ('type . def) ...) (make-rec-group (map parse-def def)))
  277. (def (parse-def def))))
  278. (define (parse-import x)
  279. (define (parse-inner mod name kind id tail)
  280. (match kind
  281. ('func (make-import mod name 'func id (parse-type-use tail)))
  282. ('table (make-import mod name 'table id (parse-table-type tail)))
  283. ('memory (make-import mod name 'memory id (parse-mem-type tail)))
  284. ('global (make-import mod name 'global id
  285. (match tail
  286. ((type) (parse-global-type type)))))))
  287. (match x
  288. (((? string? mod) (? string? name) desc)
  289. (match desc
  290. ((kind (? id? id) . tail)
  291. (parse-inner mod name kind id tail))
  292. ((kind . tail)
  293. (parse-inner mod name kind #f tail))))))
  294. (define (parse-export x)
  295. (match x
  296. (((? string? name) ((and kind (or 'func 'table 'memory 'global)) idx))
  297. (make-export name kind idx))))
  298. (define (parse-mem-arg x inst)
  299. (define (symbol-with-prefix prefix)
  300. (lambda (x)
  301. (and (symbol? x)
  302. (string-prefix? prefix (symbol->string x)))))
  303. (define (symbol-suffix x prefix)
  304. (substring (symbol->string x) (string-length prefix)))
  305. (define (parse-arg prefix x)
  306. (match x
  307. (((? (symbol-with-prefix prefix) arg) . x)
  308. (values
  309. (or (string->number (symbol-suffix arg prefix))
  310. (error "bad mem arg" arg))
  311. x))
  312. (_ (values #f x))))
  313. (let*-values (((idx x) (parse-id-or-idx x))
  314. ((offset x) (parse-arg "offset=" x))
  315. ((align x) (parse-arg "align=" x)))
  316. (values (make-mem-arg (or idx 0)
  317. (or offset 0)
  318. (or align (natural-alignment inst)))
  319. x)))
  320. (define (unfold-instruction inst)
  321. (define (unparse-val-type type)
  322. (match type
  323. ((? symbol?) type)
  324. (($ <ref-type> #f ht) `(ref ,ht))
  325. (($ <ref-type> #t ht) `(ref null ,ht))))
  326. (define (unfold-func-sig sig)
  327. (match sig
  328. (($ <func-sig> params results)
  329. `(,@(map (match-lambda
  330. ((#f . vt) `(param ,(unparse-val-type vt)))
  331. ((id . vt) `(param ,id ,(unparse-val-type vt))))
  332. params)
  333. (result ,@(map unparse-val-type results))))))
  334. (define (unfold-type-use type)
  335. (match type
  336. (($ <type-use> #f sig)
  337. (unfold-func-sig sig))
  338. (($ <type-use> idx sig)
  339. `((type ,idx) ,@(unfold-func-sig sig)))))
  340. (define (unfold-mem-arg arg)
  341. (match arg
  342. (($ <mem-arg> id offset align)
  343. `(,@(if (eqv? id 0)
  344. '()
  345. (list id))
  346. ,@(if offset
  347. (list (string->symbol (format #f "offset=~a" offset)))
  348. '())
  349. ,@(if align
  350. (list (string->symbol (format #f "align=~a" align)))
  351. '())))))
  352. (match inst
  353. (((and tag (or 'loop 'block)) body ...)
  354. (cons tag (append body (list 'end))))
  355. (('if . body)
  356. (let*-values (((label body) (parse-id body))
  357. ((type body) (parse-block-type body)))
  358. (define (finish test consequent alternate)
  359. `(,@test
  360. if ,@(if label `(,label) '()) ,@(unfold-type-use type)
  361. ,@consequent
  362. else ,@alternate
  363. end))
  364. (match body
  365. ((test ... ('then consequent ...))
  366. (finish test consequent '()))
  367. ((test ... ('then consequent ...) ('else alternate ...))
  368. (finish test consequent alternate)))))
  369. (((and tag (or 'br 'br_if 'call 'local.get 'local.set 'local.tee
  370. 'global.get 'global.set))
  371. idx
  372. . args)
  373. `(,@args ,tag ,idx))
  374. (((and tag (or 'br_on_cast 'br_on_cast_fail)) target rt1 rt2
  375. . args)
  376. `(,@args ,tag ,target ,rt1 ,rt2))
  377. (('br_table . args)
  378. (let lp ((args args) (targets '()))
  379. (match args
  380. (((? id-or-idx? target) . args)
  381. (lp args (cons target targets)))
  382. (_ `(,@args br_table ,@(reverse targets))))))
  383. (('call_indirect . args)
  384. (let*-values (((table args) (parse-id-or-idx args))
  385. ((type args) (parse-type-use args)))
  386. `(,@args call_indirect ,table ,@(unfold-type-use type))))
  387. (((and tag (or 'i32.load
  388. 'i64.load
  389. 'f32.load
  390. 'f64.load
  391. 'i32.load8_s
  392. 'i32.load8_u
  393. 'i32.load16_s
  394. 'i32.load16_u
  395. 'i64.load8_s
  396. 'i64.load8_u
  397. 'i64.load16_s
  398. 'i64.load16_u
  399. 'i64.load32_s
  400. 'i64.load32_u
  401. 'i32.store
  402. 'i64.store
  403. 'f32.store
  404. 'f64.store
  405. 'i32.store8
  406. 'i32.store16
  407. 'i64.store8
  408. 'i64.store16
  409. 'i64.store32))
  410. . args)
  411. (let-values (((mem-arg args) (parse-mem-arg args tag)))
  412. `(,@args ,tag ,@(unfold-mem-arg mem-arg))))
  413. (((and tag (or 'i32.const 'i64.const 'f32.const 'f64.const)) val . insts)
  414. `(,@insts ,tag ,val))
  415. (('ref.func (? id-or-idx? id) . args)
  416. `(,@args ref.func ,id))
  417. (((and tag (or 'call_ref 'return_call_ref)) (? id-or-idx? id) . args)
  418. `(,@args ,tag ,id))
  419. (((and tag 'ref.null) (? valid-heap-type? id) . args)
  420. `(,@args ,tag ,id))
  421. (((and tag (or 'table.set 'table.get 'table.size 'table.grow
  422. 'table.fill 'elem.drop
  423. 'memory.size 'memory.grow 'memory.fill))
  424. (? id-or-idx? id) . args)
  425. `(,@args ,tag ,id))
  426. (((and tag (or 'memory.init 'table.init))
  427. (? id-or-idx? id) (? id-or-idx? eid) . args)
  428. `(,@args ,tag ,id ,eid))
  429. (((and tag (or 'memory.init 'table.init)) (? id-or-idx? eid) . args)
  430. `(,@args ,tag 0 ,eid))
  431. (((and tag (or 'memory.copy 'table.copy))
  432. (? id-or-idx? a) (? id-or-idx? b) . args)
  433. `(,@args ,tag ,a ,b))
  434. (((and tag (or 'memory.copy 'table.copy)) . args)
  435. `(,@args ,tag 0 0))
  436. (((and tag (or 'struct.new 'struct.new_default)) (? id-or-idx? id) . args)
  437. `(,@args ,tag ,id))
  438. (((and tag (or 'struct.set 'struct.get 'struct.get_s 'struct.get_u))
  439. (? id-or-idx? ti)
  440. (? id-or-idx? fi) . args)
  441. `(,@args ,tag ,ti ,fi))
  442. (((and tag (or 'ref.test 'ref.cast)) 'null (? valid-heap-type? id) . args)
  443. `(,@args ,tag null ,id))
  444. (((and tag (or 'ref.test 'ref.cast)) (? valid-heap-type? id) . args)
  445. `(,@args ,tag ,id))
  446. (((and tag 'string.const) (? string? str) . args)
  447. `(,@args ,tag ,str))
  448. (((and tag (or 'array.new 'array.new_default 'array.fill
  449. 'array.get 'array.set 'array.get_u 'array.get_s))
  450. (? id-or-idx? ti) . args)
  451. `(,@args ,tag ,ti))
  452. (((and tag 'array.new_fixed) (? id-or-idx? ti) (? s32? k) . args)
  453. `(,@args ,tag ,ti ,k))
  454. (((and tag (or 'array.copy
  455. 'array.new_data 'array.new_elem
  456. 'array.init_data 'array.init_elem))
  457. (? id-or-idx? ti1) (? id-or-idx? ti2) . args)
  458. `(,@args ,tag ,ti1 ,ti2))
  459. (((and tag 'return_call) (? id-or-idx? id) . args)
  460. `(,@args ,tag ,id))
  461. ((tag . args)
  462. `(,@args ,tag))))
  463. (define (parse-block x block-kind)
  464. (let lp ((in x) (out '()))
  465. (define (lp/inst in parsed)
  466. (lp in (cons parsed out)))
  467. (define (lp/block block-label in parsed)
  468. ;; Skip end label.
  469. (let-values (((label in) (parse-id in)))
  470. (when label
  471. (unless (eq? label block-label) (error "bad end label" label)))
  472. (lp/inst in parsed)))
  473. (match in
  474. (()
  475. (unless (eq? block-kind 'body)
  476. (error "unexpected end of instruction sequence"))
  477. (values (reverse out) '()))
  478. (((folded ...) . in)
  479. (lp (append (unfold-instruction folded) in) out))
  480. (((? kw? inst) . in)
  481. (match inst
  482. ((or 'block 'loop)
  483. (let*-values (((label in) (parse-id in))
  484. ((type in) (parse-block-type in))
  485. ((insts in) (parse-block in inst)))
  486. (lp/block label in `(,inst ,label ,type ,insts))))
  487. ('if
  488. (let*-values (((label in) (parse-id in))
  489. ((type in) (parse-block-type in))
  490. ((consequent in) (parse-block in 'then)))
  491. (match in
  492. (('else . in)
  493. (let-values (((alternate in) (parse-block in 'else)))
  494. (lp/block label in
  495. `(,inst ,label ,type ,consequent ,alternate))))
  496. (_
  497. (lp/block label in `(,inst ,label ,type ,consequent ()))))))
  498. ('else
  499. (unless (eq? block-kind 'then)
  500. (error "unexpected 'else'"))
  501. (values (reverse out) (cons 'else in)))
  502. ('end
  503. (when (eq? block-kind 'body)
  504. (error "unexpected 'end'"))
  505. (values (reverse out) in))
  506. ('ref.func
  507. (match in
  508. (((? id-or-idx? id) . in)
  509. (lp/inst in `(,inst ,id)))))
  510. ((or 'br 'br_if
  511. 'call 'local.get 'local.set 'local.tee 'global.get
  512. 'global.set)
  513. (let-values (((idx in) (parse-id-or-idx in)))
  514. (unless idx (error "missing idx" inst in))
  515. (lp/inst in `(,inst ,idx))))
  516. ((or 'br_on_cast 'br_on_cast_fail)
  517. (match in
  518. (((? id-or-idx? target) rt1 rt2 . in)
  519. (lp/inst
  520. in
  521. `(,inst ,target ,(parse-ref-type rt1) ,(parse-ref-type rt2))))))
  522. ('br_table
  523. (let lp ((in in) (targets '()))
  524. (match in
  525. (((? id-or-idx? target) . in)
  526. (lp in (cons target targets)))
  527. (_
  528. (match (reverse targets)
  529. ((target ... default)
  530. (lp/inst in `(,inst ,target ,default)))
  531. (_ (error "no targets for br_table")))))))
  532. ('call_indirect
  533. (let*-values (((table in) (parse-id-or-idx in))
  534. ((type in) (parse-type-use in)))
  535. (lp/inst in `(,inst ,(or table 0) ,type))))
  536. ((or 'i32.load 'i64.load
  537. 'f32.load 'f64.load
  538. 'i32.load8_s 'i32.load8_u 'i32.load16_s 'i32.load16_u
  539. 'i64.load8_s 'i64.load8_u 'i64.load16_s 'i64.load16_u
  540. 'i64.load32_s 'i64.load32_u
  541. 'i32.store 'i64.store
  542. 'f32.store 'f64.store
  543. 'i32.store8 'i32.store16
  544. 'i64.store8 'i64.store16 'i64.store32)
  545. (let-values (((mem-arg in) (parse-mem-arg in inst)))
  546. (lp/inst in `(,inst ,mem-arg))))
  547. ('i32.const
  548. (match in
  549. (((? s32? const) . in)
  550. (lp/inst in `(,inst ,const)))))
  551. ('i64.const
  552. (match in
  553. (((? s64? const) . in)
  554. (lp/inst in `(,inst ,const)))))
  555. ((or 'f32.const 'f64.const)
  556. (match in
  557. (((? real? const) . in)
  558. (lp/inst in `(,inst ,(exact->inexact const))))))
  559. ((or 'call_ref 'return_call_ref)
  560. (match in
  561. (((? id-or-idx? id) . in)
  562. (lp/inst in `(,inst ,id)))))
  563. ('ref.null
  564. (match in
  565. ((id . in)
  566. (lp/inst in `(,inst ,(parse-heap-type id))))))
  567. ((or 'table.set 'table.get 'table.size 'table.grow
  568. 'table.fill 'elem.drop
  569. 'memory.size 'memory.grow 'memory.fill)
  570. (match in
  571. (((? id-or-idx? id) . in)
  572. (lp/inst in `(,inst ,id)))
  573. (_
  574. (lp/inst in `(,inst 0)))))
  575. ((or 'table.copy 'memory.copy)
  576. (match in
  577. (((? id-or-idx? a) (? id-or-idx? b) . in)
  578. (lp/inst in `(,inst ,a ,b)))
  579. (_
  580. (lp/inst in `(,inst 0 0)))))
  581. ((or 'table.init 'memory.init)
  582. (match in
  583. (((? id-or-idx? tid) (? id-or-idx? eid) . in)
  584. (lp/inst in `(,inst ,tid ,eid)))
  585. (((? id-or-idx? eid) . in)
  586. (lp/inst in `(,inst 0 ,eid)))))
  587. ((or 'struct.new 'struct.new_default)
  588. (match in
  589. (((? id-or-idx? id) . in)
  590. (lp/inst in `(,inst ,id)))))
  591. ((or 'struct.set 'struct.get 'struct.get_s 'struct.get_u)
  592. (match in
  593. (((? id-or-idx? ti) (? id-or-idx? fi) . in)
  594. (lp/inst in `(,inst ,ti ,fi)))))
  595. ((or 'ref.test 'ref.cast)
  596. (match in
  597. (('null ht . in)
  598. (lp/inst in `(,inst ,(make-ref-type #t (parse-heap-type ht)))))
  599. ((ht . in)
  600. (lp/inst in `(,inst ,(make-ref-type #f (parse-heap-type ht)))))))
  601. ('string.const
  602. (match in
  603. (((? string? str) . in)
  604. (lp/inst in `(,inst ,str)))))
  605. ((or 'array.new 'array.new_default 'array.fill
  606. 'array.get 'array.set 'array.get_u 'array.get_s)
  607. (match in
  608. (((? id-or-idx? ti) . in)
  609. (lp/inst in `(,inst ,ti)))))
  610. ('array.new_fixed
  611. (match in
  612. (((? id-or-idx? ti) (? s32? k) . in)
  613. (lp/inst in `(,inst ,ti ,k)))))
  614. ((or 'array.copy
  615. 'array.new_data 'array.new_elem
  616. 'array.init_data 'array.init_elem)
  617. (match in
  618. (((? id-or-idx? idx1) (? id-or-idx? idx2) . in)
  619. (lp/inst in `(,inst ,idx1 ,idx2)))))
  620. ('return_call
  621. (match in
  622. (((? id-or-idx? id) . in)
  623. (lp/inst in `(,inst ,id)))))
  624. (_
  625. (lp/inst in (list inst))))))))
  626. (define (parse-offset x)
  627. (parse-block (match x
  628. (('offset . offset) offset)
  629. (offset (list offset)))
  630. 'body))
  631. (define (parse-init init)
  632. (parse-block (match init
  633. (('item . init) init)
  634. (init (list init)))
  635. 'body))
  636. (define (parse-elem x)
  637. (define (parse-table-use x)
  638. (match x
  639. ((('table (? id-or-idx? table)) . x) (values table x))
  640. (_ (values #f x))))
  641. (define (parse-elemlist elemlist)
  642. (match elemlist
  643. (('func (? id-or-idx? id) ...)
  644. (values 'funcref (map (lambda (id) `((ref.func ,id))) id)))
  645. (((? id-or-idx? id) ...)
  646. (values 'funcref (map (lambda (id) `((ref.func ,id))) id)))
  647. ((type init ...)
  648. (values (parse-ref-type type) (map parse-init init)))))
  649. (let-values (((id x) (parse-id x)))
  650. (match x
  651. (('declare . elemlist)
  652. ;; Declarative element segment.
  653. (let-values (((type inits) (parse-elemlist elemlist)))
  654. (make-elem id 'declarative #f type #f inits)))
  655. ((('table table) offset . elemlist)
  656. ;; Active element segment with explicit table.
  657. (let-values (((type inits) (parse-elemlist elemlist)))
  658. (make-elem id 'active table type (parse-offset offset) inits)))
  659. (((and offset (or ('offset . _) ('i32.const _))) . elemlist)
  660. ;; Active element segment for table 0.
  661. (let-values (((type inits) (parse-elemlist elemlist)))
  662. (make-elem id 'active 0 type (parse-offset offset) inits)))
  663. (elemlist
  664. (let-values (((type inits) (parse-elemlist elemlist)))
  665. (make-elem id 'passive #f type #f inits))))))
  666. (define (bytevector-concatenate bvs)
  667. (call-with-output-bytevector
  668. (lambda (p)
  669. (for-each (lambda (bv) (put-bytevector p bv)) bvs))))
  670. (define (parse-data x)
  671. (let-values (((id x) (parse-id x)))
  672. (match x
  673. ((('memory (? id-or-idx? mem)) offset . init)
  674. ;; Active data segment with explicit memory.
  675. (make-data id 'active mem (parse-offset offset)
  676. (bytevector-concatenate init)))
  677. (((and offset (or ('offset . _) ('i32.const _))) . init)
  678. ;; Active data segment for memory 0.
  679. (make-data id 'active 0 (parse-offset offset)
  680. (bytevector-concatenate init)))
  681. (init
  682. ;; Passive data segment.
  683. (make-data id 'passive #f #f (bytevector-concatenate init))))))
  684. (define (parse-tag tag)
  685. (let*-values (((id tag) (parse-id tag))
  686. ((type tag) (parse-type-use tag)))
  687. (match tag
  688. (() (make-tag id type))
  689. (_ (error "bad tag" tag)))))
  690. (define (parse-start start)
  691. (let-values (((idx x) (parse-id-or-idx start)))
  692. (match x
  693. (() (or idx 0))
  694. (_ (error "bad start" x)))))
  695. (match (partition-clauses expr)
  696. (($ <wasm> id types imports funcs tables memories globals exports start
  697. elems datas tags strings custom)
  698. (let ((types (map parse-type-def types))
  699. (imports (map parse-import imports))
  700. (exports (map parse-export exports))
  701. (elems (map parse-elem elems))
  702. (datas (map parse-data datas))
  703. (tags (map parse-tag tags))
  704. (start (and start (parse-start start))))
  705. (define-syntax-rule (push! id val)
  706. (set! id (append! id (list val))))
  707. (define (visit-func x)
  708. (let*-values (((id x) (parse-id x))
  709. ((id) (or id (fresh-id!))))
  710. (let lp ((x x))
  711. (match x
  712. ((('export name) . x)
  713. (push! exports (make-export name 'func id))
  714. (lp x))
  715. ((('import mod name) . x)
  716. (let-values (((type x) (parse-type-use x)))
  717. (match x
  718. (()
  719. (push! imports (make-import mod name 'func id type))
  720. #f)
  721. (_
  722. (error "bad import" x)))))
  723. (_
  724. (let-values (((type x) (parse-type-use x)))
  725. (let lp ((x x) (locals '()))
  726. (match x
  727. ((('local (? id? id) vt) . x)
  728. (lp x (cons (make-local id (parse-val-type vt)) locals)))
  729. (_
  730. (make-func id type (reverse locals)
  731. (parse-block x 'body)))))))))))
  732. (define (visit-table x)
  733. (let*-values (((id x) (parse-id x))
  734. ((id) (or id (fresh-id!))))
  735. (let lp ((x x))
  736. (match x
  737. ((('export name) . x)
  738. (push! exports (make-export name 'table id))
  739. (lp x))
  740. ((('import mod name) . x)
  741. (let ((type (parse-table-type x)))
  742. (push! imports (make-import mod name 'table id type))
  743. #f))
  744. ((elemtype ... ('elem . segment))
  745. (let ((elemtype (parse-elem-type elemtype))
  746. (len (length segment))
  747. (offset '((i32.const 0))))
  748. (push!
  749. elems
  750. (match segment
  751. (((? id-or-idx? id) ...)
  752. (make-elem #f 'active id 'funcref offset
  753. (map (lambda (id) `((ref.func ,id))) id)))
  754. (((_ ...) ...)
  755. (make-elem #f 'active id 'funcref offset
  756. (map (lambda (init)
  757. (parse-block init 'body))
  758. segment)))))
  759. (make-table id
  760. (make-table-type (make-limits len len)
  761. elemtype)
  762. #f)))
  763. (_
  764. (make-table id (parse-table-type x) #f))))))
  765. (define (visit-memory x)
  766. (let*-values (((id x) (parse-id x))
  767. ((id) (or id (fresh-id!))))
  768. (let lp ((x x))
  769. (match x
  770. ((('export name) . x)
  771. (push! exports (make-export name 'memory id))
  772. (lp x))
  773. ((('import mod name) . x)
  774. (let ((type (parse-mem-type x)))
  775. (push! imports (make-import mod name 'memory id type))
  776. #f))
  777. ((('data . data))
  778. (let* ((init (bytevector-concatenate data))
  779. (len (bytevector-length init)))
  780. (push! data (make-data id 'active 0 '((i32.const 0)) init))
  781. (make-memory id (make-mem-type (make-limits len len)))))
  782. (_
  783. (make-memory id (parse-mem-type x)))))))
  784. (define (visit-global x)
  785. (let*-values (((id x) (parse-id x))
  786. ((id) (or id (fresh-id!))))
  787. (let lp ((x x))
  788. (match x
  789. ((('export name) . x)
  790. (push! exports (make-export name 'global id))
  791. (lp x))
  792. ((('import mod name) type)
  793. (let ((type (parse-global-type type)))
  794. (push! imports (make-import mod name 'global id type))
  795. #f))
  796. ((type . init)
  797. (make-global id
  798. (parse-global-type type)
  799. (parse-block init 'body)))))))
  800. (let ((funcs (filter-map visit-func funcs))
  801. (tables (filter-map visit-table tables))
  802. (memories (filter-map visit-memory memories))
  803. (globals (filter-map visit-global globals)))
  804. (make-wasm id types imports funcs tables memories globals exports
  805. start elems datas tags strings custom))))))
  806. (define (wasm->wat mod)
  807. (match mod
  808. (($ <wasm> id types imports funcs tables memories globals exports start
  809. elems datas tags strings custom)
  810. ;; TODO: Factorize type-repr code that is duplicated between here
  811. ;; and (wasm dump).
  812. (define (val-type-repr vt)
  813. (match vt
  814. (($ <ref-type> #t ht)
  815. `(ref null ,ht))
  816. (($ <ref-type> #f ht)
  817. `(ref ,ht))
  818. (_ vt)))
  819. (define (params-repr params)
  820. (match params
  821. (() '())
  822. ((($ <param> #f type) ...)
  823. `((param ,@(map val-type-repr type))))
  824. ((($ <param> id type) . params)
  825. (cons `(param ,id ,(val-type-repr type))
  826. (params-repr params)))))
  827. (define (results-repr results)
  828. (map (lambda (type) `(result ,(val-type-repr type))) results))
  829. (define (field-repr field)
  830. (define (wrap mutable? repr)
  831. (if mutable? `(mut ,repr) repr))
  832. (match field
  833. (($ <field> id mutable? type)
  834. (let ((repr (wrap mutable? (val-type-repr type))))
  835. (if id
  836. `(field ,id ,repr)
  837. repr)))))
  838. (define (type-repr type)
  839. (match type
  840. (($ <func-sig> params results)
  841. `(func ,@(params-repr params) ,@(results-repr results)))
  842. (($ <sub-type> final? supers type)
  843. `(sub ,@(if final? '(final) '()) ,@supers ,(type-repr type)))
  844. (($ <struct-type> fields)
  845. `(struct ,@(map field-repr fields)))
  846. (($ <array-type> mutable? type)
  847. `(array ,(field-repr (make-field #f mutable? type))))))
  848. (define (type-use-repr type-use)
  849. (match type-use
  850. (($ <type-use> _ ($ <func-sig> params results))
  851. (append (params-repr params) (results-repr results)))))
  852. (define (block-type-repr bt)
  853. (match bt
  854. (#f '())
  855. ((? type-use? use)
  856. (type-use-repr use))
  857. ((? ref-type? rt)
  858. `((param ,(val-type-repr rt))))))
  859. (define (instr-repr instr)
  860. (define (make-prefix-arg prefix x)
  861. (if (zero? x)
  862. '()
  863. (list (string->symbol (string-append prefix (number->string x))))))
  864. (match instr
  865. (($ <mem-arg> id offset align)
  866. `(,id
  867. ,@(make-prefix-arg "offset=" offset)
  868. ,@(make-prefix-arg "align=" align)))
  869. (($ <ref-type> _ (? symbol? ht))
  870. `(,ht))
  871. (($ <type-use> idx)
  872. `((type ,idx)))
  873. ;; Instructions that need special handling:
  874. (('ref.cast ($ <ref-type> null? ht))
  875. `(ref.cast ,@(if null? '(null) '()) ,ht))
  876. (('string.const (? number? idx))
  877. `(string.const ,(list-ref strings idx)))
  878. (('if label bt consequent alternate)
  879. `(if ,@(block-type-repr bt)
  880. ,@(if label `(,label) '())
  881. (then ,@(instrs-repr consequent))
  882. (else ,@(instrs-repr alternate))))
  883. (((and op (or 'block 'loop)) label bt body)
  884. `(,op ,@(if label `(,label) '())
  885. ,@(block-type-repr bt)
  886. ,@(instrs-repr body)))
  887. ((_ ...)
  888. (append-map instr-repr instr))
  889. (_ `(,instr))))
  890. (define (instrs-repr instrs)
  891. (map instr-repr instrs))
  892. (define (limits-repr limits)
  893. (match limits
  894. (($ <limits> min max)
  895. (if max (list min max) (list min)))))
  896. (define (elem-item-repr init)
  897. `(item ,@(instrs-repr init)))
  898. `(module
  899. ,@(if id `(,id) '())
  900. ;; Types
  901. ,@(map (match-lambda
  902. (($ <type> id val)
  903. `(type ,id ,(type-repr val)))
  904. (($ <rec-group> types)
  905. `(rec ,@(map (match-lambda
  906. (($ <type> id val)
  907. `(type ,id ,(type-repr val))))
  908. types))))
  909. types)
  910. ;; Imports
  911. ,@(map (match-lambda
  912. (($ <import> mod name 'func id type)
  913. `(import ,mod ,name (func ,id ,@(type-use-repr type))))
  914. (($ <import> mod name 'global id ($ <global-type> mutable? type))
  915. `(import ,mod ,name
  916. (global ,id ,(if mutable?
  917. `(mut ,(val-type-repr type))
  918. (val-type-repr type)))))
  919. (($ <import> mod name 'memory id ($ <mem-type> limits))
  920. `(import ,mod ,name (memory ,id ,@(limits-repr limits))))
  921. (($ <import> mod name 'table id ($ <table-type> limits elem-type))
  922. `(import ,mod ,name
  923. (table ,id ,@(limits-repr limits)
  924. ,(val-type-repr elem-type)))))
  925. imports)
  926. ;; Exports
  927. ,@(map (match-lambda
  928. (($ <export> name kind idx)
  929. `(export ,name (,kind ,idx))))
  930. exports)
  931. ;; Globals
  932. ,@(map (match-lambda
  933. (($ <global> id ($ <global-type> mutable? type) init)
  934. `(global ,id
  935. ,(if mutable?
  936. `(mut ,(val-type-repr type))
  937. (val-type-repr type))
  938. ,@(instrs-repr init))))
  939. globals)
  940. ;; Tables
  941. ,@(map (match-lambda
  942. (($ <table> id ($ <table-type> limits elem-type))
  943. `(table ,id ,@(limits-repr limits)
  944. ,(val-type-repr elem-type))))
  945. tables)
  946. ;; Memories
  947. ,@(map (match-lambda
  948. (($ <memory> id ($ <mem-type> limits))
  949. `(memory ,id ,@(limits-repr limits))))
  950. memories)
  951. ;; Element segments
  952. ,@(map (match-lambda
  953. (($ <elem> id mode table type offset items)
  954. (match mode
  955. ('passive
  956. `(elem ,id ,(val-type-repr type)
  957. ,@(map elem-item-repr items)))
  958. ('active
  959. `(elem ,id (table ,table)
  960. (offset ,@(instrs-repr offset))
  961. ,(val-type-repr type)
  962. ,@(map elem-item-repr items)))
  963. ('declarative
  964. `(elem ,id declare ,@(map elem-item-repr items))))))
  965. elems)
  966. ;; Data segments
  967. ,@(map (match-lambda
  968. (($ <data> id mode mem offset init)
  969. (case mode
  970. ((active)
  971. `(data ,id ,mem ,@(instrs-repr offset) ,init))
  972. ((passive)
  973. `(data ,id ,init)))))
  974. datas)
  975. ;; Functions
  976. ,@(map (match-lambda
  977. (($ <func> id type locals body)
  978. (match type
  979. (($ <type-use> idx sig)
  980. `(func ,(or id idx)
  981. ,@(match (type-repr sig)
  982. (('func . params+results)
  983. params+results))
  984. ,@(map (match-lambda
  985. (($ <local> id type)
  986. `(local ,id ,(val-type-repr type))))
  987. locals)
  988. ,@(instrs-repr body))))))
  989. funcs)
  990. ;; Start function
  991. ,@(if start `((start ,start)) '())))))