57aac39ba44d4e295354fd2c869c1a0fc9a7c65c
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)
123 const doesDictionary
= {}
126 pop
: () => simstack
.pop(),
127 push
: (val
) => simstack
.push(val
),
128 rinit
: () => rstack
.length
= 0,
129 rpop
: () => rstack
.pop(),
130 rpush
: (val
) => rstack
.push(val
),
131 sys_write
: (channel
, addr
, u
) => channels
[channel
] === undefined ? 0 : channels
[channel
].write(addr
, u
),
132 sys_read
: (channel
, addr
, u
) => channels
[channel
] === undefined ? 0 : channels
[channel
].read(addr
, u
),
133 sys_listen
: (reqAddr
, cbAddr
) => {
134 //TODO: call into the module to wasm fn "event" to push an event
135 //to forth, which pushes esi to the return stack and queues the
136 //callback function provided from listen. reqaddr could be
137 //"fetch", in which case no channel is used. otherwise very
138 //similar to sys_fetch.
140 sys_fetch
: (channel
, reqAddr
) => {
141 //TODO: map to fetch promise, write to channel buffer,
142 //javascript "fetch" as fallback, explicit handles for
143 //"textEntry" or any third party protocols like activitypub
144 console
.log(`fetch ${channel} ${reqAddr}`)
146 sys_echo
: (val
) => output
.print(`${val} `),
147 sys_echochar
: (val
) => output
.print(String
.fromCharCode(val
)),
148 sys_reflect
: (addr
) => {
149 console
.log(`reflect: ${addr}: ${
150 new DataView(wasmMem.buffer, addr, 4)
154 vocab_get
: (addr
, u
) => {
155 const word
= String
.fromCharCode
.apply(
157 new Uint16Array(wasmMem
.buffer
, addr
, u
>> 1)
159 const answer
= dictionary
[word
.toUpperCase()]
160 if (answer
=== undefined)
164 vocab_set
: (addr
, u
, num
) => {
165 const word
= String
.fromCharCode
.apply(
167 new Uint16Array(wasmMem
.buffer
, addr
, u
>> 1)
169 dictionary
[word
.toUpperCase()] = num
172 does_get
: (u
) => doesDictionary
[u
] || 0,
173 does_set
: (u
, v
) => doesDictionary
[u
] = v
,
174 is_whitespace
: (key
) => /\s/.test(String
.fromCharCode(key
)),
175 sys_stack
: () => console
.log(`[${simstack}]`),
176 sys_parsenum
: (addr
, u
, base
) => {
177 const word
= String
.fromCharCode
.apply(
179 new Uint16Array(wasmMem
.buffer
, addr
, u
>> 1)
181 const answer
= Number
.parseInt(word
, base
)
182 if (Number
.isNaN(answer
))
184 new DataView(wasmMem
.buffer
, addr
, 4).setUint32(0,answer
,true)
188 output
.print(Object
.getOwnPropertyNames(dictionary
).toString().split(',').join(' '))
192 initialize
.then((results
) => {
194 WebAssembly
.instantiate(results
[1], wasmImport
).then((module
) => {
195 wasmMem
= module
.instance
.exports
.memory
196 forth
= module
.instance
.exports
.main
197 console
.log('wasm loaded')