Overview

Formatter

Given a file horrible.wat:

(module (memory
10) (func
$f (param
     $n i32) (result
i32) (if
             (                       i32.lt_s
        (
local.get $n)
        (
                          i32.const
                          
                          
                          0))
    (  then
(
 
 unreachable)))

    (
     if
( 
i32.lt_s
        (local.get                            $n)
        (i32.const                             2))
    (then          (return (local.get $n)))) (if   
      (i32.eqz   
(i32.load (i32.mul (i32.const 4) (local.get $n)))) (then local.get $n i32.const 4 i32.mul
      (call $f (i32.sub (local.get $n) (i32.const 1)))
      (call $f (i32.sub (local.get $n)
(i32.const 2))) i32.add   i32.store )) local.get $n       i32.const 4 i32.mul i32.load return))

Owi will format it like this:

$ owi fmt horrible.wat
(module
  (memory 10)
  (func $f (param $n i32) (result i32)
    local.get $n
    i32.const 0
    i32.lt_s
    (if
      (then
        unreachable
      )
    )
    local.get $n
    i32.const 2
    i32.lt_s
    (if
      (then
        local.get $n
        return
      )
    )
    i32.const 4
    local.get $n
    i32.mul
    i32.load align=1
    i32.eqz
    (if
      (then
        local.get $n
        i32.const 4
        i32.mul
        local.get $n
        i32.const 1
        i32.sub
        call $f
        local.get $n
        i32.const 2
        i32.sub
        call $f
        i32.add
        i32.store align=1
      )
    )
    local.get $n
    i32.const 4
    i32.mul
    i32.load align=1
    return
  )
)

Are you able to recognize the program now?

Interpreter

Given a file 42.wat with the following content:

(module $quickstart
  (func $f
    i32.const 20
    i32.const 22
    i32.add
    drop
  )
  (start $f)
)

Running the interpreter is as simple as:

$ owi run ./42.wat

Nothing is happening, so you can add the -v option to print an execution trace:

$ owi run ./42.wat -v
owi: [INFO] parsing      ...
owi: [INFO] checking     ...
owi: [INFO] typechecking ...
owi: [INFO] linking      ...
owi: [INFO] interpreting ...
owi: [INFO] stack         : [  ]
owi: [INFO] running instr : call 0
owi: [INFO] calling func  : func f
owi: [INFO] stack         : [  ]
owi: [INFO] running instr : i32.const 20
owi: [INFO] stack         : [ i32.const 20 ]
owi: [INFO] running instr : i32.const 22
owi: [INFO] stack         : [ i32.const 22 ; i32.const 20 ]
owi: [INFO] running instr : i32.add
owi: [INFO] stack         : [ i32.const 42 ]
owi: [INFO] running instr : drop

Script using the spectest module

Given the following print.wast file:

(module

  (func $print_i32 (import "spectest" "print_i32") (param i32))

  (func $main
    i32.const 42
    call $print_i32
  )

  (start $main)
)

You can print the value thanks to the print_i32 function imported from the spectest module:

$ owi script ./print.wast
42

Optimizer

Given the useless program useless.wat:

(module
  (func $i32binop
    i32.const 21
    i32.const 21
    i32.add
    i32.const 0
    drop
    drop

    i32.const 63
    i32.const 21
    i32.sub
    i32.const 0
    drop
    drop

    i32.const 21
    i32.const 2
    i32.mul
    i32.const 0
    drop
    drop

    i32.const 84
    i32.const 2
    i32.div_s
    i32.const 0
    drop
    drop

    i32.const 84
    i32.const 2
    i32.div_u
    i32.const 0
    drop
    drop

    i32.const -42
    i32.const 4
    i32.rem_s     ;; 4*10 + 2 > =-2
    i32.const 0
    drop
    drop

    i32.const -42
    i32.const 4
    i32.rem_u     ;; 4*10 + 2 > =2
    i32.const 0
    drop
    drop

    i32.const 1
    i32.const 3
    i32.and          ;; bitwise ope > =1
    i32.const 0
    drop
    drop

    i32.const 1
    i32.const 3
    i32.or           ;; bitwise ope > =3
    i32.const 0
    drop
    drop

    i32.const 1
    i32.const 3
    i32.xor          ;; bitwise ope > =2
    i32.const 0
    drop
    drop

    i32.const 1
    i32.const 3
    i32.shl          ;; shift left ope > =8
    i32.const 0
    drop
    drop

    i32.const 8
    i32.const 3
    i32.shr_u        ;; shift right ope > =1
    i32.const 0
    drop
    drop

    i32.const 8
    i32.const 3
    i32.shr_s        ;; shift right ope > =1
    i32.const 0
    drop
    drop

    i32.const 1
    i32.const 3
    i32.rotl         ;; rotation left ope > =8
    i32.const 0
    drop
    drop

    i32.const 8
    i32.const 3
    i32.rotr         ;; rotation left ope > =1
    i32.const 0
    drop
    drop
  )

  (func $i64binop
    i64.const 21
    i64.const 21
    i64.add
    i32.const 0
    drop
    drop

    i64.const 63
    i64.const 21
    i64.sub
    i32.const 0
    drop
    drop

    i64.const 21
    i64.const 2
    i64.mul
    i32.const 0
    drop
    drop

    i64.const 84
    i64.const 2
    i64.div_s
    i32.const 0
    drop
    drop

    i64.const 84
    i64.const 2
    i64.div_u
    i32.const 0
    drop
    drop

    i64.const -42
    i64.const 4
    i64.rem_s     ;; 4*10 + 2 > =-2
    i32.const 0
    drop
    drop

    i64.const -42
    i64.const 4
    i64.rem_u     ;; 4*10 + 2 > =2
    i32.const 0
    drop
    drop

    i64.const 1
    i64.const 3
    i64.and          ;; bitwise ope > =1
    i32.const 0
    drop
    drop

    i64.const 1
    i64.const 3
    i64.or           ;; bitwise ope > =3
    i32.const 0
    drop
    drop

    i64.const 1
    i64.const 3
    i64.xor          ;; bitwise ope > =2
    i32.const 0
    drop
    drop

    i64.const 1
    i64.const 3
    i64.shl          ;; shift left ope > =8
    i32.const 0
    drop
    drop

    i64.const 8
    i64.const 3
    i64.shr_u        ;; shift right ope > =1
    i32.const 0
    drop
    drop

    i64.const 8
    i64.const 3
    i64.shr_s        ;; shift right ope > =1
    i32.const 0
    drop
    drop

    i64.const 1
    i64.const 3
    i64.rotl         ;; rotation left ope > =8
    i32.const 0
    drop
    drop

    i64.const 8
    i64.const 3
    i64.rotr         ;; rotation left ope > =1
    i32.const 0
    drop
    drop
  )

  (func $f32binop
    f32.const 21
    f32.const 21
    f32.add
    i32.const 0
    drop
    drop

    f32.const 63
    f32.const 21
    f32.sub
    i32.const 0
    drop
    drop

    f32.const 21
    f32.const 2
    f32.mul
    i32.const 0
    drop
    drop

    f32.const 84
    f32.const 2
    f32.div
    i32.const 0
    drop
    drop

    f32.const 42
    f32.const 21
    f32.max
    i32.const 0
    drop
    drop

    f32.const 42
    f32.const 84
    f32.min
    i32.const 0
    drop
    drop

    f32.const -42
    f32.const 21
    f32.copysign
    i32.const 0
    drop
    drop
  )

  (func $f64binop
    f64.const 21
    f64.const 21
    f64.add
    i32.const 0
    drop
    drop

    f64.const 63
    f64.const 21
    f64.sub
    i32.const 0
    drop
    drop

    f64.const 21
    f64.const 2
    f64.mul
    i32.const 0
    drop
    drop

    f64.const 84
    f64.const 2
    f64.div
    i32.const 0
    drop
    drop

    f64.const 42
    f64.const 21
    f64.max
    i32.const 0
    drop
    drop

    f64.const 42
    f64.const 84
    f64.min
    i32.const 0
    drop
    drop

    f64.const -42
    f64.const 21
    f64.copysign
    i32.const 0
    drop
    drop
  )

  (func $start
    call $i32binop
    call $i64binop
    call $f32binop
    call $f64binop
  )

  (start $start)
)

Owi is able to get rid of most of the code:

$ owi opt useless.wat
(module
  (type (sub final  (func)))
  (func $i32binop

  )
  (func $i64binop

  )
  (func $f32binop

  )
  (func $f64binop

  )
  (func $start
    call 0
    call 1
    call 2
    call 3
  )
  (start 4)
)

Validator

Given a file type_error.wat with the following content:

(module $quickstart
  (func $f
    i32.const 20
    i32.const 22
    i32.add
    i32.add
    drop
  )
  (start $f)
)

Running the validator is as simple as:

$ owi validate ./type_error.wat
owi: [ERROR] type mismatch (expected [i32 i32] but stack is [i32])
[35]

You can also print a more detailed trace with the -v option:

$ owi validate ./type_error.wat -v
owi: [INFO] parsing      ...
owi: [INFO] checking     ...
owi: [INFO] typechecking ...
owi: [ERROR] type mismatch (expected [i32 i32] but stack is [i32])
[35]

Wasm2wat

Given a file 42.wasm, you can convert it to result.wat and then run it:

$ owi wasm2wat 42.wasm -o result.wat
$ cat result.wat
(module
  (type (sub final  (func)))
  (func
    i32.const 20
    i32.const 22
    i32.add
    drop
  )
  (start 0)
)
$ owi run result.wat -v
owi: [INFO] parsing      ...
owi: [INFO] checking     ...
owi: [INFO] typechecking ...
owi: [INFO] linking      ...
owi: [INFO] interpreting ...
owi: [INFO] stack         : [  ]
owi: [INFO] running instr : call 0
owi: [INFO] calling func  : func anonymous
owi: [INFO] stack         : [  ]
owi: [INFO] running instr : i32.const 20
owi: [INFO] stack         : [ i32.const 20 ]
owi: [INFO] running instr : i32.const 22
owi: [INFO] stack         : [ i32.const 22 ; i32.const 20 ]
owi: [INFO] running instr : i32.add
owi: [INFO] stack         : [ i32.const 42 ]
owi: [INFO] running instr : drop

Wat2wasm

Given a file 42.wat, you can convert it to result.wasm and then run it:

$ owi wat2wasm 42.wat -o result.wasm
$ owi run result.wasm -v
owi: [INFO] typechecking ...
owi: [INFO] linking      ...
owi: [INFO] interpreting ...
owi: [INFO] stack         : [  ]
owi: [INFO] running instr : call 0
owi: [INFO] calling func  : func anonymous
owi: [INFO] stack         : [  ]
owi: [INFO] running instr : i32.const 20
owi: [INFO] stack         : [ i32.const 20 ]
owi: [INFO] running instr : i32.const 22
owi: [INFO] stack         : [ i32.const 22 ; i32.const 20 ]
owi: [INFO] running instr : i32.add
owi: [INFO] stack         : [ i32.const 42 ]
owi: [INFO] running instr : drop