Skip to content

Instantly share code, notes, and snippets.

@brecert
Created February 27, 2022 21:29
Show Gist options
  • Save brecert/701f4371baf00ae7de7d44bd371b7fe8 to your computer and use it in GitHub Desktop.
Save brecert/701f4371baf00ae7de7d44bd371b7fe8 to your computer and use it in GitHub Desktop.
(module
;; Import the required fd_write WASI function which will write the given io vectors to stdout
;; The function signature for fd_write is:
;; (File Descriptor, *iovs, iovs_len, nwritten) -> Returns number of bytes written
(import "wasi_unstable" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))
(import "wasi_unstable" "fd_read" (func $fd_read (param i32 i32 i32 i32) (result i32)))
(memory 1)
(export "memory" (memory 0))
;; create new io vector within linear memory
(data (i32.const 0) "\18\00\00\00") ;; iovec.buf - pointer to the prompt string
(data (i32.const 4) "\03\00\00\00") ;; iovec.buf_len -
;; valid-list
(data (i32.const 8) "\1c\00\00\00")
(data (i32.const 12) "\03\00\00\00")
(data (i32.const 16) "\20\00\00\00")
(data (i32.const 20) "\03\00\00\00")
(data (i32.const 24) "foo")
(data (i32.const 28) "bar")
(data (i32.const 32) "bar")
;; create new cio vector within linear memory
(data (i32.const 36) "\78\00\00\00") ;; ciovec.buf - pointer to the input string
(data (i32.const 40) "\0b\00\00\00") ;; ciovec.buf_len - max length of 255
;; comma
(data (i32.const 44) "\34\00\00\00")
(data (i32.const 48) "\02\00\00\00")
(data (i32.const 52) ", ")
;; braces
(data (i32.const 56) "\48\00\00\00")
(data (i32.const 60) "\01\00\00\00")
(data (i32.const 64) "\49\00\00\00")
(data (i32.const 68) "\03\00\00\00")
(data (i32.const 72) "(")
(data (i32.const 73) "): ")
;; invalid answer
(data (i32.const 78) "\5e\00\00\00")
(data (i32.const 82) "\01\00\00\00")
(data (i32.const 86) "\5f\00\00\00")
(data (i32.const 90) "\17\00\00\00")
(data (i32.const 94) "\"")
(data (i32.const 95) "\" is not a valid answer")
;; input string buffer
(data (i32.const 120) " bree \r\n")
(func $pointer.load8_u (export "mem_char_at") (param $ptr i32) (param $offset i32) (result i32)
(
i32.load8_u
(i32.add
(i32.load (local.get $ptr))
(local.get $offset)
)
)
)
(func $iovec.buf_len (export "buf_len") (param $iov i32) (result i32)
(i32.load offset=4 (local.get $iov))
)
(func $iovec.eq (param $iov1 i32) (param $iov2 i32) (result i32)
(local $idx i32)
(local $size i32)
(local.set $idx (i32.const 0))
(local.set $size (call $iovec.buf_len (local.get $iov1)))
(if (i32.ne (local.get $size) (call $iovec.buf_len (local.get $iov2)))
(return (i32.const 0))
)
(loop $loop
(if (i32.ne (call $pointer.load8_u (local.get $iov1) (local.get $idx)) (call $pointer.load8_u (local.get $iov2) (local.get $idx)))
(then (return (i32.const 0))))
(local.set $idx (i32.add (local.get $idx) (i32.const 1)))
(br_if $loop (i32.ne (local.get $idx) (local.get $size)))
)
(return (i32.const 1))
)
(func $char.is_whitespace (param $char i32) (result i32)
;; ' ' = 32
;; '\r' = 13
;; '\n' = 10
(return
(i32.or
(i32.eq (local.get $char) (i32.const 32))
(i32.or
(i32.eq (local.get $char) (i32.const 13))
(i32.eq (local.get $char) (i32.const 10))
)
)
)
)
;; returns slice (start-mem end-mem)
(func $iovec.trim (export "trim") (param $iov i32) (result i32 i32)
(local $start i32)
(local $end i32)
(local.set $start (i32.load (local.get $iov)))
(local.set $end (call $iovec.buf_len (local.get $iov)))
(loop $loop
(if (i32.and
(call $char.is_whitespace (call $pointer.load8_u (local.get $iov) (local.get $end)))
(i32.ne (local.get $end) (local.get $start))
)
(then
(local.set $end (i32.sub (local.get $end) (i32.const 1)))
(br $loop)
)
)
)
(loop $loop
(if (i32.and
(call $char.is_whitespace (i32.load8_u (local.get $start)) )
(i32.ne (local.get $start) (i32.add (local.get $iov (local.get $end))))
)
(then
(local.set $start (i32.add (local.get $start) (i32.const 1)))
(br $loop)
)
)
)
(return (local.get $start) (local.get $end))
)
;; -1 for nothing
;; otherwise return found item index
(func $list<iovec>.find (param $iov i32) (param $iovs i32) (param $iovs_len i32) (result i32)
(local $idx i32)
(local.set $idx (i32.const 0))
(loop $loop
(if
(call $iovec.eq
(local.get $iov)
(i32.add
(local.get $iovs)
(i32.mul (local.get $idx) (i32.const 8))
)
)
(then (return (local.get $idx)))
)
(local.set $idx (i32.add (local.get $idx) (i32.const 1)))
(br_if $loop (i32.ne (local.get $idx) (local.get $iovs_len)))
)
(return (i32.const -1))
)
(func $print (param $iovec i32)
(call $fd_write
(i32.const 1) ;; file_descriptor - 1 for stdout
(local.get $iovec) ;; *iovs - The pointer to the iov array, which is stored at memory location 0
(i32.const 1) ;; iovs_len - We're printing 1 string stored in an iov - so one.
(i32.const 512) ;; nwritten - A place in memory to store the number of bytes written
)
drop
)
(func $print_joined (param $iovs i32) (param $iovs.len i32) (param $iov_join_with i32)
(local $idx i32)
(local.set $idx (i32.const 0))
(loop $loop
(call $print (i32.add
(local.get $iovs)
(i32.mul (local.get $idx) (i32.const 8))
))
(local.set $idx (i32.add (local.get $idx) (i32.const 1)))
(if (i32.ge_u (local.get $idx) (local.get $iovs.len)) (return))
(call $print (local.get $iov_join_with))
(br $loop)
)
)
(func $print_prompt
(call $print (i32.const 0))
(call $print (i32.const 56))
(call $print_joined
(i32.const 8)
(i32.const 2)
(i32.const 44)
)
(call $print (i32.const 64))
)
(func $swap (param i32 i32) (result i32 i32) (local.get 1) (local.get 0))
(func (export "test") (result i32 i32)
(call $iovec.trim (i32.const 36))
;; not ideal, not sure how else to handle
(i32.store (i32.const 40) (call $swap))
(i32.store (i32.const 36) (call $swap))
(i32.load (i32.const 36))
(i32.load (i32.const 40))
)
(func $question (export "question") (param $prompt i32) (param $valid i32) (param $valid_len i32)
(local $ret i32)
(loop $loop
(i32.store (i32.const 36) (i32.const 120))
(i32.store (i32.const 40) (i32.const 255))
(call $print_prompt)
(local.set $ret
(call $fd_read
(i32.const 0)
(i32.const 36)
(i32.const 1)
(i32.const 40)
)
)
;; [temporary until trim implemented] remove \r\n
(i32.store (i32.const 40) (i32.sub (i32.load (i32.const 40)) (i32.const 2)))
(call $iovec.trim (i32.const 36))
;; not ideal, not sure how else to handle
(i32.store (i32.const 40) (call $swap))
(i32.store (i32.const 36) (call $swap))
(call $print (i32.const 36))
(local.set $ret (call $list<iovec>.find (i32.const 36) (local.get $valid) (local.get $valid_len)))
(if (i32.ne (local.get $ret) (i32.const -1)) (then (return (local.get $ret))))
(br $loop)
)
)
(func $main (export "_start")
(call $question (i32.const 0) (i32.const 8) (i32.const 2))
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment