(module ;; import console.log. (func $print (import "guppy" "print") (param i32)) ;; declare a table with a reference to $halt in it. idk why, but this is ;; necessary to use funcrefs lmfao. (table 2 funcref) (elem (i32.const 0) $halt) ;; an array of return continuations. (type $cont (func (param i32))) (type $cont-stack-type (array (mut (ref null $cont)))) (global $cont-stack (ref $cont-stack-type) (array.new_default $cont-stack-type (i32.const 128))) (global $cont-stack-top (mut i32) (i32.const 0)) ;; a global array on which we pass arguments. (type $arg-array-type (array (mut (ref null eq)))) (global $arg-array (ref $arg-array-type) (array.new_default $arg-array-type (i32.const 32))) ;; cps'd function. takes the number of scheme arguments as the sole ;; wasm argument. arguments are read into locals from ;; $arg-array. does not return, instead popping a continuation from ;; $cont-stack and tail-calling it. (func $add (param $nargs i32) (local $x (ref eq)) (local $y (ref eq)) (local $return (ref $cont)) (local.set $x (ref.as_non_null (array.get $arg-array-type (global.get $arg-array) (i32.const 0)))) (local.set $y (ref.as_non_null (array.get $arg-array-type (global.get $arg-array) (i32.const 1)))) (array.set $arg-array-type (global.get $arg-array) (i32.const 0) (ref.i31 (i32.add (i31.get_s (ref.cast (ref i31) (local.get $x))) (i31.get_s (ref.cast (ref i31) (local.get $y)))))) (return_call_ref $cont (i32.const 1) (block (result (ref $cont)) (ref.as_non_null (array.get $cont-stack-type (global.get $cont-stack) (global.get $cont-stack-top))) (global.set $cont-stack-top (i32.sub (global.get $cont-stack-top) (i32.const 1)))))) ;; for demo purposes, this continuation calls console.log and stops. (func $halt (param $nargs i32) (call $print (i31.get_s (ref.cast (ref i31) (ref.as_non_null (array.get $arg-array-type (global.get $arg-array) (i32.const 0))))))) ;; entry point }:3 (func (export "main") ;; push args (array.set $arg-array-type (global.get $arg-array) (i32.const 0) (ref.i31 (i32.const 4))) (array.set $arg-array-type (global.get $arg-array) (i32.const 1) (ref.i31 (i32.const 5))) ;; push return continuation (array.set $cont-stack-type (global.get $cont-stack) (i32.const 0) (ref.func $halt)) ;; make call }:) (return_call $add ;; inform $add how many arguments we called it with (i32.const 2))))