Web-based NovaForth repl

This commit is contained in:
2023-01-01 17:26:21 -06:00
parent 63d58b63e3
commit 2dea244673
13 changed files with 1097 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
import 'xterm/css/xterm.css'
import './app.css'
import { Terminal } from 'xterm'
import { Readline } from 'xterm-readline'
import init, { WasmCPU, NovaForth } from '../pkg/vweb.js'
const term = new Terminal()
const rl = new Readline()
const TIB = 80000 // Just a convenient place to stick a terminal input buffer for the repl. Could be any otherwise-unused address.
const OUT = 0x10000 // A place that NovaForth will use for its output buffer
let syms
term.loadAddon(rl)
term.open(document.getElementsByClassName('terminal')[0])
term.write('Loading...\r\n')
const handleKey = ({key, domEvent: { key: mnemonic }}) => {
if (mnemonic === 'Enter') {
console.log(mnemonic)
} else {
term.write(key)
}
}
init().then(async () => {
const cpu = new WasmCPU()
syms = JSON.parse(NovaForth.symbols()) // Grab the symbol table for the ROM so we can poke things by name
NovaForth.rom().forEach((byte, idx) => {
cpu.poke(0x400 + idx, byte)
})
term.write(`Loaded ${NovaForth.rom().length} bytes\r\n`)
NovaForth.prelude().split(/\n/).forEach((line) => {
const result = eval4th(cpu, line) // If there's anything wrong with the prelude, say so
if (result !== '') {
console.log(`Error with "${line}": ${result}`)
}
})
term.write(`Loaded NovaForth Prelude\r\n`)
document.getElementsByClassName('prelude')[0].appendChild(document.createTextNode(NovaForth.prelude()))
term.focus()
while (true) {
const line = await rl.read('> ') // Read the line of input
const str = eval4th(cpu, line) // Run it on the CPU
rl.println(str) // Println the result
}
})
function eval4th(cpu, line) {
// Copy the line to TIB and null-terminate it
for (let i = 0; i < line.length; i++) {
cpu.poke(TIB + i, line.charCodeAt(i))
}
cpu.poke(TIB + line.length, 0)
cpu.push_call(syms.stop) // Tell the CPU to stop once we're done
cpu.push_data(TIB) // Push the TIB and call eval
cpu.set_pc(syms.eval)
cpu.run() // Run it!
const len = cpu.peek24(syms.emit_cursor) // Find the length of the output
let str = '' // Copy the output from the memory to a JS string
for (let i = OUT; i < OUT + len; i++) {
str = str + String.fromCharCode(cpu.peek(i))
}
cpu.poke24(syms.emit_cursor, 0) // Re-clear the output buffer
return str
}