blob: 0d174cd0efac6667ad3abb45c26412026ed7c9c1 [file] [edit]
;; Unhandled tags & guards
(module
(tag $exn)
(tag $e1)
(tag $e2)
(type $f1 (func))
(type $k1 (cont $f1))
(func $f1 (export "unhandled-1")
(suspend $e1)
)
(func (export "unhandled-2")
(resume $k1 (cont.new $k1 (ref.func $f1)))
)
(func (export "unhandled-3")
(block $h (result (ref $k1))
(resume $k1 (on $e2 $h) (cont.new $k1 (ref.func $f1)))
(unreachable)
)
(drop)
)
(func (export "handled")
(block $h (result (ref $k1))
(resume $k1 (on $e1 $h) (cont.new $k1 (ref.func $f1)))
(unreachable)
)
(drop)
)
(elem declare func $f2)
(func $f2
(throw $exn)
)
(func (export "uncaught-1")
(block $h (result (ref $k1))
(resume $k1 (on $e1 $h) (cont.new $k1 (ref.func $f2)))
(unreachable)
)
(drop)
)
(func (export "uncaught-2")
(block $h (result (ref $k1))
(resume $k1 (on $e1 $h) (cont.new $k1 (ref.func $f1)))
(unreachable)
)
(resume_throw $k1 $exn)
)
(elem declare func $f3)
(func $f3
(call $f4)
)
(func $f4
(suspend $e1)
)
(func (export "uncaught-3")
(block $h (result (ref $k1))
(resume $k1 (on $e1 $h) (cont.new $k1 (ref.func $f3)))
(unreachable)
)
(resume_throw $k1 $exn)
)
(elem declare func $r0 $r1)
(func $r0)
(func $r1 (suspend $e1) (suspend $e1))
(func $nl1 (param $k (ref $k1))
(resume $k1 (local.get $k))
(resume $k1 (local.get $k))
)
(func $nl2 (param $k (ref $k1))
(block $h (result (ref $k1))
(resume $k1 (on $e1 $h) (local.get $k))
(unreachable)
)
(resume $k1 (local.get $k))
(unreachable)
)
(func $nl3 (param $k (ref $k1))
(local $k' (ref null $k1))
(block $h1 (result (ref $k1))
(resume $k1 (on $e1 $h1) (local.get $k))
(unreachable)
)
(local.set $k')
(block $h2 (result (ref $k1))
(resume $k1 (on $e1 $h2) (local.get $k'))
(unreachable)
)
(resume $k1 (local.get $k'))
(unreachable)
)
(func $nl4 (param $k (ref $k1))
(drop (cont.bind $k1 $k1 (local.get $k)))
(resume $k1 (local.get $k))
)
(func (export "non-linear-1")
(call $nl1 (cont.new $k1 (ref.func $r0)))
)
(func (export "non-linear-2")
(call $nl2 (cont.new $k1 (ref.func $r1)))
)
(func (export "non-linear-3")
(call $nl3 (cont.new $k1 (ref.func $r1)))
)
(func (export "non-linear-4")
(call $nl4 (cont.new $k1 (ref.func $r1)))
)
)
(assert_suspension (invoke "unhandled-1") "unhandled")
(assert_suspension (invoke "unhandled-2") "unhandled")
(assert_suspension (invoke "unhandled-3") "unhandled")
(assert_return (invoke "handled"))
(assert_exception (invoke "uncaught-1"))
;; TODO: resume_throw (assert_exception (invoke "uncaught-2"))
;; TODO: resume_throw (assert_exception (invoke "uncaught-3"))
(assert_trap (invoke "non-linear-1") "continuation already consumed")
(assert_trap (invoke "non-linear-2") "continuation already consumed")
(assert_trap (invoke "non-linear-3") "continuation already consumed")
;; TODO: cont.bind (assert_trap (invoke "non-linear-4") "continuation already consumed")
(assert_invalid
(module
(type $ft (func))
(func
(cont.new $ft (ref.null $ft))
(drop)))
"non-continuation type 0")
(assert_invalid
(module
(type $ft (func))
(type $ct (cont $ft))
(func
(resume $ft (ref.null $ct))
(unreachable)))
"non-continuation type 0")
(assert_invalid
(module
(type $ft (func))
(type $ct (cont $ft))
(tag $exn)
(func
(resume_throw $ft $exn (ref.null $ct))
(unreachable)))
"non-continuation type 0")
(assert_invalid
(module
(type $ft (func))
(type $ct (cont $ft))
(func
(cont.bind $ft $ct (ref.null $ct))
(unreachable)))
"non-continuation type 0")
(assert_invalid
(module
(type $ft (func))
(type $ct (cont $ft))
(func
(cont.bind $ct $ft (ref.null $ct))
(unreachable)))
"non-continuation type 0")
(assert_invalid
(module
(type $ft (func))
(type $ct (cont $ft))
(tag $foo)
(func
(block $on_foo (result (ref $ft))
(resume $ct (on $foo $on_foo) (ref.null $ct))
(unreachable)
)
(drop)))
"non-continuation type 0")
(assert_invalid
(module
(type $ft (func))
(type $ct (cont $ft))
(tag $foo)
(func
(block $on_foo (result (ref $ct) (ref $ft))
(resume $ct (on $foo $on_foo) (ref.null $ct))
(unreachable)
)
(drop)
(drop)))
"non-continuation type 0")
(assert_invalid
(module
(type $ct (cont $ct)))
"non-function type 0")
(assert_invalid
(module
(rec
(type $s0 (struct (field (ref 0) (ref 1) (ref $s0) (ref $s1))))
(type $s1 (struct (field (ref 0) (ref 1) (ref $s0) (ref $s1))))
)
(type $ct (cont $s0)))
"non-function type 0")
(module
(rec
(type $f1 (func (param (ref $f2))))
(type $f2 (func (param (ref $f1))))
)
(type $c1 (cont $f1))
(type $c2 (cont $f2))
)
;; Simple state example
(module $state
(tag $get (result i32))
(tag $set (param i32) (result i32))
(type $f (func (param i32) (result i32)))
(type $k (cont $f))
(func $runner (param $s i32) (param $k (ref $k)) (result i32)
(loop $loop
(block $on_get (result (ref $k))
(block $on_set (result i32 (ref $k))
(resume $k (on $get $on_get) (on $set $on_set)
(local.get $s) (local.get $k)
)
(return)
)
;; on set
(local.set $k)
(local.set $s)
(br $loop)
)
;; on get
(local.set $k)
(br $loop)
)
(unreachable)
)
(func $f (param i32) (result i32)
(drop (suspend $set (i32.const 7)))
(i32.add
(suspend $get)
(i32.mul
(i32.const 2)
(i32.add
(suspend $set (i32.const 3))
(suspend $get)
)
)
)
)
(elem declare func $f)
(func (export "run") (result i32)
(call $runner (i32.const 0) (cont.new $k (ref.func $f)))
)
)
(assert_return (invoke "run") (i32.const 19))