X-Git-Url: https://git.kengrimes.com/?p=watForth.git;a=blobdiff_plain;f=forth.js;h=9c0e58d2dc57e8128b67b3295ebe37fbec366d6a;hp=c05d444d08215e8daf4bc804fbab3454fd29830e;hb=94d40c7e5521898acd394ca7a3e30cf20065ee5c;hpb=b9be17929d350bf4ab9c747e29ae6c1203035111 diff --git a/forth.js b/forth.js index c05d444..9c0e58d 100644 --- a/forth.js +++ b/forth.js @@ -12,33 +12,77 @@ along with this program. If not, see . */ 'use strict' const initialize = Promise.all([ - fetch('forth.forth').then((re) => re.text()), - fetch('forth.wasm').then(re => re.arrayBuffer()) + 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()) ]) window.onload = () => { + /* Initialize Views */ let forthdiv = document.getElementById("forth") if (forthdiv === null) { forthdiv = document.createElement("div") - forthdiv.setAttribute("style","height:400px;") + forthdiv.setAttribute("style","height:100%;margin:auto;width:100%;max-width:640px;overflow-x:hidden;") document.body.appendChild(forthdiv) } const outframe = document.createElement("div") - outframe.setAttribute("style", "overflow-y:hidden;height:40%;") + 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%;") + outframe.appendChild(stackview) const txtoutput = document.createElement("pre") - txtoutput.setAttribute("style", "white-space:pre-wrap;") - const txtinput = document.createElement("textarea") - let txtinputrows = "1" - txtinput.setAttribute("autofocus", "true") - txtinput.setAttribute("cols", "60") - txtinput.setAttribute("rows", txtinputrows) + txtoutput.setAttribute("style", "white-space:pre-wrap;max-height:256px;overflow-y:scroll;flex:1 0 342px;") outframe.appendChild(txtoutput) + /* const rstackview = document.createElement("pre") + rstackview.setAttribute("style", "white-space:pre-wrap;flex:0 1 8%;") + outframe.appendChild(rstackview) */ + const memview = document.createElement("pre") + memview.setAttribute("style", "padding-left: 8px; white-space:pre-wrap;flex:0 0 88px;") + outframe.appendChild(memview) + 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.oninput = () => txtinput.setAttribute("rows", ((txtinput.value.match(/[\n]/g) || [1]).length + 1).toString()); + txtinput.oninput() forthdiv.appendChild(outframe) forthdiv.appendChild(txtinput) - const output = { - print: (string) => txtoutput.textContent += string - } + + /* 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 = "" @@ -46,62 +90,33 @@ window.onload = () => { switch (event.key) { case "Enter": if (event.ctrlKey) { - txtinput.value += '\n' - txtinputrows = (Number.parseInt(txtinputrows, 10) + 1).toString() - txtinput.setAttribute("rows", txtinputrows) + const endPos = txtinput.selectionStart + 1 + txtinput.value = + txtinput.value.substring(0, txtinput.selectionStart) + + '\n' + + txtinput.value.substring(txtinput.selectionEnd, txtinput.value.length) + txtinput.setSelectionRange(endPos, endPos) + txtinput.oninput() } else { stdin += txtinput.value - txtoutput.textContent += txtinput.value + '\n' + txtoutput.textContent += txtinput.value + if (!/\s/.test(txtinput.value.slice(-1))) + txtoutput.textContent += " " txtinput.value = "" - txtinputrows = "1" - txtinput.setAttribute("rows", txtinputrows) event.preventDefault() event.stopPropagation() forth() - txtoutput.textContent += " _ok.\n" - outframe.scrollTop = outframe.scrollHeight; + updateViews() + txtoutput.scrollTop = txtoutput.scrollHeight } break case "Backspace": - if (txtinput.value.charCodeAt(txtinput.value.length - 1) === 10) { - txtinputrows = (Number.parseInt(txtinputrows, 10) - 1).toString() - txtinput.setAttribute("rows", txtinputrows) - } break default: break } }) -/* document.addEventListener('keydown', (event) => { - //console.log(`keydown: ${event.key}`) - if (event.key != "F5") { - event.preventDefault() - event.stopPropagation() - switch (event.key) { - case "Enter": - txtoutput.textContent += '\n' - stdin += '\n' - forth() - output.print(" _ok.") - outframe.scrollTop = outframe.scrollHeight; - txtoutput.textContent += '\n' - break - case "Backspace": - stdin = stdin.substring(0, stdin.length - 1) - txtoutput.textContent = txtoutput.textContent.substring(0, txtoutput.textContent.length - 1) - break - default: - if (event.key.length == 1) { - const input = event.ctrlKey ? ` \\\^${event.key} ` : event.key - stdin += input - output.print(input) - } - break - } - } - })*/ - const channels = [{ read: (writeAddr, maxBytes) => { const maxChars = maxBytes >> 1 @@ -118,56 +133,8 @@ window.onload = () => { new Uint16Array(wasmMem.buffer, readAddr, maxBytes >> 1) )) }] - const simstack = [] - const rstack = [] - const dictionary = { - ';': 1, - 'LIT': 2, - RINIT: 3, - WORD: 16500, - KEY: 5, - DUP: 6, - '+': 7, - 'NOOP2': 8, - '.': 9, - '@': 10, - '!': 11, - EXECUTE: 12, - NOOP: 13, - 'JZ:': 14, - 'JNZ:': 15, - DROP: 16, - 'WS?': 17, - 'JMP:': 18, - 'WPUTC': 19, - 'WB0': 20, - 'FIND': 21, - 'NUMBER': 22, - 'W!LEN': 23, - 'J-1:': 24, - 'BYE': 25, - 'SWAP': 26, - 'WORDS': 27, - 'HERE': 28, - 'DEFINE': 29, - '2DUP': 30, - 'ROT': 31, - '2DROP': 32, - ',': 33, - '-': 34, - 'CHANNEL!': 35, - 'HERE!': 36, - '=?': 37, - '.S': 38, - 'STRING-START': 39, - 'STRING-PUT': 40, - 'STRING-END': 41, - ':': 16800, - 'MODE': 14336, - 'EXECUTE-MODE': 16680, - 'QUIT': 16384, - 'INTERPRET': 16400 - } + + /* System runtime */ const wasmImport = { env: { pop: () => simstack.pop(), @@ -190,7 +157,7 @@ window.onload = () => { //"textEntry" or any third party protocols like activitypub console.log(`fetch ${channel} ${reqAddr}`) }, - sys_echo: (val) => output.print(`${val} `), + sys_echo: (val, base) => output.print(`${val.toString(base)} `), sys_echochar: (val) => output.print(String.fromCharCode(val)), sys_reflect: (addr) => { console.log(`reflect: ${addr}: ${ @@ -198,32 +165,14 @@ window.onload = () => { .getUint32(0,true) }`) }, - vocab_get: (addr, u) => { - const word = String.fromCharCode.apply( - null, - new Uint16Array(wasmMem.buffer, addr, u >> 1) - ) - const answer = dictionary[word.toUpperCase()] - if (answer === undefined) - return 0 - return answer - }, - vocab_set: (addr, u, num) => { - const word = String.fromCharCode.apply( - null, - new Uint16Array(wasmMem.buffer, addr, u >> 1) - ) - dictionary[word.toUpperCase()] = num - return 0 - }, + 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}]`), + sys_stack: () => console.log(`[${simstack}][${rstack}]`), sys_parsenum: (addr, u, base) => { - const word = String.fromCharCode.apply( - null, - new Uint16Array(wasmMem.buffer, addr, u >> 1) - ) - const answer = Number.parseInt(word, 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) @@ -241,6 +190,7 @@ window.onload = () => { forth = module.instance.exports.main console.log('wasm loaded') forth() + updateViews() }) }) }