You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
'use strict'
-const initialize = Promise.all([
+
+/* State */
+const output = {
+ print: (string) => {},
+ updateViews: () => {}
+}
+const channels = []
+let wasmMem, forth
+
+/* Init */
+Promise.all([
fetch('forth.forth', {credentials: 'include', headers:{'content-type':'text/plain'}}).then((re) => re.text()),
fetch('forth.wasm', {credentials: 'include', headers:{'content-type':'application/wasm'}}).then(re => re.arrayBuffer())
-])
+]).then((results) => {
+ WebAssembly.instantiate(results[1], wasmImport).then((module) => {
+ wasmMem = module.instance.exports.memory.buffer
+ forth = (chno, data) => {
+ if (typeof chno !== "number") {
+ data = chno
+ chno = 0
+ }
+ channels[chno].writeEnv(data)
+ if (chno === 0)
+ output.print(data)
+ module.instance.exports.main(chno)
+ output.updateViews()
+ }
+ console.log('wasm loaded')
+ forth(results[0])
+ })
+})
+
+/* Environment functions */
+const wasmString = (addr, u) =>
+ String.fromCharCode.apply(
+ null,
+ new Uint16Array(wasmMem, addr, u >> 1)
+ )
+const strToArrayBuffer = (str) => {
+ const buf = new ArrayBuffer(str.length << 1);
+ const bufView = new Uint16Array(buf);
+ for (let i = 0, strLen = str.length; i < strLen; i++)
+ bufView[i] = str.charCodeAt(i);
+ return buf;
+}
+const bufJoin = (buf1, buf2) => {
+ const newBuf = new Uint8Array(buf1.byteLength + buf2.byteLength)
+ newBuf.set(new Uint8Array(buf1), 0)
+ newBuf.set(new Uint8Array(buf2), buf1.byteLength)
+ return newBuf.buffer
+}
+
+/* I/O Channel Drivers */
+class Channel {
+ constructor(opt) {
+ opt.chno = channels.indexOf(undefined)
+ if (opt.chno === -1)
+ opt.chno = channels.length
+ Object.assign(this, opt)
+ if (this.buffer === undefined)
+ this.buffer = new ArrayBuffer(0)
+ channels[this.chno] = this
+ return this
+ }
+ read(writeAddr, maxBytes) {
+ const wasmView = new Uint8Array(wasmMem, writeAddr, maxBytes)
+ const bufBytes = Math.min(maxBytes, this.buffer.byteLength)
+ const bufView = new Uint8Array(this.buffer, 0, bufBytes)
+ wasmView.set(bufView, 0)
+ this.buffer = this.buffer.slice(bufBytes)
+ return bufBytes
+ }
+ write(readAddr, maxBytes) {
+ const newBuf = new Uint8Array(this.buffer.byteLength + maxBytes)
+ newBuf.set(new Uint8Array(this.buffer), 0)
+ newBuf.set(new Uint8Array(wasmMem, readAddr, maxBytes), this.buffer.byteLength)
+ this.buffer = newBuf
+ }
+ writeEnv(data) {
+ switch (typeof data) {
+ case "string":
+ this.buffer = bufJoin(this.buffer, strToArrayBuffer(data))
+ break
+ case "object" :
+ if (data instanceof ArrayBuffer)
+ this.buffer = bufJoin(this.buffer, data)
+ else
+ this.buffer = bufJoin(this.buffer, strToArrayBuffer(JSON.stringify(data)))
+ break
+ case "number" :
+ const buf = new ArrayBuffer(4)
+ new DataView(buf, 0, 4).setInt32(data)
+ this.buffer = bufJoin(this.buffer, buf)
+ break
+ default :
+ console.error(`environment wrote unhandled object: ${data}`)
+ return
+ }
+ }
+}
+/* 0 STDIN, 1 STDOUT, 2 STDERR */
+new Channel({
+ write(readAddr, maxBytes) {
+ super.write(readAddr, maxBytes)
+ output.print(wasmString(readAddr, maxBytes))
+ }
+})
+new Channel({
+ read(writeAddr, maxBytes) { return 0 },
+ write(readAddr, maxBytes) { output.print(`\\\ => ${wasmString(readAddr, maxBytes)}\n`) }
+})
+new Channel({
+ read(writeAddr, maxBytes) { return 0 },
+ write(readAddr, maxBytes) { console.error(wasmString(readAddr, maxBytes)) }
+})
+
+/* System runtime */
+const simstack = []
+const rstack = []
+const dictionary = { EXECUTE: 12 }
+const doesDictionary = {}
+const wasmImport = {
+ env: {
+ pop: () => simstack.pop(),
+ push: (val) => simstack.push(val),
+ rinit: () => rstack.length = 0,
+ rpop: () => rstack.length ? rstack.pop() : 16388,
+ rpush: (val) => rstack.push(val),
+ sys_write: (chno, addr, u) => channels[chno] === undefined ? 0 : channels[chno].write(addr, u),
+ sys_read: (chno, addr, u) => channels[chno] === undefined ? 0 : channels[chno].read(addr, u),
+ sys_listen: (chno, cbAddr, addr, u) => { //sys_connect?
+ //TODO: call into the module to wasm fn "event" to push an event
+ //to forth, which pushes esi to the return stack and queues the
+ //callback function provided from listen. reqaddr could be
+ //"fetch", in which case no channel is used. otherwise very
+ //similar to sys_fetch.
+
+ //callbacks are events, like listen events
+ //totally event-driven, one listener per event
+ //other listen types: mouse, keyboard, touch, main_loop (10ms interval), wrtc, etc
+ //fetch is different because it offers no "write" interface, doesn't repeat
+ },
+ sys_fetch: (cbAddr, addr, u) => {
+ const str = wasmString(addr, u)
+ console.log(`fetching: ${str}`)
+ const args = JSON.parse(wasmString(addr, u))
+ console.log(args)
+ const url = args.url
+ delete args.url
+ const channel = new Channel()
+ fetch(url, args).then((re) => {
+ if (args.headers === undefined ||
+ args.headers['content-type'] === undefined ||
+ args.headers['content-type'].toLowerCase().indexOf('text/plain') === 0 )
+ re.text().then((txt) => forth(channel.chno, txt))
+ else {
+ const reader = new FileReader()
+ reader.onload = (evt) => forth(channel.chno, evt.target.result)
+ re.blob().then((blob) => reader.readAsArrayBuffer(blob))
+ }
+ }).catch(console.error)
+ //TODO: map to fetch promise, write to channel buffer,
+ //javascript "fetch" as fallback, explicit handles for
+ //"textEntry" or any third party protocols like activitypub
+ return channel.chno
+ },
+ sys_close: (chno) => delete channels[chno],
+ sys_echo: (val, base) => output.print(`\\\ => ${val.toString(base)} `),
+ sys_echochar: (val) => output.print(String.fromCharCode(val)),
+ sys_reflect: (addr) => {
+ console.log(`reflect: ${addr}: ${
+ new DataView(wasmMem, addr, 4)
+ .getUint32(0,true)
+ }`)
+ },
+ vocab_get: (addr, u) => dictionary[wasmString(addr, u).toUpperCase()] || 0,
+ vocab_set: (addr, u, v) => dictionary[wasmString(addr, u).toUpperCase()] = v,
+ does_get: (addr, u) => doesDictionary[wasmString(addr, u).toUpperCase()] || 0,
+ does_set: (addr, u, v) => doesDictionary[wasmString(addr, u).toUpperCase()] = v,
+ is_whitespace: (key) => /\s/.test(String.fromCharCode(key)),
+ sys_stack: () => console.log(`[${simstack}][${rstack}]`),
+ sys_parsenum: (addr, u, base) => {
+ const answer = Number.parseInt(wasmString(addr, u), base)
+ if (Number.isNaN(answer))
+ return -1
+ new DataView(wasmMem, addr, 4).setUint32(0,answer,true)
+ return 0
+ },
+ sys_words: () => {
+ output.print(Object.getOwnPropertyNames(dictionary).toString().split(',').join(' '))
+ }
+ }
+}
+
+/* View Logic */
window.onload = () => {
- /* Initialize Views */
let forthdiv = document.getElementById("forth")
if (forthdiv === null) {
forthdiv = document.createElement("div")
const outframe = document.createElement("div")
outframe.setAttribute("style", "background-color:black;padding-left:6px;padding-right:6px;color:chartreuse;height:268px;resize:vertical;display:flex;align-items:flex-end;flex-flow:row;")
const stackview = document.createElement("pre")
- stackview.setAttribute("style", "white-space:pre-wrap;flex:0 0 8%;")
+ stackview.setAttribute("style", "white-space:pre-wrap;flex:0 0 6%;")
outframe.appendChild(stackview)
const txtoutput = document.createElement("pre")
txtoutput.setAttribute("style", "white-space:pre-wrap;max-height:256px;overflow-y:scroll;flex:1 0 342px;")
const txtinput = document.createElement("textarea")
txtinput.setAttribute("autofocus", "true")
txtinput.setAttribute("wrap", "hard")
- txtinput.setAttribute("style", "resize:none;white-space:pre;margin-left:8%;width:75%;")
+ txtinput.setAttribute("style", "resize:none;white-space:pre;margin-left:6%;width:77%;")
txtinput.oninput = () => txtinput.setAttribute("rows", ((txtinput.value.match(/[\n]/g) || [1]).length + 1).toString());
txtinput.oninput()
- forthdiv.appendChild(outframe)
- forthdiv.appendChild(txtinput)
-
- /* Initialize State */
- const simstack = []
- const rstack = []
- let wasmMem
- let forth
- const dictionary = { EXECUTE: 12 }
- const doesDictionary = {}
-
- /* Environment functions */
- const output = {
- print: (string) => txtoutput.textContent += `\\\ => ${string} \n`
- }
- const wasmString = (addr, u) =>
- String.fromCharCode.apply(
- null,
- new Uint16Array(wasmMem.buffer, addr, u >> 1)
- )
- const updateViews = () => {
- const base = new DataView(wasmMem.buffer, 14348 /* base */, 4).getUint32(0,true)
- stackview.textContent = simstack.map((v) => v.toString(base)).join('\n')
- // rstackview.textContent = rstack.join('\n')
- let cnt = 0;
- const maxBytes = 64
- let here = new DataView(wasmMem.buffer, 14340 /* here */, 4).getUint32(0,true)
- memview.textContent = Array.from(new Uint8Array(wasmMem.buffer, here - maxBytes, maxBytes), (v) => {
- cnt++;
- v = ('0' + (v & 0xFF).toString(16)).slice(-2)
- if (cnt === maxBytes)
- return v
- if ((cnt % 16) === 0)
- return `${v}\n=> ${(here -maxBytes + cnt).toString(base)}\n`
- if ((cnt % 4) === 0)
- return `${v}\n`
- return `${v} `
- }).join('')
- outframe.scrollTop = outframe.scrollHeight
- }
-
- /* Input capture */
- let stdin = ""
- txtinput.addEventListener('keydown', (event) => {
+ txtinput.onkeydown = (event) => {
switch (event.key) {
case "Enter":
if (event.ctrlKey) {
txtinput.oninput()
}
else {
- stdin += txtinput.value
- txtoutput.textContent += txtinput.value
if (!/\s/.test(txtinput.value.slice(-1)))
- txtoutput.textContent += " "
- txtinput.value = ""
+ txtinput.value += " "
event.preventDefault()
event.stopPropagation()
- forth()
- updateViews()
- txtoutput.scrollTop = txtoutput.scrollHeight
+ forth(txtinput.value)
+ txtinput.value = ""
}
break
case "Backspace":
default:
break
}
- })
- const channels = [{
- read: (writeAddr, maxBytes) => {
- const maxChars = maxBytes >> 1
- const bufView = new Uint16Array(wasmMem.buffer, writeAddr, maxChars)
- let i
- for (i = 0; i < maxChars && i < stdin.length; i++)
- bufView[i] = stdin.charCodeAt(i)
- stdin = stdin.substring(maxChars)
- return i << 1
- },
- write: (readAddr, maxBytes) =>
- output.print(String.fromCharCode.apply(
- null,
- new Uint16Array(wasmMem.buffer, readAddr, maxBytes >> 1)
- ))
- }]
-
- /* System runtime */
- const wasmImport = {
- env: {
- pop: () => simstack.pop(),
- push: (val) => simstack.push(val),
- rinit: () => rstack.length = 0,
- rpop: () => rstack.pop(),
- rpush: (val) => rstack.push(val),
- sys_write: (channel, addr, u) => channels[channel] === undefined ? 0 : channels[channel].write(addr, u),
- sys_read: (channel, addr, u) => channels[channel] === undefined ? 0 : channels[channel].read(addr, u),
- sys_listen: (reqAddr, cbAddr) => {
- //TODO: call into the module to wasm fn "event" to push an event
- //to forth, which pushes esi to the return stack and queues the
- //callback function provided from listen. reqaddr could be
- //"fetch", in which case no channel is used. otherwise very
- //similar to sys_fetch.
- },
- sys_fetch: (channel, reqAddr) => {
- //TODO: map to fetch promise, write to channel buffer,
- //javascript "fetch" as fallback, explicit handles for
- //"textEntry" or any third party protocols like activitypub
- console.log(`fetch ${channel} ${reqAddr}`)
- },
- sys_echo: (val, base) => output.print(`${val.toString(base)} `),
- sys_echochar: (val) => output.print(String.fromCharCode(val)),
- sys_reflect: (addr) => {
- console.log(`reflect: ${addr}: ${
- new DataView(wasmMem.buffer, addr, 4)
- .getUint32(0,true)
- }`)
- },
- vocab_get: (addr, u) => dictionary[wasmString(addr, u).toUpperCase()] || 0,
- vocab_set: (addr, u, v) => dictionary[wasmString(addr, u).toUpperCase()] = v,
- does_get: (addr, u) => doesDictionary[wasmString(addr, u).toUpperCase()] || 0,
- does_set: (addr, u, v) => doesDictionary[wasmString(addr, u).toUpperCase()] = v,
- is_whitespace: (key) => /\s/.test(String.fromCharCode(key)),
- sys_stack: () => console.log(`[${simstack}][${rstack}]`),
- sys_parsenum: (addr, u, base) => {
- const answer = Number.parseInt(wasmString(addr, u), base)
- if (Number.isNaN(answer))
- return -1
- new DataView(wasmMem.buffer, addr, 4).setUint32(0,answer,true)
- return 0
- },
- sys_words: () => {
- output.print(Object.getOwnPropertyNames(dictionary).toString().split(',').join(' '))
- }
- }
}
- initialize.then((results) => {
- stdin = results[0]
- WebAssembly.instantiate(results[1], wasmImport).then((module) => {
- wasmMem = module.instance.exports.memory
- forth = module.instance.exports.main
- console.log('wasm loaded')
- forth()
- updateViews()
- })
- })
+ forthdiv.appendChild(outframe)
+ forthdiv.appendChild(txtinput)
+ /* Set up output functions */
+ output.print = (string) => txtoutput.textContent += string,
+ output.updateViews = () => {
+ const base = new DataView(wasmMem, 14348 /* base */, 4).getUint32(0,true)
+ stackview.textContent = simstack.map((v) => v.toString(base)).join('\n')
+ // rstackview.textContent = rstack.join('\n')
+ let cnt = 0;
+ const maxBytes = 64
+ let here = new DataView(wasmMem, 14340 /* here */, 4).getUint32(0,true)
+ memview.textContent = Array.from(new Uint8Array(wasmMem, here - maxBytes, maxBytes), (v) => {
+ cnt++;
+ v = ('0' + (v & 0xFF).toString(16)).slice(-2)
+ if (cnt === maxBytes)
+ return v
+ if ((cnt % 16) === 0)
+ return `${v}\n=> ${(here -maxBytes + cnt).toString(base)}\n`
+ if ((cnt % 4) === 0)
+ return `${v}\n`
+ return `${v} `
+ }).join('')
+ outframe.scrollTop = outframe.scrollHeight
+ txtoutput.scrollTop = txtoutput.scrollHeight
+ }
}
(import "env" "rpop" (func $rpop (result i32)))
(import "env" "rpush" (func $rpush (param i32)))
(import "env" "sys_read" (func $sys_read (param i32 i32 i32) (result i32)))
- (import "env" "sys_fetch" (func $sys_fetch (param i32 i32) (result i32)))
- (import "env" "sys_listen" (func $sys_listen (param i32) (result i32)))
+ (import "env" "sys_fetch" (func $sys_fetch (param i32 i32 i32) (result i32)))
+ (import "env" "sys_listen" (func $sys_listen (param i32 i32 i32) (result i32)))
(import "env" "sys_write" (func $sys_write (param i32 i32 i32) (result i32)))
(import "env" "sys_echo" (func $sys_echo (param i32 i32)))
(import "env" "sys_echochar" (func $sys_echochar (param i32)))
(global $inbuf_data i32 (i32.const 12296))
(global $kvars i32 (i32.const 14336)) ;; 0x3800 Size: 2048
(data (i32.const 12288) "\f8\07\00\00") ;; 2040 len
+ (global $mode_p i32 (i32.const 14336))
+ (global $here_p i32 (i32.const 14340))
+ (global $start_p i32 (i32.const 14344))
+ (global $base_p i32 (i32.const 14348))
+ (global $stringbelt_tail_p i32 (i32.const 14352))
+ (global $stringbelt_head_p i32 (i32.const 14356))
+ (global $wordbelt_tail_p i32 (i32.const 14360))
+ (global $wordbelt_head_p i32 (i32.const 14364))
+ (global $channel_in_p i32 (i32.const 14368))
+ (global $channel_out_p i32 (i32.const 14372))
(data (i32.const 14336) "\28\41\00\00") ;; MODE
(data (i32.const 14340) "\04\42\00\00") ;; HERE
(data (i32.const 14344) "\00\40\00\00") ;; START (16384) (Quit)
(data (i32.const 14356) "\00\00\00\00") ;; STRINGBELT_HEAD
(data (i32.const 14360) "\00\20\00\00") ;; WORDBELT_TAIL
(data (i32.const 14364) "\00\20\00\00") ;; WORDBELT_HEAD
- (data (i32.const 14368) "\00\00\00\00") ;; CHANNEL
+ (data (i32.const 14368) "\00\00\00\00") ;; CHANNEL-IN
+ (data (i32.const 14372) "\01\00\00\00") ;; CHANNEL-OUT
+ (; channel listeners 0x3c00 ;)
+ (global $channel_listeners_p i32 (i32.const 15360))
+ (data (i32.const 15360) "\00\40\00\00") ;; CHANNEL LISTENER 0 (quit)
(; Quit ;)
- (data (i32.const 16384) "\03\00\00\00") ;; RINIT xt
+ (global $quit_p i32 (i32.const 16384))
+ (data (i32.const 16384) "\01\00\00\00") ;; RINIT xt
+ (global $quit_ret_p i32 (i32.const 16388))
(data (i32.const 16388) "\10\40\00\00") ;; INTERPRET xt
(data (i32.const 16392) "\12\00\00\00") ;; JMP xt
(data (i32.const 16396) "\00\40\00\00") ;; quit location (16384)
(export "memory" (memory $0))
(export "main" (func $main))
- (func $main (result i32)
+ (func $main (param $event_channel i32) (result i32)
+ block $use_current_channel
+ (; rstack contains channel barriers (numbers lower than 256)
+ which will reset channel to 0 when returning to the quit loop.
+ if an interrupt event is happening, load its handler and set
+ the input channel. ;)
+ get_local $event_channel
+ i32.eqz
+ br_if $use_current_channel
+ get_local $event_channel
+ i32.const 255
+ i32.gt_u
+ br_if $use_current_channel
+ get_global $channel_in_p
+ get_local $event_channel
+ i32.store
+ end
+ get_global $channel_listeners_p
+ get_local $event_channel
+ i32.const 2
+ i32.shl
+ i32.add
+ i32.load
call $interpret
)
- (func $interpret (result i32)
+ (func $interpret (param $esi i32) (result i32)
(local $here i32)
(local $eax i32)
- (local $esi i32)
(local $inbuf_head i32)
(local $stringbelt_tail i32)
(local $stringbelt_head i32)
(local $wordbelt_tail i32)
(local $wordbelt_head i32)
- (local $channel i32)
- i32.const 14340
+ (local $channel_in i32)
+ (local $channel_out i32)
+ get_global $here_p
i32.load
set_local $here
- (; Load "start" into esi, then restore "start" to "quit" ;)
- i32.const 14344
- i32.load
- set_local $esi
- i32.const 14344
- i32.const 16384
- i32.store
- (; "start" will be a normal quit, unless cirumvented in this run ;)
get_global $inbuf_data
set_local $inbuf_head
- i32.const 14352
+ get_global $stringbelt_tail_p
i32.load
set_local $stringbelt_tail
- i32.const 14356
+ get_global $stringbelt_head_p
i32.load
set_local $stringbelt_head
- i32.const 14360
+ get_global $wordbelt_tail_p
i32.load
set_local $wordbelt_tail
- i32.const 14364
+ get_global $wordbelt_head_p
i32.load
set_local $wordbelt_head
- i32.const 14368
+ get_global $channel_in_p
i32.load
- set_local $channel
+ set_local $channel_in
+ get_global $channel_out_p
+ i32.load
+ set_local $channel_out
+ get_global $quit_p
+ set_local $esi
block $bye
loop $next
get_local $esi
block $drop block $wsbool block $jmp block $wordputc block $wordstart
block $dictget block $parsenum block $wordfinish block $jneg1 block $swap
block $words block $here block $dictset block $dup2 block $rot block $drop2
- block $comma block $subtract block $keychan block $sethere block $eqbool
+ block $comma block $subtract block $inchan block $sethere block $eqbool
block $echostring block $strstart block $strput block $strend block $fetchinc
- block $setinc block $finddoes block $definedoes block $stacktrace
+ block $setinc block $finddoes block $definedoes block $stacktrace block $webfetch
+ block $outchan block $read
get_local $eax
br_table $op0 $ret (;2;)$lit $rinit (;4;)$word $key (;6;)$dup $plus
(;8;)$jmp $emit (;10;)$fetch $set (;12;)$execute $noop (;14;)$jz $jnz
(;16;)$drop $wsbool (;18;)$jmp $wordputc (;20;)$wordstart $dictget
(;22;)$parsenum $wordfinish (;24;)$jneg1 $bye (;26;)$swap $words
(;28;)$here $dictset (;30;)$dup2 $rot (;32;)$drop2 $comma
- (;34;)$subtract $keychan (;36;)$sethere $eqbool (;38;)$echostring $strstart
+ (;34;)$subtract $inchan (;36;)$sethere $eqbool (;38;)$echostring $strstart
(;40;)$strput $strend (;42;)$fetchinc $setinc (;44;)$finddoes $definedoes
- (;46;)$stacktrace $default
+ (;46;)$stacktrace $webfetch (;48;)$outchan $read (;50;)$default
+ end ;; read
+ get_local $channel_in
+ call $pop ;; location to write
+ set_local $eax
+ call $pop
+ get_local $eax
+ call $sys_read
+ br $next
+ end ;; outchan
+ call $pop
+ set_local $channel_out
+ br $next
+ end ;; webfetch
+ call $pop
+ call $rpush
+ call $pop
+ set_local $eax
+ call $pop
+ get_local $eax
+ call $rpop
+ call $sys_fetch
+ br $next
end ;; stacktrace
call $sys_stack
get_local $esi
set_local $stringbelt_head
br $next
end ;; echostring
- get_local $channel
+ get_local $channel_out
call $pop
set_local $eax
call $pop
call $pop
set_local $here
br $next
- end ;; keychan
+ end ;; inchan
call $pop
- set_local $channel
+ set_local $channel_in
br $next
end ;; subtract
call $pop
call $pop
tee_local $eax
call $rpop
- i32.const 14348 (; load BASE ;)
+ get_global $base_p
i32.load
call $sys_parsenum
get_local $eax
br $next
end ;; emit (.)
call $pop
- i32.const 14348
+ get_global $base_p
i32.load
call $sys_echo
br $next
br $next
end ;; key_read
get_global $inbuf_size
- get_local $channel
+ i32.const 0 (; stdin hardcode ;)
get_global $inbuf_data
get_global $inbuf
i32.load
end ;; word
br $next
end ;; rinit
+ call $rpop
+
call $rinit
+ i32.const 0
+ set_local $channel_in
br $next
end ;; lit
get_local $esi
call $push
br $next
end ;; ret
- call $rpop
+ block $gotonext
+ (; cannot jump lower than 256 because it is reserved for
+ opcodes, so overload popping that kind of retval with
+ a channel selector, for when an event handler yields and
+ is interrupted by another event handler. there are also
+ a max of 255 channels, which is the same as the opcode space ;)
+ call $rpop
+ tee_local $eax
+ i32.const 255
+ i32.gt_u
+ br_if $gotonext
+ get_local $eax
+ set_local $channel_in
+ call $rpop
+ set_local $eax
+ end ;; gotonext
+ get_local $eax
set_local $esi
br $next
end ;; op0
end ;; execloop
end ;; next loop
end ;; bye
- i32.const 14340
+ get_global $here_p
get_local $here
i32.store
- i32.const 14352
+ get_global $stringbelt_tail_p
get_local $stringbelt_tail
i32.store
- i32.const 14356
+ get_global $stringbelt_head_p
get_local $stringbelt_head
i32.store
- i32.const 14360
+ get_global $wordbelt_tail_p
get_local $wordbelt_tail
i32.store
- i32.const 14364
+ get_global $wordbelt_head_p
get_local $wordbelt_head
i32.store
- i32.const 14368
- get_local $channel
+ get_global $channel_in_p
+ get_local $channel_in
+ i32.store
+ get_global $channel_out_p
+ get_local $channel_out
i32.store
i32.const 0
return