eb25ced1078d8578b6ea9467c4b344d360727961
1 /* This program is free software: you can redistribute it and/or modify
2 it under the terms of the GNU General Public License as published by
3 the Free Software Foundation, either version 3 of the License, or
4 (at your option) any later version.
6 This program is distributed in the hope that it will be useful,
7 but WITHOUT ANY WARRANTY; without even the implied warranty of
8 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 GNU General Public License for more details.
11 You should have received a copy of the GNU General Public License
12 along with this program. If not, see <http://www.gnu.org/licenses/>. */
14 const initialize = Promise.all([
15 fetch('forth.forth', {credentials: 'include', headers:{'content-type':'text/plain'}}).then((re) => re.text()),
16 fetch('forth.wasm', {credentials: 'include', headers:{'content-type':'application/wasm'}}).then(re => re.arrayBuffer())
18 window.onload = () => {
22 let forthdiv = document.getElementById("forth")
23 if (forthdiv === null) {
24 forthdiv = document.createElement("div")
25 forthdiv.setAttribute("style","height:100%;margin:auto;width:100%;overflow-x:hidden;")
26 document.body.appendChild(forthdiv)
28 const outframe = document.createElement("div")
29 outframe.setAttribute("style", "background-color:black;padding-left:6px;padding-right:6px;color:chartreuse;height:256px;resize:vertical;display:flex;align-items:flex-end;flex-flow:row")
30 const stackview = document.createElement("pre")
31 stackview.setAttribute("style", "white-space:pre-wrap;flex:0 0 8%;")
32 outframe.appendChild(stackview)
33 const txtoutput = document.createElement("pre")
34 txtoutput.setAttribute("style", "white-space:pre-wrap;overflow-y:scroll;flex:1 0 342px;")
35 outframe.appendChild(txtoutput)
36 const rstackview = document.createElement("pre")
37 rstackview.setAttribute("style", "white-space:pre-wrap;flex:0 1 8%;")
38 outframe.appendChild(rstackview)
39 const memview = document.createElement("pre")
40 memview.setAttribute("style", "white-space:pre-wrap;flex:0 0 8%;")
41 outframe.appendChild(memview)
42 const txtinput = document.createElement("textarea")
43 txtinput.setAttribute("autofocus", "true")
44 txtinput.setAttribute("wrap", "hard")
45 txtinput.setAttribute("style", "resize:none;white-space:pre;margin-left:8%;width:60%;")
46 txtinput.oninput = () => txtinput.rows = (txtinput.value.match(/[\n]/g) || [1]).length + 1;
48 forthdiv.appendChild(outframe)
49 forthdiv.appendChild(txtinput)
53 print: (string) => txtoutput.textContent += `\\\ => ${string} \n`
55 const updateViews = () => {
56 stackview.textContent = simstack.join('\n')
57 rstackview.textContent = rstack.join('\n')
60 let here = new DataView(wasmMem.buffer, 14340 /* here */, 4).getUint32(0,true)
61 memview
.textContent
= Array
.from(new Uint8Array(wasmMem
.buffer
, here
- maxBytes
, maxBytes
), (v
) => {
63 v
= ('0' + (v
& 0xFF).toString(16)).slice(-2)
70 outframe
.scrollTop
= outframe
.scrollHeight
74 txtinput
.addEventListener('keydown', (event
) => {
78 const endPos
= txtinput
.selectionStart
+ 1
80 txtinput
.value
.substring(0, txtinput
.selectionStart
) +
82 txtinput
.value
.substring(txtinput
.selectionEnd
, txtinput
.value
.length
)
83 txtinput
.setSelectionRange(endPos
, endPos
)
87 stdin
+= txtinput
.value
88 txtoutput
.textContent
+= txtinput
.value
89 if (!/\s/.test(txtinput
.value
.slice(-1)))
90 txtoutput
.textContent
+= " "
92 event
.preventDefault()
93 event
.stopPropagation()
105 read
: (writeAddr
, maxBytes
) => {
106 const maxChars
= maxBytes
>> 1
107 const bufView
= new Uint16Array(wasmMem
.buffer
, writeAddr
, maxChars
)
109 for (i
= 0; i
< maxChars
&& i
< stdin
.length
; i
++)
110 bufView
[i
] = stdin
.charCodeAt(i
)
111 stdin
= stdin
.substring(maxChars
)
114 write
: (readAddr
, maxBytes
) =>
115 output
.print(String
.fromCharCode
.apply(
117 new Uint16Array(wasmMem
.buffer
, readAddr
, maxBytes
>> 1)
164 'EXECUTE-MODE': 16680,
170 pop
: () => simstack
.pop(),
171 push
: (val
) => simstack
.push(val
),
172 rinit
: () => rstack
.length
= 0,
173 rpop
: () => rstack
.pop(),
174 rpush
: (val
) => rstack
.push(val
),
175 sys_write
: (channel
, addr
, u
) => channels
[channel
] === undefined ? 0 : channels
[channel
].write(addr
, u
),
176 sys_read
: (channel
, addr
, u
) => channels
[channel
] === undefined ? 0 : channels
[channel
].read(addr
, u
),
177 sys_listen
: (reqAddr
, cbAddr
) => {
178 //TODO: call into the module to wasm fn "event" to push an event
179 //to forth, which pushes esi to the return stack and queues the
180 //callback function provided from listen. reqaddr could be
181 //"fetch", in which case no channel is used. otherwise very
182 //similar to sys_fetch.
184 sys_fetch
: (channel
, reqAddr
) => {
185 //TODO: map to fetch promise, write to channel buffer,
186 //javascript "fetch" as fallback, explicit handles for
187 //"textEntry" or any third party protocols like activitypub
188 console
.log(`fetch ${channel} ${reqAddr}`)
190 sys_echo
: (val
) => output
.print(`${val} `),
191 sys_echochar
: (val
) => output
.print(String
.fromCharCode(val
)),
192 sys_reflect
: (addr
) => {
193 console
.log(`reflect: ${addr}: ${
194 new DataView(wasmMem.buffer, addr, 4)
198 vocab_get
: (addr
, u
) => {
199 const word
= String
.fromCharCode
.apply(
201 new Uint16Array(wasmMem
.buffer
, addr
, u
>> 1)
203 const answer
= dictionary
[word
.toUpperCase()]
204 if (answer
=== undefined)
208 vocab_set
: (addr
, u
, num
) => {
209 const word
= String
.fromCharCode
.apply(
211 new Uint16Array(wasmMem
.buffer
, addr
, u
>> 1)
213 dictionary
[word
.toUpperCase()] = num
216 is_whitespace
: (key
) => /\s/.test(String
.fromCharCode(key
)),
217 sys_stack
: () => console
.log(`[${simstack}]`),
218 sys_parsenum
: (addr
, u
, base
) => {
219 const word
= String
.fromCharCode
.apply(
221 new Uint16Array(wasmMem
.buffer
, addr
, u
>> 1)
223 const answer
= Number
.parseInt(word
, base
)
224 if (Number
.isNaN(answer
))
226 new DataView(wasmMem
.buffer
, addr
, 4).setUint32(0,answer
,true)
230 output
.print(Object
.getOwnPropertyNames(dictionary
).toString().split(',').join(' '))
234 initialize
.then((results
) => {
236 WebAssembly
.instantiate(results
[1], wasmImport
).then((module
) => {
237 wasmMem
= module
.instance
.exports
.memory
238 forth
= module
.instance
.exports
.main
239 console
.log('wasm loaded')