Decompilers make it possible to have human readyble representations of a compiled WebAssembly module. For instance, having defined functions to compute fibonacci numbers.

import swam._
import text._
import decompilation._
import util.pretty._
import cats.effect._
import java.nio.file.Paths

implicit val cs = IO.contextShift(scala.concurrent.ExecutionContext.global)

def compdec(p: String): (Doc, Doc) =
  Blocker[IO].use { blocker =>
    for {
      tcompiler <- Compiler[IO](blocker)
      rdecompiler <-RawDecompiler[IO]
      tdecompiler <- TextDecompiler[IO](blocker)
      rd <- rdecompiler.decompile(tcompiler.stream(Paths.get(p), true, blocker))
      td <- tdecompiler.decompile(tcompiler.stream(Paths.get(p), true, blocker))
    } yield (rd, td)
  }.unsafeRunSync()

val (rd, td) = compdec("fibo.wat")

The simple raw decompiler simply prints a text version of the module sections. It can render modules that are not valid.

println(rd.render(0))
// ; section "Types"
// ; type 0
// [i64] → [i64]
// ; type 1
// [] → [i64]
// ; type 2
// [i64, i64, i64] → [i64]
// ; section "Imports"
// 
// ; section "Functions"
// ; function type 0
// 0
// ; function type 1
// 2
// ; function type 2
// 0
// ; section "Tables"
// 
// ; section "Memories"
// 
// ; section "Globals"
// 
// ; section "Exports"
// {name naive, func 0}
// {name clever, func 2}
// ; section "Elements"
// 
// ; section "Code"
// ; function body 0
// local.get 0
// i64.const 2
// i64.lt_s
// if @1
//   i64.const 1
// else
//   local.get 0
//   i64.const 2
//   i64.sub
//   call 0
//   local.get 0
//   i64.const 1
//   i64.sub
//   call 0
//   i64.add
// end
// ; function body 1
// local.get 2
// i64.const 0
// i64.gt_s
// if @1
//   local.get 1
//   local.get 1
//   local.get 0
//   i64.add
//   local.get 2
//   i64.const 1
//   i64.sub
//   call 1
// else
//   local.get 0
// end
// ; function body 2
// i64.const 1
// i64.const 1
// local.get 0
// call 1
// ; section "Data"
// 
// ; custom section "name"
// 00046669626f01170300056e616976650105696e6e65720206636c65766572021b03000401000169010c0300026e3201026e3102016e020401000169

The smart text decompiler renders a formatted text version of the module. The module must be valid to be rendered.

println(td.render(0))
// (module $fibo
//   (export
//     "naive"
//     (func $naive))
//   (export
//     "clever"
//     (func $clever))
//   (func $naive
//     (param $i i64)
//     (result i64)
//     (if
//       (type
//          1
//       (i64.lt_s
//         (local.get $i)
//         (i64.const 2))
//     (then
//       i64.const 1)
//     (else
//       (i64.add
//         (call $naive
//           (i64.sub
//             (local.get $i)
//             (i64.const 2)))
//         (call $naive
//           (i64.sub
//             (local.get $i)
//             (i64.const 1)))))))
//   (func $inner
//     (param $n2 i64)
//     (param $n1 i64)
//     (param $n i64)
//     (result i64)
//     (if
//       (type
//          1
//       (i64.gt_s
//         (local.get $n)
//         (i64.const 0))
//     (then
//       (call $inner
//         (local.get $n1)
//         (i64.add
//           (local.get $n1)
//           (local.get $n2))
//         (i64.sub
//           (local.get $n)
//           (i64.const 1))))
//     (else
//       local.get $n2)))
//   (func $clever
//     (param $i i64)
//     (result i64)
//     (call $inner
//       (i64.const 1)
//       (i64.const 1)
//       (local.get $i))))