wat.scm 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  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-tag-type x)
  229. (let-values (((type x) (parse-type-use x)))
  230. (match x
  231. (() (make-tag-type 'exception type)))))
  232. (define (parse-id-or-idx x)
  233. (match x
  234. (((? id-or-idx? id) . x) (values id x))
  235. (_ (values #f x))))
  236. (define (parse-id x)
  237. (match x
  238. (((? id? id) . x) (values id x))
  239. (_ (values #f x))))
  240. (define (parse-array-type x)
  241. (match x
  242. (('mut t) (make-array-type #t (parse-storage-type t)))
  243. (t (make-array-type #f (parse-storage-type t)))))
  244. (define (parse-field x)
  245. (match x
  246. (('field (? id? id) ('mut t))
  247. (make-field id #t (parse-storage-type t)))
  248. (('field (? id? id) t)
  249. (make-field id #f (parse-storage-type t)))
  250. (('mut t)
  251. (make-field #f #t (parse-storage-type t)))
  252. (t
  253. (make-field #f #f (parse-storage-type t)))))
  254. (define (parse-struct-type x)
  255. (make-struct-type (map parse-field x)))
  256. (define (parse-sub-type type)
  257. (match type
  258. (('sub 'final (? id-or-idx? super) ... type)
  259. (make-sub-type #t super (parse-prim-type type)))
  260. (('sub (? id-or-idx? super) ... type)
  261. (make-sub-type #f super (parse-prim-type type)))
  262. (type
  263. (parse-prim-type type))))
  264. (define (parse-prim-type x)
  265. (match x
  266. (('func . sig) (parse-func-sig sig))
  267. (('array sig) (parse-array-type sig))
  268. (('struct . sig) (parse-struct-type sig))))
  269. (define (parse-type x)
  270. (match x
  271. (('sub id sub)
  272. (make-sub-type #f (list id) (parse-prim-type sub)))
  273. (_ (parse-prim-type x))))
  274. (define (parse-type-def def)
  275. (define (parse-def def)
  276. (match def
  277. (((? id-or-idx? id) type) (make-type id (parse-sub-type type)))
  278. ((type) (make-type #f (parse-sub-type type)))))
  279. (match def
  280. (('rec ('type . def) ...) (make-rec-group (map parse-def def)))
  281. (def (parse-def def))))
  282. (define (parse-import x)
  283. (define (parse-inner mod name kind id tail)
  284. (match kind
  285. ('func (make-import mod name 'func id (parse-type-use tail)))
  286. ('table (make-import mod name 'table id (parse-table-type tail)))
  287. ('memory (make-import mod name 'memory id (parse-mem-type tail)))
  288. ('global (make-import mod name 'global id
  289. (match tail
  290. ((type) (parse-global-type type)))))))
  291. (match x
  292. (((? string? mod) (? string? name) desc)
  293. (match desc
  294. ((kind (? id? id) . tail)
  295. (parse-inner mod name kind id tail))
  296. ((kind . tail)
  297. (parse-inner mod name kind #f tail))))))
  298. (define (parse-export x)
  299. (match x
  300. (((? string? name) ((and kind (or 'func 'table 'memory 'global)) idx))
  301. (make-export name kind idx))))
  302. (define (parse-mem-arg x inst)
  303. (define (symbol-with-prefix prefix)
  304. (lambda (x)
  305. (and (symbol? x)
  306. (string-prefix? prefix (symbol->string x)))))
  307. (define (symbol-suffix x prefix)
  308. (substring (symbol->string x) (string-length prefix)))
  309. (define (parse-arg prefix x)
  310. (match x
  311. (((? (symbol-with-prefix prefix) arg) . x)
  312. (values
  313. (or (string->number (symbol-suffix arg prefix))
  314. (error "bad mem arg" arg))
  315. x))
  316. (_ (values #f x))))
  317. (let*-values (((idx x) (parse-id-or-idx x))
  318. ((offset x) (parse-arg "offset=" x))
  319. ((align x) (parse-arg "align=" x)))
  320. (values (make-mem-arg (or idx 0)
  321. (or offset 0)
  322. (or align (natural-alignment inst)))
  323. x)))
  324. (define (unfold-instruction inst)
  325. (define (unparse-val-type type)
  326. (match type
  327. ((? symbol?) type)
  328. (($ <ref-type> #f ht) `(ref ,ht))
  329. (($ <ref-type> #t ht) `(ref null ,ht))))
  330. (define (unfold-func-sig sig)
  331. (match sig
  332. (($ <func-sig> params results)
  333. `(,@(map (match-lambda
  334. ((#f . vt) `(param ,(unparse-val-type vt)))
  335. ((id . vt) `(param ,id ,(unparse-val-type vt))))
  336. params)
  337. (result ,@(map unparse-val-type results))))))
  338. (define (unfold-type-use type)
  339. (match type
  340. (($ <type-use> #f sig)
  341. (unfold-func-sig sig))
  342. (($ <type-use> idx sig)
  343. `((type ,idx) ,@(unfold-func-sig sig)))))
  344. (define (unfold-mem-arg arg)
  345. (match arg
  346. (($ <mem-arg> id offset align)
  347. `(,@(if (eqv? id 0)
  348. '()
  349. (list id))
  350. ,@(if offset
  351. (list (string->symbol (format #f "offset=~a" offset)))
  352. '())
  353. ,@(if align
  354. (list (string->symbol (format #f "align=~a" align)))
  355. '())))))
  356. (match inst
  357. (((and tag (or 'loop 'block)) body ...)
  358. (cons tag (append body (list 'end))))
  359. (('if . body)
  360. (let*-values (((label body) (parse-id body))
  361. ((type body) (parse-block-type body)))
  362. (define (finish test consequent alternate)
  363. `(,@test
  364. if ,@(if label `(,label) '()) ,@(unfold-type-use type)
  365. ,@consequent
  366. else ,@alternate
  367. end))
  368. (match body
  369. ((test ... ('then consequent ...))
  370. (finish test consequent '()))
  371. ((test ... ('then consequent ...) ('else alternate ...))
  372. (finish test consequent alternate)))))
  373. (('try . body)
  374. (let*-values (((label body) (parse-id body))
  375. ((type body) (parse-block-type body)))
  376. (define (finish body catches catch-all)
  377. `(try ,@(if label `(,label) '()) ,@(unfold-type-use type)
  378. ,@body
  379. ,@(apply append catches)
  380. catch_all ,@catch-all
  381. end))
  382. (match body
  383. ((('do body ...) ('delegate label))
  384. `(try_delegate ,@(if label `(,label) '()) ,@(unfold-type-use type)
  385. ,@body end ,label))
  386. ((('do body ...))
  387. (finish body '() '()))
  388. ((('do body ...) (and catches ('catch _ ...)) ...)
  389. (finish body catches '()))
  390. ((('do body ...) (and catches ('catch _ ...)) ... ('catch_all catch-all ...))
  391. (finish body catches catch-all))
  392. ((('do body ...) ('catch_all catch-all ...))
  393. (finish body '() catch-all)))))
  394. (((and tag (or 'br 'br_if 'call 'local.get 'local.set 'local.tee
  395. 'global.get 'global.set 'throw 'rethrow))
  396. idx
  397. . args)
  398. `(,@args ,tag ,idx))
  399. (((and tag (or 'br_on_cast 'br_on_cast_fail)) target rt1 rt2
  400. . args)
  401. `(,@args ,tag ,target ,rt1 ,rt2))
  402. (('br_table . args)
  403. (let lp ((args args) (targets '()))
  404. (match args
  405. (((? id-or-idx? target) . args)
  406. (lp args (cons target targets)))
  407. (_ `(,@args br_table ,@(reverse targets))))))
  408. (('call_indirect . args)
  409. (let*-values (((table args) (parse-id-or-idx args))
  410. ((type args) (parse-type-use args)))
  411. `(,@args call_indirect ,table ,@(unfold-type-use type))))
  412. (((and tag (or 'i32.load
  413. 'i64.load
  414. 'f32.load
  415. 'f64.load
  416. 'i32.load8_s
  417. 'i32.load8_u
  418. 'i32.load16_s
  419. 'i32.load16_u
  420. 'i64.load8_s
  421. 'i64.load8_u
  422. 'i64.load16_s
  423. 'i64.load16_u
  424. 'i64.load32_s
  425. 'i64.load32_u
  426. 'i32.store
  427. 'i64.store
  428. 'f32.store
  429. 'f64.store
  430. 'i32.store8
  431. 'i32.store16
  432. 'i64.store8
  433. 'i64.store16
  434. 'i64.store32))
  435. . args)
  436. (let-values (((mem-arg args) (parse-mem-arg args tag)))
  437. `(,@args ,tag ,@(unfold-mem-arg mem-arg))))
  438. (((and tag (or 'i32.const 'i64.const 'f32.const 'f64.const)) val . insts)
  439. `(,@insts ,tag ,val))
  440. (('ref.func (? id-or-idx? id) . args)
  441. `(,@args ref.func ,id))
  442. (((and tag (or 'call_ref 'return_call_ref)) (? id-or-idx? id) . args)
  443. `(,@args ,tag ,id))
  444. (((and tag 'ref.null) (? valid-heap-type? id) . args)
  445. `(,@args ,tag ,id))
  446. (((and tag (or 'table.set 'table.get 'table.size 'table.grow
  447. 'table.fill 'elem.drop
  448. 'memory.size 'memory.grow 'memory.fill))
  449. (? id-or-idx? id) . args)
  450. `(,@args ,tag ,id))
  451. (((and tag (or 'memory.init 'table.init))
  452. (? id-or-idx? id) (? id-or-idx? eid) . args)
  453. `(,@args ,tag ,id ,eid))
  454. (((and tag (or 'memory.init 'table.init)) (? id-or-idx? eid) . args)
  455. `(,@args ,tag 0 ,eid))
  456. (((and tag (or 'memory.copy 'table.copy))
  457. (? id-or-idx? a) (? id-or-idx? b) . args)
  458. `(,@args ,tag ,a ,b))
  459. (((and tag (or 'memory.copy 'table.copy)) . args)
  460. `(,@args ,tag 0 0))
  461. (((and tag (or 'struct.new 'struct.new_default)) (? id-or-idx? id) . args)
  462. `(,@args ,tag ,id))
  463. (((and tag (or 'struct.set 'struct.get 'struct.get_s 'struct.get_u))
  464. (? id-or-idx? ti)
  465. (? id-or-idx? fi) . args)
  466. `(,@args ,tag ,ti ,fi))
  467. (((and tag (or 'ref.test 'ref.cast)) 'null (? valid-heap-type? id) . args)
  468. `(,@args ,tag null ,id))
  469. (((and tag (or 'ref.test 'ref.cast)) (? valid-heap-type? id) . args)
  470. `(,@args ,tag ,id))
  471. (((and tag 'string.const) (? string? str) . args)
  472. `(,@args ,tag ,str))
  473. (((and tag (or 'array.new 'array.new_default 'array.fill
  474. 'array.get 'array.set 'array.get_u 'array.get_s))
  475. (? id-or-idx? ti) . args)
  476. `(,@args ,tag ,ti))
  477. (((and tag 'array.new_fixed) (? id-or-idx? ti) (? s32? k) . args)
  478. `(,@args ,tag ,ti ,k))
  479. (((and tag (or 'array.copy
  480. 'array.new_data 'array.new_elem
  481. 'array.init_data 'array.init_elem))
  482. (? id-or-idx? ti1) (? id-or-idx? ti2) . args)
  483. `(,@args ,tag ,ti1 ,ti2))
  484. (((and tag 'return_call) (? id-or-idx? id) . args)
  485. `(,@args ,tag ,id))
  486. ((tag . args)
  487. `(,@args ,tag))))
  488. (define (parse-block x block-kind)
  489. (let lp ((in x) (out '()))
  490. (define (lp/inst in parsed)
  491. (lp in (cons parsed out)))
  492. (define (lp/block block-label in parsed)
  493. ;; Skip end label.
  494. (let-values (((label in) (parse-id in)))
  495. (when label
  496. (unless (eq? label block-label) (error "bad end label" label)))
  497. (lp/inst in parsed)))
  498. (match in
  499. (()
  500. (unless (eq? block-kind 'body)
  501. (error "unexpected end of instruction sequence"))
  502. (values (reverse out) '()))
  503. (((folded ...) . in)
  504. (lp (append (unfold-instruction folded) in) out))
  505. (((? kw? inst) . in)
  506. (match inst
  507. ((or 'block 'loop)
  508. (let*-values (((label in) (parse-id in))
  509. ((type in) (parse-block-type in))
  510. ((insts in) (parse-block in inst)))
  511. (lp/block label in `(,inst ,label ,type ,insts))))
  512. ('if
  513. (let*-values (((label in) (parse-id in))
  514. ((type in) (parse-block-type in))
  515. ((consequent in) (parse-block in 'then)))
  516. (match in
  517. (('else . in)
  518. (let-values (((alternate in) (parse-block in 'else)))
  519. (lp/block label in
  520. `(,inst ,label ,type ,consequent ,alternate))))
  521. (_
  522. (lp/block label in `(,inst ,label ,type ,consequent ()))))))
  523. ('else
  524. (unless (eq? block-kind 'then)
  525. (error "unexpected 'else'"))
  526. (values (reverse out) (cons 'else in)))
  527. ('try
  528. (let*-values (((label in) (parse-id in))
  529. ((type in) (parse-block-type in))
  530. ((body in) (parse-block in 'do)))
  531. (let loop ((in in) (catches '()))
  532. (match in
  533. (('catch tag . in)
  534. (let-values (((catch in) (parse-block in 'catch)))
  535. (loop in (cons (cons tag catch) catches))))
  536. (('catch_all . in)
  537. (let-values (((catch-all in) (parse-block in 'catch_all)))
  538. (lp/block label in
  539. `(,inst ,label ,type ,body
  540. ,(reverse catches)
  541. ,catch-all))))))))
  542. ('try_delegate
  543. (let*-values (((label in) (parse-id in))
  544. ((type in) (parse-block-type in))
  545. ((body in) (parse-block in 'do)))
  546. (match in
  547. (((? id-or-idx? id) . in)
  548. (lp/block label in `(,inst ,label ,type ,body ,id))))))
  549. ('catch
  550. (unless (memq block-kind '(do catch))
  551. (error "unexpected 'catch'"))
  552. (values (reverse out) (cons 'catch in)))
  553. ('catch_all
  554. (unless (memq block-kind '(do catch))
  555. (error "unexpected 'catch_all'"))
  556. (values (reverse out) (cons 'catch_all in)))
  557. ('end
  558. (when (eq? block-kind 'body)
  559. (error "unexpected 'end'"))
  560. (values (reverse out) in))
  561. ('ref.func
  562. (match in
  563. (((? id-or-idx? id) . in)
  564. (lp/inst in `(,inst ,id)))))
  565. ((or 'br 'br_if
  566. 'call 'local.get 'local.set 'local.tee 'global.get
  567. 'global.set 'throw 'rethrow)
  568. (let-values (((idx in) (parse-id-or-idx in)))
  569. (unless idx (error "missing idx" inst in))
  570. (lp/inst in `(,inst ,idx))))
  571. ((or 'br_on_cast 'br_on_cast_fail)
  572. (match in
  573. (((? id-or-idx? target) rt1 rt2 . in)
  574. (lp/inst
  575. in
  576. `(,inst ,target ,(parse-ref-type rt1) ,(parse-ref-type rt2))))))
  577. ('br_table
  578. (let lp ((in in) (targets '()))
  579. (match in
  580. (((? id-or-idx? target) . in)
  581. (lp in (cons target targets)))
  582. (_
  583. (match (reverse targets)
  584. ((target ... default)
  585. (lp/inst in `(,inst ,target ,default)))
  586. (_ (error "no targets for br_table")))))))
  587. ('call_indirect
  588. (let*-values (((table in) (parse-id-or-idx in))
  589. ((type in) (parse-type-use in)))
  590. (lp/inst in `(,inst ,(or table 0) ,type))))
  591. ((or 'i32.load 'i64.load
  592. 'f32.load 'f64.load
  593. 'i32.load8_s 'i32.load8_u 'i32.load16_s 'i32.load16_u
  594. 'i64.load8_s 'i64.load8_u 'i64.load16_s 'i64.load16_u
  595. 'i64.load32_s 'i64.load32_u
  596. 'i32.store 'i64.store
  597. 'f32.store 'f64.store
  598. 'i32.store8 'i32.store16
  599. 'i64.store8 'i64.store16 'i64.store32)
  600. (let-values (((mem-arg in) (parse-mem-arg in inst)))
  601. (lp/inst in `(,inst ,mem-arg))))
  602. ('i32.const
  603. (match in
  604. (((? s32? const) . in)
  605. (lp/inst in `(,inst ,const)))))
  606. ('i64.const
  607. (match in
  608. (((? s64? const) . in)
  609. (lp/inst in `(,inst ,const)))))
  610. ((or 'f32.const 'f64.const)
  611. (match in
  612. (((? real? const) . in)
  613. (lp/inst in `(,inst ,(exact->inexact const))))))
  614. ((or 'call_ref 'return_call_ref)
  615. (match in
  616. (((? id-or-idx? id) . in)
  617. (lp/inst in `(,inst ,id)))))
  618. ('ref.null
  619. (match in
  620. ((id . in)
  621. (lp/inst in `(,inst ,(parse-heap-type id))))))
  622. ((or 'table.set 'table.get 'table.size 'table.grow
  623. 'table.fill 'elem.drop
  624. 'memory.size 'memory.grow 'memory.fill)
  625. (match in
  626. (((? id-or-idx? id) . in)
  627. (lp/inst in `(,inst ,id)))
  628. (_
  629. (lp/inst in `(,inst 0)))))
  630. ((or 'table.copy 'memory.copy)
  631. (match in
  632. (((? id-or-idx? a) (? id-or-idx? b) . in)
  633. (lp/inst in `(,inst ,a ,b)))
  634. (_
  635. (lp/inst in `(,inst 0 0)))))
  636. ((or 'table.init 'memory.init)
  637. (match in
  638. (((? id-or-idx? tid) (? id-or-idx? eid) . in)
  639. (lp/inst in `(,inst ,tid ,eid)))
  640. (((? id-or-idx? eid) . in)
  641. (lp/inst in `(,inst 0 ,eid)))))
  642. ((or 'struct.new 'struct.new_default)
  643. (match in
  644. (((? id-or-idx? id) . in)
  645. (lp/inst in `(,inst ,id)))))
  646. ((or 'struct.set 'struct.get 'struct.get_s 'struct.get_u)
  647. (match in
  648. (((? id-or-idx? ti) (? id-or-idx? fi) . in)
  649. (lp/inst in `(,inst ,ti ,fi)))))
  650. ((or 'ref.test 'ref.cast)
  651. (match in
  652. (('null ht . in)
  653. (lp/inst in `(,inst ,(make-ref-type #t (parse-heap-type ht)))))
  654. ((ht . in)
  655. (lp/inst in `(,inst ,(make-ref-type #f (parse-heap-type ht)))))))
  656. ('string.const
  657. (match in
  658. (((? string? str) . in)
  659. (lp/inst in `(,inst ,str)))))
  660. ((or 'array.new 'array.new_default 'array.fill
  661. 'array.get 'array.set 'array.get_u 'array.get_s)
  662. (match in
  663. (((? id-or-idx? ti) . in)
  664. (lp/inst in `(,inst ,ti)))))
  665. ('array.new_fixed
  666. (match in
  667. (((? id-or-idx? ti) (? s32? k) . in)
  668. (lp/inst in `(,inst ,ti ,k)))))
  669. ((or 'array.copy
  670. 'array.new_data 'array.new_elem
  671. 'array.init_data 'array.init_elem)
  672. (match in
  673. (((? id-or-idx? idx1) (? id-or-idx? idx2) . in)
  674. (lp/inst in `(,inst ,idx1 ,idx2)))))
  675. ('return_call
  676. (match in
  677. (((? id-or-idx? id) . in)
  678. (lp/inst in `(,inst ,id)))))
  679. (_
  680. (lp/inst in (list inst))))))))
  681. (define (parse-offset x)
  682. (parse-block (match x
  683. (('offset . offset) offset)
  684. (offset (list offset)))
  685. 'body))
  686. (define (parse-init init)
  687. (parse-block (match init
  688. (('item . init) init)
  689. (init (list init)))
  690. 'body))
  691. (define (parse-elem x)
  692. (define (parse-table-use x)
  693. (match x
  694. ((('table (? id-or-idx? table)) . x) (values table x))
  695. (_ (values #f x))))
  696. (define (parse-elemlist elemlist)
  697. (match elemlist
  698. (('func (? id-or-idx? id) ...)
  699. (values 'funcref (map (lambda (id) `((ref.func ,id))) id)))
  700. (((? id-or-idx? id) ...)
  701. (values 'funcref (map (lambda (id) `((ref.func ,id))) id)))
  702. ((type init ...)
  703. (values (parse-ref-type type) (map parse-init init)))))
  704. (let-values (((id x) (parse-id x)))
  705. (match x
  706. (('declare . elemlist)
  707. ;; Declarative element segment.
  708. (let-values (((type inits) (parse-elemlist elemlist)))
  709. (make-elem id 'declarative #f type #f inits)))
  710. ((('table table) offset . elemlist)
  711. ;; Active element segment with explicit table.
  712. (let-values (((type inits) (parse-elemlist elemlist)))
  713. (make-elem id 'active table type (parse-offset offset) inits)))
  714. (((and offset (or ('offset . _) ('i32.const _))) . elemlist)
  715. ;; Active element segment for table 0.
  716. (let-values (((type inits) (parse-elemlist elemlist)))
  717. (make-elem id 'active 0 type (parse-offset offset) inits)))
  718. (elemlist
  719. (let-values (((type inits) (parse-elemlist elemlist)))
  720. (make-elem id 'passive #f type #f inits))))))
  721. (define (bytevector-concatenate bvs)
  722. (call-with-output-bytevector
  723. (lambda (p)
  724. (for-each (lambda (bv) (put-bytevector p bv)) bvs))))
  725. (define (parse-data x)
  726. (let-values (((id x) (parse-id x)))
  727. (match x
  728. ((('memory (? id-or-idx? mem)) offset . init)
  729. ;; Active data segment with explicit memory.
  730. (make-data id 'active mem (parse-offset offset)
  731. (bytevector-concatenate init)))
  732. (((and offset (or ('offset . _) ('i32.const _))) . init)
  733. ;; Active data segment for memory 0.
  734. (make-data id 'active 0 (parse-offset offset)
  735. (bytevector-concatenate init)))
  736. (init
  737. ;; Passive data segment.
  738. (make-data id 'passive #f #f (bytevector-concatenate init))))))
  739. (define (parse-start start)
  740. (let-values (((idx x) (parse-id-or-idx start)))
  741. (match x
  742. (() (or idx 0))
  743. (_ (error "bad start" x)))))
  744. (match (partition-clauses expr)
  745. (($ <wasm> id types imports funcs tables memories globals exports start
  746. elems datas tags strings custom)
  747. (let ((types (map parse-type-def types))
  748. (imports (map parse-import imports))
  749. (exports (map parse-export exports))
  750. (elems (map parse-elem elems))
  751. (datas (map parse-data datas))
  752. (start (and start (parse-start start))))
  753. (define-syntax-rule (push! id val)
  754. (set! id (append! id (list val))))
  755. (define (visit-func x)
  756. (let*-values (((id x) (parse-id x))
  757. ((id) (or id (fresh-id!))))
  758. (let lp ((x x))
  759. (match x
  760. ((('export name) . x)
  761. (push! exports (make-export name 'func id))
  762. (lp x))
  763. ((('import mod name) . x)
  764. (let-values (((type x) (parse-type-use x)))
  765. (match x
  766. (()
  767. (push! imports (make-import mod name 'func id type))
  768. #f)
  769. (_
  770. (error "bad import" x)))))
  771. (_
  772. (let-values (((type x) (parse-type-use x)))
  773. (let lp ((x x) (locals '()))
  774. (match x
  775. ((('local (? id? id) vt) . x)
  776. (lp x (cons (make-local id (parse-val-type vt)) locals)))
  777. (_
  778. (make-func id type (reverse locals)
  779. (parse-block x 'body)))))))))))
  780. (define (visit-table x)
  781. (let*-values (((id x) (parse-id x))
  782. ((id) (or id (fresh-id!))))
  783. (let lp ((x x))
  784. (match x
  785. ((('export name) . x)
  786. (push! exports (make-export name 'table id))
  787. (lp x))
  788. ((('import mod name) . x)
  789. (let ((type (parse-table-type x)))
  790. (push! imports (make-import mod name 'table id type))
  791. #f))
  792. ((elemtype ... ('elem . segment))
  793. (let ((elemtype (parse-elem-type elemtype))
  794. (len (length segment))
  795. (offset '((i32.const 0))))
  796. (push!
  797. elems
  798. (match segment
  799. (((? id-or-idx? id) ...)
  800. (make-elem #f 'active id 'funcref offset
  801. (map (lambda (id) `((ref.func ,id))) id)))
  802. (((_ ...) ...)
  803. (make-elem #f 'active id 'funcref offset
  804. (map (lambda (init)
  805. (parse-block init 'body))
  806. segment)))))
  807. (make-table id
  808. (make-table-type (make-limits len len)
  809. elemtype)
  810. #f)))
  811. (_
  812. (make-table id (parse-table-type x) #f))))))
  813. (define (visit-memory x)
  814. (let*-values (((id x) (parse-id x))
  815. ((id) (or id (fresh-id!))))
  816. (let lp ((x x))
  817. (match x
  818. ((('export name) . x)
  819. (push! exports (make-export name 'memory id))
  820. (lp x))
  821. ((('import mod name) . x)
  822. (let ((type (parse-mem-type x)))
  823. (push! imports (make-import mod name 'memory id type))
  824. #f))
  825. ((('data . data))
  826. (let* ((init (bytevector-concatenate data))
  827. (len (bytevector-length init)))
  828. (push! data (make-data id 'active 0 '((i32.const 0)) init))
  829. (make-memory id (make-mem-type (make-limits len len)))))
  830. (_
  831. (make-memory id (parse-mem-type x)))))))
  832. (define (visit-global x)
  833. (let*-values (((id x) (parse-id x))
  834. ((id) (or id (fresh-id!))))
  835. (let lp ((x x))
  836. (match x
  837. ((('export name) . x)
  838. (push! exports (make-export name 'global id))
  839. (lp x))
  840. ((('import mod name) type)
  841. (let ((type (parse-global-type type)))
  842. (push! imports (make-import mod name 'global id type))
  843. #f))
  844. ((type . init)
  845. (make-global id
  846. (parse-global-type type)
  847. (parse-block init 'body)))))))
  848. (define (visit-tag x)
  849. (let*-values (((id x) (parse-id x))
  850. ((id) (or id (fresh-id!))))
  851. (let lp ((x x))
  852. (match x
  853. ((('export name) . x)
  854. (push! exports (make-export name 'tag id))
  855. (lp x))
  856. ((('import mod name) . x)
  857. (let ((type (parse-tag-type x)))
  858. (push! imports (make-import mod name 'tag id type))
  859. #f))
  860. (_
  861. (make-tag id (parse-tag-type x)))))))
  862. (let ((funcs (filter-map visit-func funcs))
  863. (tables (filter-map visit-table tables))
  864. (memories (filter-map visit-memory memories))
  865. (globals (filter-map visit-global globals))
  866. (tags (filter-map visit-tag tags)))
  867. (make-wasm id types imports funcs tables memories globals exports
  868. start elems datas tags strings custom))))))
  869. (define (wasm->wat mod)
  870. (match mod
  871. (($ <wasm> id types imports funcs tables memories globals exports start
  872. elems datas tags strings custom)
  873. ;; TODO: Factorize type-repr code that is duplicated between here
  874. ;; and (wasm dump).
  875. (define (val-type-repr vt)
  876. (match vt
  877. (($ <ref-type> #t ht)
  878. `(ref null ,ht))
  879. (($ <ref-type> #f ht)
  880. `(ref ,ht))
  881. (_ vt)))
  882. (define (params-repr params)
  883. (match params
  884. (() '())
  885. ((($ <param> #f type) ...)
  886. `((param ,@(map val-type-repr type))))
  887. ((($ <param> id type) . params)
  888. (cons `(param ,id ,(val-type-repr type))
  889. (params-repr params)))))
  890. (define (results-repr results)
  891. (map (lambda (type) `(result ,(val-type-repr type))) results))
  892. (define (field-repr field)
  893. (define (wrap mutable? repr)
  894. (if mutable? `(mut ,repr) repr))
  895. (match field
  896. (($ <field> id mutable? type)
  897. (let ((repr (wrap mutable? (val-type-repr type))))
  898. (if id
  899. `(field ,id ,repr)
  900. repr)))))
  901. (define (type-repr type)
  902. (match type
  903. (($ <func-sig> params results)
  904. `(func ,@(params-repr params) ,@(results-repr results)))
  905. (($ <sub-type> final? supers type)
  906. `(sub ,@(if final? '(final) '()) ,@supers ,(type-repr type)))
  907. (($ <struct-type> fields)
  908. `(struct ,@(map field-repr fields)))
  909. (($ <array-type> mutable? type)
  910. `(array ,(field-repr (make-field #f mutable? type))))))
  911. (define (type-use-repr type-use)
  912. (match type-use
  913. (($ <type-use> _ ($ <func-sig> params results))
  914. (append (params-repr params) (results-repr results)))))
  915. (define (block-type-repr bt)
  916. (match bt
  917. (#f '())
  918. ((? type-use? use)
  919. (type-use-repr use))
  920. ((? ref-type? rt)
  921. `((param ,(val-type-repr rt))))))
  922. (define (instr-repr instr)
  923. (define (make-prefix-arg prefix x)
  924. (if (zero? x)
  925. '()
  926. (list (string->symbol (string-append prefix (number->string x))))))
  927. (match instr
  928. (($ <mem-arg> id offset align)
  929. `(,id
  930. ,@(make-prefix-arg "offset=" offset)
  931. ,@(make-prefix-arg "align=" align)))
  932. (($ <ref-type> _ (? symbol? ht))
  933. `(,ht))
  934. (($ <type-use> idx)
  935. `((type ,idx)))
  936. ;; Instructions that need special handling:
  937. (('ref.cast ($ <ref-type> null? ht))
  938. `(ref.cast ,@(if null? '(null) '()) ,ht))
  939. (('string.const (? number? idx))
  940. `(string.const ,(list-ref strings idx)))
  941. (('if label bt consequent alternate)
  942. `(if ,@(block-type-repr bt)
  943. ,@(if label `(,label) '())
  944. (then ,@(instrs-repr consequent))
  945. (else ,@(instrs-repr alternate))))
  946. (((and op (or 'block 'loop)) label bt body)
  947. `(,op ,@(if label `(,label) '())
  948. ,@(block-type-repr bt)
  949. ,@(instrs-repr body)))
  950. ((_ ...)
  951. (append-map instr-repr instr))
  952. (_ `(,instr))))
  953. (define (instrs-repr instrs)
  954. (map instr-repr instrs))
  955. (define (limits-repr limits)
  956. (match limits
  957. (($ <limits> min max)
  958. (if max (list min max) (list min)))))
  959. (define (elem-item-repr init)
  960. `(item ,@(instrs-repr init)))
  961. `(module
  962. ,@(if id `(,id) '())
  963. ;; Types
  964. ,@(map (match-lambda
  965. (($ <type> id val)
  966. `(type ,id ,(type-repr val)))
  967. (($ <rec-group> types)
  968. `(rec ,@(map (match-lambda
  969. (($ <type> id val)
  970. `(type ,id ,(type-repr val))))
  971. types))))
  972. types)
  973. ;; Imports
  974. ,@(map (match-lambda
  975. (($ <import> mod name 'func id type)
  976. `(import ,mod ,name (func ,id ,@(type-use-repr type))))
  977. (($ <import> mod name 'global id ($ <global-type> mutable? type))
  978. `(import ,mod ,name
  979. (global ,id ,(if mutable?
  980. `(mut ,(val-type-repr type))
  981. (val-type-repr type)))))
  982. (($ <import> mod name 'memory id ($ <mem-type> limits))
  983. `(import ,mod ,name (memory ,id ,@(limits-repr limits))))
  984. (($ <import> mod name 'table id ($ <table-type> limits elem-type))
  985. `(import ,mod ,name
  986. (table ,id ,@(limits-repr limits)
  987. ,(val-type-repr elem-type)))))
  988. imports)
  989. ;; Exports
  990. ,@(map (match-lambda
  991. (($ <export> name kind idx)
  992. `(export ,name (,kind ,idx))))
  993. exports)
  994. ;; Globals
  995. ,@(map (match-lambda
  996. (($ <global> id ($ <global-type> mutable? type) init)
  997. `(global ,id
  998. ,(if mutable?
  999. `(mut ,(val-type-repr type))
  1000. (val-type-repr type))
  1001. ,@(instrs-repr init))))
  1002. globals)
  1003. ;; Tables
  1004. ,@(map (match-lambda
  1005. (($ <table> id ($ <table-type> limits elem-type))
  1006. `(table ,id ,@(limits-repr limits)
  1007. ,(val-type-repr elem-type))))
  1008. tables)
  1009. ;; Memories
  1010. ,@(map (match-lambda
  1011. (($ <memory> id ($ <mem-type> limits))
  1012. `(memory ,id ,@(limits-repr limits))))
  1013. memories)
  1014. ;; Element segments
  1015. ,@(map (match-lambda
  1016. (($ <elem> id mode table type offset items)
  1017. (match mode
  1018. ('passive
  1019. `(elem ,id ,(val-type-repr type)
  1020. ,@(map elem-item-repr items)))
  1021. ('active
  1022. `(elem ,id (table ,table)
  1023. (offset ,@(instrs-repr offset))
  1024. ,(val-type-repr type)
  1025. ,@(map elem-item-repr items)))
  1026. ('declarative
  1027. `(elem ,id declare ,@(map elem-item-repr items))))))
  1028. elems)
  1029. ;; Data segments
  1030. ,@(map (match-lambda
  1031. (($ <data> id mode mem offset init)
  1032. (case mode
  1033. ((active)
  1034. `(data ,id ,mem ,@(instrs-repr offset) ,init))
  1035. ((passive)
  1036. `(data ,id ,init)))))
  1037. datas)
  1038. ;; Functions
  1039. ,@(map (match-lambda
  1040. (($ <func> id type locals body)
  1041. (match type
  1042. (($ <type-use> idx sig)
  1043. `(func ,(or id idx)
  1044. ,@(match (type-repr sig)
  1045. (('func . params+results)
  1046. params+results))
  1047. ,@(map (match-lambda
  1048. (($ <local> id type)
  1049. `(local ,id ,(val-type-repr type))))
  1050. locals)
  1051. ,@(instrs-repr body))))))
  1052. funcs)
  1053. ;; Start function
  1054. ,@(if start `((start ,start)) '())))))