Web-based NovaForth repl
This commit is contained in:
@@ -1 +1,3 @@
|
||||
/target
|
||||
/vweb/node_modules/
|
||||
/vweb/build/
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
{"$BRNZ":28,"$BRZ":27,"$CALL":25,"$JMP":23,"$JMPR":24,"$PUSH":0,"$RET":26,"$SWAP":20,"$end":4585,"$start":1024,"advance_entry":1141,"backslash":3276,"close_paren":3267,"close_paren_stub":3275,"compare":1414,"compile_dict_start":3429,"compile_dictionary":4222,"compile_handleword":3150,"compile_instruction":1537,"compile_instruction_arg":1511,"compile_tick":1196,"cr":1067,"cursor":4210,"data_start":3340,"dict_start":3588,"dictionary":4219,"does_at_runtime":2225,"does_word":2196,"dupnz":1074,"dupnz_done":1080,"emit":1025,"emit_cursor":1042,"emit_hook":4228,"end0_pop1":1093,"end0_pop2":1092,"end1_pop2":1096,"eval":1773,"expected_word_err":3388,"find_in_dict":1149,"find_in_dict_next":1179,"find_word":2584,"handleword_hook":4198,"heap":4195,"heap_start":4586,"hex_is_number":1280,"hex_itoa":1701,"immediate_handleword":3113,"input_number":1595,"invalid_mnemonic":3293,"invalid_mnemonic_str":3353,"is_digit":1084,"is_number":1205,"is_number_hook":4201,"itoa":1618,"itoa_hook":4204,"itoa_loop":1648,"itoa_pos":1637,"itoa_print_loop":1685,"lambda_nesting_level":4216,"lambda_start_ptr":4213,"line_len":4207,"linecomment":3209,"missing_word":3301,"missing_word_str":3340,"mnemonics":2258,"mnemonics_end":2469,"new_dict":1451,"new_dict_error":1497,"nova_asm_to":2563,"nova_bracket_tick":2634,"nova_char":2689,"nova_close_brace":3049,"nova_close_bracket":1998,"nova_colon":2146,"nova_comma":2133,"nova_compile_dotquote":2877,"nova_compile_opcode":2555,"nova_compile_open_brace":3024,"nova_compile_squote":2810,"nova_continue":2007,"nova_create":1946,"nova_dec":2660,"nova_dotquote":2856,"nova_emit":3007,"nova_exit":2099,"nova_here":2579,"nova_hex":2672,"nova_immediate":2105,"nova_immediate_open_brace":3012,"nova_literal":2654,"nova_number":1932,"nova_opcode":2550,"nova_opcode_for_word":2469,"nova_open_bracket":1990,"nova_peekr":2961,"nova_popr":2994,"nova_postpone":2017,"nova_print_stack":2907,"nova_pushr":2981,"nova_quote_string_to":2715,"nova_resolve":1568,"nova_rpick":2969,"nova_safe_opcode":2529,"nova_semicolon":2154,"nova_squote":2780,"nova_tick":2613,"nova_word":1852,"nova_word_to":1902,"nova_word_to_pad":2164,"open_paren":3250,"pad":4231,"parencomment":3211,"parse_hex_digit":1326,"pos_is_number":1234,"pos_is_number_bad":1271,"pos_is_number_done":1276,"pos_is_number_loop":1236,"print":1045,"print_number":1613,"print_stack_end":3426,"print_stack_start":3422,"push_jump":1552,"quit":3317,"quit_vector":4225,"r_stack":4490,"r_stack_ptr":4487,"skip_nonword":1388,"skip_word":1371,"stop":1024,"tick":1187,"unclosed_error":3372,"word_char":1081,"wordeq":1100}
|
||||
@@ -0,0 +1,25 @@
|
||||
: if $ brz >asm ; immediate
|
||||
: then resolve ; immediate
|
||||
: else r> $ jmpr >asm >r resolve ; immediate
|
||||
: variable create 0 , does> ;
|
||||
: arshift $ arshift asm ;
|
||||
: lshift [ $ lshift asm ] ;
|
||||
: rshift [ $ rshift asm ] ;
|
||||
: u> [ $ gt ] asm ;
|
||||
: u< [ $ lt ] asm ;
|
||||
: rdrop r> pop ;
|
||||
: over 1 pick ;
|
||||
: nip swap pop ;
|
||||
: -rot rot rot ;
|
||||
: tuck dup -rot ;
|
||||
: space 32 emit ;
|
||||
: cr 13 emit 10 emit ;
|
||||
: +! dup @ rot + swap ! ;
|
||||
: 2dup 1 pick 1 pick ;
|
||||
: allot here swap &heap +! ;
|
||||
: negate -1 ^ 1 + ;
|
||||
: free negate &heap +! here ;
|
||||
: c+! dup c@ rot + swap c! ;
|
||||
: ror dup 1 rshift swap 23 lshift | ;
|
||||
: rol dup 23 rshift swap 1 lshift | ;
|
||||
: abs dup 0 < if negate then ;
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "vweb"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
vcore = { path = "../vcore" }
|
||||
wasm-bindgen = "0.2"
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
wasm-pack build --target web
|
||||
npm run bundle
|
||||
cp pkg/vweb_bg.wasm src/index.html build
|
||||
@@ -0,0 +1,9 @@
|
||||
require('esbuild').build({
|
||||
entryPoints: ['src/app.js'],
|
||||
bundle: true,
|
||||
outdir: 'build',
|
||||
format: 'esm',
|
||||
loader: {
|
||||
'.wasm': 'file'
|
||||
}
|
||||
}).catch(() => process.exit(1))
|
||||
Generated
+650
@@ -0,0 +1,650 @@
|
||||
{
|
||||
"name": "vweb",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"esbuild": "^0.16.12",
|
||||
"xterm": "^5.0.0",
|
||||
"xterm-readline": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.12.tgz",
|
||||
"integrity": "sha512-CTWgMJtpCyCltrvipZrrcjjRu+rzm6pf9V8muCsJqtKujR3kPmU4ffbckvugNNaRmhxAF1ZI3J+0FUIFLFg8KA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.12.tgz",
|
||||
"integrity": "sha512-0LacmiIW+X0/LOLMZqYtZ7d4uY9fxYABAYhSSOu+OGQVBqH4N5eIYgkT7bBFnR4Nm3qo6qS3RpHKVrDASqj/uQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-sS5CR3XBKQXYpSGMM28VuiUnbX83Z+aWPZzClW+OB2JquKqxoiwdqucJ5qvXS8pM6Up3RtJfDnRQZkz3en2z5g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.12.tgz",
|
||||
"integrity": "sha512-Dpe5hOAQiQRH20YkFAg+wOpcd4PEuXud+aGgKBQa/VriPJA8zuVlgCOSTwna1CgYl05lf6o5els4dtuyk1qJxQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-ApGRA6X5txIcxV0095X4e4KKv87HAEXfuDRcGTniDWUUN+qPia8sl/BqG/0IomytQWajnUn4C7TOwHduk/FXBQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.12.tgz",
|
||||
"integrity": "sha512-AMdK2gA9EU83ccXCWS1B/KcWYZCj4P3vDofZZkl/F/sBv/fphi2oUqUTox/g5GMcIxk8CF1CVYTC82+iBSyiUg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-KUKB9w8G/xaAbD39t6gnRBuhQ8vIYYlxGT2I+mT6UGRnCGRr1+ePFIGBQmf5V16nxylgUuuWVW1zU2ktKkf6WQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.12.tgz",
|
||||
"integrity": "sha512-vhDdIv6z4eL0FJyNVfdr3C/vdd/Wc6h1683GJsFoJzfKb92dU/v88FhWdigg0i6+3TsbSDeWbsPUXb4dif2abg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.12.tgz",
|
||||
"integrity": "sha512-29HXMLpLklDfmw7T2buGqq3HImSUaZ1ArmrPOMaNiZZQptOSZs32SQtOHEl8xWX5vfdwZqrBfNf8Te4nArVzKQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.12.tgz",
|
||||
"integrity": "sha512-JFDuNDTTfgD1LJg7wHA42o2uAO/9VzHYK0leAVnCQE/FdMB599YMH73ux+nS0xGr79pv/BK+hrmdRin3iLgQjg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.12.tgz",
|
||||
"integrity": "sha512-xTGzVPqm6WKfCC0iuj1fryIWr1NWEM8DMhAIo+4rFgUtwy/lfHl+Obvus4oddzRDbBetLLmojfVZGmt/g/g+Rw==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.12.tgz",
|
||||
"integrity": "sha512-zI1cNgHa3Gol+vPYjIYHzKhU6qMyOQrvZ82REr5Fv7rlh5PG6SkkuCoH7IryPqR+BK2c/7oISGsvPJPGnO2bHQ==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.12.tgz",
|
||||
"integrity": "sha512-/C8OFXExoMmvTDIOAM54AhtmmuDHKoedUd0Otpfw3+AuuVGemA1nQK99oN909uZbLEU6Bi+7JheFMG3xGfZluQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.12.tgz",
|
||||
"integrity": "sha512-qeouyyc8kAGV6Ni6Isz8hUsKMr00EHgVwUKWNp1r4l88fHEoNTDB8mmestvykW6MrstoGI7g2EAsgr0nxmuGYg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.12.tgz",
|
||||
"integrity": "sha512-s9AyI/5vz1U4NNqnacEGFElqwnHusWa81pskAf8JNDM2eb6b2E6PpBmT8RzeZv6/TxE6/TADn2g9bb0jOUmXwQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-e8YA7GQGLWhvakBecLptUiKxOk4E/EPtSckS1i0MGYctW8ouvNUoh7xnU15PGO2jz7BYl8q1R6g0gE5HFtzpqQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-z2+kUxmOqBS+6SRVd57iOLIHE8oGOoEnGVAmwjm2aENSP35HPS+5cK+FL1l+rhrsJOFIPrNHqDUNechpuG96Sg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-PAonw4LqIybwn2/vJujhbg1N9W2W8lw9RtXIvvZoyzoA/4rA4CpiuahVbASmQohiytRsixbNoIOUSjRygKXpyA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-+wr1tkt1RERi+Zi/iQtkzmMH4nS8+7UIRxjcyRz7lur84wCkAITT50Olq/HiT4JN2X2bjtlOV6vt7ptW5Gw60Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.12.tgz",
|
||||
"integrity": "sha512-XEjeUSHmjsAOJk8+pXJu9pFY2O5KKQbHXZWQylJzQuIBeiGrpMeq9sTVrHefHxMOyxUgoKQTcaTS+VK/K5SviA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.12.tgz",
|
||||
"integrity": "sha512-eRKPM7e0IecUAUYr2alW7JGDejrFJXmpjt4MlfonmQ5Rz9HWpKFGCjuuIRgKO7W9C/CWVFXdJ2GjddsBXqQI4A==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-iPYKN78t3op2+erv2frW568j1q0RpqX6JOLZ7oPPaAV1VaF7dDstOrNw37PVOYoTWE11pV4A1XUitpdEFNIsPg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.12.tgz",
|
||||
"integrity": "sha512-eq5KcuXajf2OmivCl4e89AD3j8fbV+UTE9vczEzq5haA07U9oOTzBWlh3+6ZdjJR7Rz2QfWZ2uxZyhZxBgJ4+g==",
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/android-arm": "0.16.12",
|
||||
"@esbuild/android-arm64": "0.16.12",
|
||||
"@esbuild/android-x64": "0.16.12",
|
||||
"@esbuild/darwin-arm64": "0.16.12",
|
||||
"@esbuild/darwin-x64": "0.16.12",
|
||||
"@esbuild/freebsd-arm64": "0.16.12",
|
||||
"@esbuild/freebsd-x64": "0.16.12",
|
||||
"@esbuild/linux-arm": "0.16.12",
|
||||
"@esbuild/linux-arm64": "0.16.12",
|
||||
"@esbuild/linux-ia32": "0.16.12",
|
||||
"@esbuild/linux-loong64": "0.16.12",
|
||||
"@esbuild/linux-mips64el": "0.16.12",
|
||||
"@esbuild/linux-ppc64": "0.16.12",
|
||||
"@esbuild/linux-riscv64": "0.16.12",
|
||||
"@esbuild/linux-s390x": "0.16.12",
|
||||
"@esbuild/linux-x64": "0.16.12",
|
||||
"@esbuild/netbsd-x64": "0.16.12",
|
||||
"@esbuild/openbsd-x64": "0.16.12",
|
||||
"@esbuild/sunos-x64": "0.16.12",
|
||||
"@esbuild/win32-arm64": "0.16.12",
|
||||
"@esbuild/win32-ia32": "0.16.12",
|
||||
"@esbuild/win32-x64": "0.16.12"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/xterm": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm/-/xterm-5.1.0.tgz",
|
||||
"integrity": "sha512-LovENH4WDzpwynj+OTkLyZgJPeDom9Gra4DMlGAgz6pZhIDCQ+YuO7yfwanY+gVbn/mmZIStNOnVRU/ikQuAEQ=="
|
||||
},
|
||||
"node_modules/xterm-readline": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/xterm-readline/-/xterm-readline-1.1.1.tgz",
|
||||
"integrity": "sha512-f87S2/jKwRZoZTxE2vkPgBCipDl6k6tTkMTb9pmwC4R6XkfR491fWBuToZd/nZasp6seD2u0jdABinUDWsK6dw==",
|
||||
"dependencies": {
|
||||
"string-width": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"xterm": "^5.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@esbuild/android-arm": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.12.tgz",
|
||||
"integrity": "sha512-CTWgMJtpCyCltrvipZrrcjjRu+rzm6pf9V8muCsJqtKujR3kPmU4ffbckvugNNaRmhxAF1ZI3J+0FUIFLFg8KA==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/android-arm64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.12.tgz",
|
||||
"integrity": "sha512-0LacmiIW+X0/LOLMZqYtZ7d4uY9fxYABAYhSSOu+OGQVBqH4N5eIYgkT7bBFnR4Nm3qo6qS3RpHKVrDASqj/uQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/android-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-sS5CR3XBKQXYpSGMM28VuiUnbX83Z+aWPZzClW+OB2JquKqxoiwdqucJ5qvXS8pM6Up3RtJfDnRQZkz3en2z5g==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/darwin-arm64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.12.tgz",
|
||||
"integrity": "sha512-Dpe5hOAQiQRH20YkFAg+wOpcd4PEuXud+aGgKBQa/VriPJA8zuVlgCOSTwna1CgYl05lf6o5els4dtuyk1qJxQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/darwin-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-ApGRA6X5txIcxV0095X4e4KKv87HAEXfuDRcGTniDWUUN+qPia8sl/BqG/0IomytQWajnUn4C7TOwHduk/FXBQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/freebsd-arm64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.12.tgz",
|
||||
"integrity": "sha512-AMdK2gA9EU83ccXCWS1B/KcWYZCj4P3vDofZZkl/F/sBv/fphi2oUqUTox/g5GMcIxk8CF1CVYTC82+iBSyiUg==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/freebsd-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-KUKB9w8G/xaAbD39t6gnRBuhQ8vIYYlxGT2I+mT6UGRnCGRr1+ePFIGBQmf5V16nxylgUuuWVW1zU2ktKkf6WQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-arm": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.12.tgz",
|
||||
"integrity": "sha512-vhDdIv6z4eL0FJyNVfdr3C/vdd/Wc6h1683GJsFoJzfKb92dU/v88FhWdigg0i6+3TsbSDeWbsPUXb4dif2abg==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-arm64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.12.tgz",
|
||||
"integrity": "sha512-29HXMLpLklDfmw7T2buGqq3HImSUaZ1ArmrPOMaNiZZQptOSZs32SQtOHEl8xWX5vfdwZqrBfNf8Te4nArVzKQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-ia32": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.12.tgz",
|
||||
"integrity": "sha512-JFDuNDTTfgD1LJg7wHA42o2uAO/9VzHYK0leAVnCQE/FdMB599YMH73ux+nS0xGr79pv/BK+hrmdRin3iLgQjg==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-loong64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.12.tgz",
|
||||
"integrity": "sha512-xTGzVPqm6WKfCC0iuj1fryIWr1NWEM8DMhAIo+4rFgUtwy/lfHl+Obvus4oddzRDbBetLLmojfVZGmt/g/g+Rw==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-mips64el": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.12.tgz",
|
||||
"integrity": "sha512-zI1cNgHa3Gol+vPYjIYHzKhU6qMyOQrvZ82REr5Fv7rlh5PG6SkkuCoH7IryPqR+BK2c/7oISGsvPJPGnO2bHQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-ppc64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.12.tgz",
|
||||
"integrity": "sha512-/C8OFXExoMmvTDIOAM54AhtmmuDHKoedUd0Otpfw3+AuuVGemA1nQK99oN909uZbLEU6Bi+7JheFMG3xGfZluQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-riscv64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.12.tgz",
|
||||
"integrity": "sha512-qeouyyc8kAGV6Ni6Isz8hUsKMr00EHgVwUKWNp1r4l88fHEoNTDB8mmestvykW6MrstoGI7g2EAsgr0nxmuGYg==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-s390x": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.12.tgz",
|
||||
"integrity": "sha512-s9AyI/5vz1U4NNqnacEGFElqwnHusWa81pskAf8JNDM2eb6b2E6PpBmT8RzeZv6/TxE6/TADn2g9bb0jOUmXwQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-e8YA7GQGLWhvakBecLptUiKxOk4E/EPtSckS1i0MGYctW8ouvNUoh7xnU15PGO2jz7BYl8q1R6g0gE5HFtzpqQ==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/netbsd-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-z2+kUxmOqBS+6SRVd57iOLIHE8oGOoEnGVAmwjm2aENSP35HPS+5cK+FL1l+rhrsJOFIPrNHqDUNechpuG96Sg==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/openbsd-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-PAonw4LqIybwn2/vJujhbg1N9W2W8lw9RtXIvvZoyzoA/4rA4CpiuahVbASmQohiytRsixbNoIOUSjRygKXpyA==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/sunos-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-+wr1tkt1RERi+Zi/iQtkzmMH4nS8+7UIRxjcyRz7lur84wCkAITT50Olq/HiT4JN2X2bjtlOV6vt7ptW5Gw60Q==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/win32-arm64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.12.tgz",
|
||||
"integrity": "sha512-XEjeUSHmjsAOJk8+pXJu9pFY2O5KKQbHXZWQylJzQuIBeiGrpMeq9sTVrHefHxMOyxUgoKQTcaTS+VK/K5SviA==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/win32-ia32": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.12.tgz",
|
||||
"integrity": "sha512-eRKPM7e0IecUAUYr2alW7JGDejrFJXmpjt4MlfonmQ5Rz9HWpKFGCjuuIRgKO7W9C/CWVFXdJ2GjddsBXqQI4A==",
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/win32-x64": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.12.tgz",
|
||||
"integrity": "sha512-iPYKN78t3op2+erv2frW568j1q0RpqX6JOLZ7oPPaAV1VaF7dDstOrNw37PVOYoTWE11pV4A1XUitpdEFNIsPg==",
|
||||
"optional": true
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.16.12",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.12.tgz",
|
||||
"integrity": "sha512-eq5KcuXajf2OmivCl4e89AD3j8fbV+UTE9vczEzq5haA07U9oOTzBWlh3+6ZdjJR7Rz2QfWZ2uxZyhZxBgJ4+g==",
|
||||
"requires": {
|
||||
"@esbuild/android-arm": "0.16.12",
|
||||
"@esbuild/android-arm64": "0.16.12",
|
||||
"@esbuild/android-x64": "0.16.12",
|
||||
"@esbuild/darwin-arm64": "0.16.12",
|
||||
"@esbuild/darwin-x64": "0.16.12",
|
||||
"@esbuild/freebsd-arm64": "0.16.12",
|
||||
"@esbuild/freebsd-x64": "0.16.12",
|
||||
"@esbuild/linux-arm": "0.16.12",
|
||||
"@esbuild/linux-arm64": "0.16.12",
|
||||
"@esbuild/linux-ia32": "0.16.12",
|
||||
"@esbuild/linux-loong64": "0.16.12",
|
||||
"@esbuild/linux-mips64el": "0.16.12",
|
||||
"@esbuild/linux-ppc64": "0.16.12",
|
||||
"@esbuild/linux-riscv64": "0.16.12",
|
||||
"@esbuild/linux-s390x": "0.16.12",
|
||||
"@esbuild/linux-x64": "0.16.12",
|
||||
"@esbuild/netbsd-x64": "0.16.12",
|
||||
"@esbuild/openbsd-x64": "0.16.12",
|
||||
"@esbuild/sunos-x64": "0.16.12",
|
||||
"@esbuild/win32-arm64": "0.16.12",
|
||||
"@esbuild/win32-ia32": "0.16.12",
|
||||
"@esbuild/win32-x64": "0.16.12"
|
||||
}
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"xterm": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm/-/xterm-5.1.0.tgz",
|
||||
"integrity": "sha512-LovENH4WDzpwynj+OTkLyZgJPeDom9Gra4DMlGAgz6pZhIDCQ+YuO7yfwanY+gVbn/mmZIStNOnVRU/ikQuAEQ=="
|
||||
},
|
||||
"xterm-readline": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/xterm-readline/-/xterm-readline-1.1.1.tgz",
|
||||
"integrity": "sha512-f87S2/jKwRZoZTxE2vkPgBCipDl6k6tTkMTb9pmwC4R6XkfR491fWBuToZd/nZasp6seD2u0jdABinUDWsK6dw==",
|
||||
"requires": {
|
||||
"string-width": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"esbuild": "^0.16.12",
|
||||
"xterm": "^5.0.0",
|
||||
"xterm-readline": "^1.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
"bundle": "node esbuild.js"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
body {
|
||||
background-color: #333333;
|
||||
color: #dddddd;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 8fr 1fr;
|
||||
grid-template-rows: auto auto;
|
||||
}
|
||||
|
||||
.terminal {
|
||||
grid-area: 1 / 2 / 1 / 2;
|
||||
border: 2px solid #777777;
|
||||
}
|
||||
|
||||
.instructions {
|
||||
grid-area: 2 / 2 / 2 / 2;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #0f0f0f;
|
||||
}
|
||||
|
||||
td.word, td.signature {
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
padding-right: 1em;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="app.css"/>
|
||||
<title>NovaForth REPL</title>
|
||||
<script type="module" src="app.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
<div class="terminal"></div>
|
||||
<div class="instructions">
|
||||
<h2>NovaForth Console</h2>
|
||||
<p>
|
||||
This is a REPL for NovaForth, using the Vulcan imaginary CPU.
|
||||
You can type lines of Forth code and have them evaluated, and see the results.
|
||||
</p>
|
||||
<p>
|
||||
For a full introduction to NovaForth, read
|
||||
<a href="https://docs.google.com/document/d/12juFyAGWC9TL2qB97Ud3VehlVdge-zpEjy7FSM1BWF4/edit?usp=sharing">
|
||||
this sample chapter
|
||||
</a>
|
||||
from the upcoming Vulcan book. A short tutorial is below:
|
||||
</p>
|
||||
<h3>Tutorial and examples:</h3>
|
||||
<p>
|
||||
Forth programs are a series of "words" separated by whitespace. NovaForth evaluates words line-by-line, and a
|
||||
full dictionary of available words is listed below. Here are some example programs:
|
||||
</p>
|
||||
<p>
|
||||
<pre>5 3 + .</pre>
|
||||
This program pushes the numbers "5" and "3" to the stack, then adds the top two numbers on the stack, and
|
||||
finally pops the top number from the stack (now "8") and prints it.
|
||||
</p>
|
||||
<p>
|
||||
<pre>." Hello, world!"</pre>
|
||||
This program prints a standard greeting.
|
||||
</p>
|
||||
<p>
|
||||
<pre>: square dup * ;
|
||||
4 square .</pre>
|
||||
This defines a new word, "square", which multiplies the top value on the stack by itself. The second line then
|
||||
calls that word on the number "4" and prints the result.
|
||||
</p>
|
||||
<p>
|
||||
<pre>: collatz
|
||||
dup 2 % if
|
||||
3 * 1 +
|
||||
else
|
||||
2 /
|
||||
then ;
|
||||
|
||||
4 collatz 5 collatz .s</pre>
|
||||
This defines a word "collatz" which showcases conditionals: if the number given to it is odd, it returns triple
|
||||
that number plus one; if it's even, it returns half that number. The ".s" word prints the stack without modifying
|
||||
it and is a useful debugging tool.
|
||||
</p>
|
||||
<h3>NovaForth Dictionary</h3>
|
||||
<h4>Arithmetic and stack juggling</h4>
|
||||
<table>
|
||||
<tr><td class="word">+</td><td class="signature">a b -- c</td><td class="meaning">Addition</td></tr>
|
||||
<tr><td class="word">-</td><td class="signature">a b -- c</td><td class="meaning">Subtraction</td></tr>
|
||||
<tr><td class="word">*</td><td class="signature">a b -- c</td><td class="meaning">Multiplication</td></tr>
|
||||
<tr><td class="word">/</td><td class="signature">a b -- c</td><td class="meaning">Division (truncates to integer)</td></tr>
|
||||
<tr><td class="word">%</td><td class="signature">a b -- c</td><td class="meaning">Modulus</td></tr>
|
||||
<tr><td class="word">pop</td><td class="signature">a --</td><td class="meaning">Throw away the top element of the stack</td></tr>
|
||||
<tr><td class="word">dup</td><td class="signature">a -- a a</td><td class="meaning">Duplicate the top element of the stack</td></tr>
|
||||
<tr><td class="word">swap</td><td class="signature">a b -- b a</td><td class="meaning">Swap the top two elements of the stack</td></tr>
|
||||
<tr>
|
||||
<td class="word">pick</td>
|
||||
<td class="signature">* index -- * el</td>
|
||||
<td class="meaning">Copy an element from deep in the stack to the top. "0 pick" is equivalent to dup,
|
||||
"1 pick" pushes the value one below the top, and so on</td></tr>
|
||||
<tr>
|
||||
<td class="word">rot</td>
|
||||
<td class="signature">a b c -- b c a</td>
|
||||
<td class="meaning">Rotate the top three elements on the stack</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="word">-rot</td>
|
||||
<td class="signature">a b c -- c a b</td>
|
||||
<td class="meaning">Rotate the top three elements on the stack the other direction (prelude word)</td>
|
||||
</tr>
|
||||
<tr><td class="word">?dup</td><td class="signature">a -- a a OR 0 -- 0</td><td class="meaning">Duplicates the top of stack if it's nonzero</td></tr>
|
||||
<tr><td class="word">>r</td><td class="signature">a --</td><td class="meaning">Pushes the top of the stack to the R stack</td></tr>
|
||||
<tr><td class="word">r></td><td class="signature">-- a</td><td class="meaning">Pushes the top of the R stack to the stack</td></tr>
|
||||
<tr><td class="word">r@</td><td class="signature">-- a</td><td class="meaning">Copies the top of the R stack to the stack, leaving the R stack unchanged</td></tr>
|
||||
<tr><td class="word">rpick</td><td class="signature">index -- a</td><td class="meaning">Picks a value from deep in the R stack, much like "pick" does with the data stack</td></tr>
|
||||
<tr><td class="word">rdrop</td><td class="signature">--</td><td class="meaning">Drop the top value from the R stack (prelude word)</td></tr>
|
||||
<tr><td class="word">lshift</td><td class="signature">a b -- c</td><td class="meaning">Binary-shifts "a" left "b" bits, shifting in zeroes (prelude word)</td></tr>
|
||||
<tr><td class="word">rshift</td><td class="signature">a b -- c</td><td class="meaning">Binary-shifts "a" right "b" bits, shifting in zeroes (prelude word)</td></tr>
|
||||
<tr><td class="word">arshift</td><td class="signature">a b -- c</td><td class="meaning">Arithmetic right shift: right-shift leaving the high order bit untouched (to preserve sign) (prelude word)</td></tr>
|
||||
<tr><td class="word">ror</td><td class="signature">a -- b</td><td class="meaning">Roll one bit right, moving the low bit to the high bit (prelude word)</td></tr>
|
||||
<tr><td class="word">rol</td><td class="signature">a -- b</td><td class="meaning">Roll one bit left, moving the high bit to the low bit (prelude word)</td></tr>
|
||||
<tr><td class="word">over</td><td class="signature">a b -- a b a</td><td class="meaning">Duplicate the value one below top (prelude word)</td></tr>
|
||||
<tr><td class="word">nip</td><td class="signature">a b -- b</td><td class="meaning">Drop the value one below top (prelude word)</td></tr>
|
||||
<tr><td class="word">tuck</td><td class="signature">a b -- b a b</td><td class="meaning">Duplicate the top value, placing it underneath the one below top (prelude word)</td></tr>
|
||||
<tr><td class="word">2dup</td><td class="signature">a b -- a b a b</td><td class="meaning">Duplicate the top two values (prelude word)</td></tr>
|
||||
<tr><td class="word">negate</td><td class="signature">a -- b</td><td class="meaning">Multiply the top of stack by -1 (prelude word)</td></tr>
|
||||
<tr><td class="word">abs</td><td class="signature">a -- b</td><td class="meaning">Return the absolute value of the top of stack (prelude word)</td></tr>
|
||||
</table>
|
||||
<h4>I/O</h4>
|
||||
<table>
|
||||
<tr><td class="word">word <em>word</em></td><td class="signature">-- addr</td><td class="meaning">Copies <em>word</em> to the pad, leaving its address on the stack</td></tr>
|
||||
<tr><td class="word">pad</td><td class="signature">-- addr</td><td class="meaning">Pushes the address of the pad to the stack</td></tr>
|
||||
<tr><td class="word">number <em>str</em></td><td class="signature">-- num 1 OR -- 0</td><td class="meaning">Tries to parse the given word as a number, pushes the number followed by 1 if it's parseable and 0 if it's not</td></tr>
|
||||
<tr><td class="word">hex</td><td class="signature">--</td><td class="meaning">Switches all I/O to hexadecimal mode</td></tr>
|
||||
<tr><td class="word">dec</td><td class="signature">--</td><td class="meaning">Switches all I/O to base-10 mode (the default)</td></tr>
|
||||
<tr><td class="word">.</td><td class="signature">a --</td><td class="meaning">Prints the number on the top of the stack</td></tr>
|
||||
<tr><td class="word">s"</td><td class="signature">-- addr</td><td class="meaning">Reads a string until a double-quote, copies them to the heap, and returns the address of the string</td></tr>
|
||||
<tr><td class="word">."</td><td class="signature">--</td><td class="meaning">Reads a string until a double-quote and prints it</td></tr>
|
||||
<tr><td class="word">emit</td><td class="signature">ch --</td><td class="meaning">Emits a byte (as ASCII) to the console</td></tr>
|
||||
<tr><td class="word">print</td><td class="signature">addr --</td><td class="meaning">Prints a null-terminated string to the console</td></tr>
|
||||
<tr><td class="word">.s</td><td class="signature">--</td><td class="meaning">Prints the stack contents as a debugging aid</td></tr>
|
||||
<tr><td class="word">space</td><td class="signature">--</td><td class="meaning">Prints a space (prelude word)</td></tr>
|
||||
<tr><td class="word">cr</td><td class="signature">--</td><td class="meaning">Prints a newline (10 followed by 13, carriage return and line feed) (prelude word)</td></tr>
|
||||
</table>
|
||||
<h4>Logic and control structures</h4>
|
||||
<table>
|
||||
<tr><td class="word">></td><td class="signature">a b -- c</td><td class="meaning">Returns a 1 if a is greater than b, 0 otherwise (signed comparison)</td></tr>
|
||||
<tr><td class="word"><</td><td class="signature">a b -- c</td><td class="meaning">Returns a 1 if a is less than b, 0 otherwise (signed comparison)</td></tr>
|
||||
<tr><td class="word">u></td><td class="signature">a b -- c</td><td class="meaning">Returns a 1 if a is greater than b, 0 otherwise (unsigned comparison) (prelude word)</td></tr>
|
||||
<tr><td class="word">u<</td><td class="signature">a b -- c</td><td class="meaning">Returns a 1 if a is less than b, 0 otherwise (unsigned comparison) (prelude word)</td></tr>
|
||||
<tr><td class="word">=</td><td class="signature">a b -- c</td><td class="meaning">Returns a 1 if a is equal to b, 0 otherwise</td></tr>
|
||||
<tr><td class="word">&</td><td class="signature">a b -- c</td><td class="meaning">Bitwise-and of a and b</td></tr>
|
||||
<tr><td class="word">|</td><td class="signature">a b -- c</td><td class="meaning">Bitwise-or of a and b</td></tr>
|
||||
<tr><td class="word">^</td><td class="signature">a b -- c</td><td class="meaning">Bitwise-xor of a and b</td></tr>
|
||||
<tr><td class="word">not</td><td class="signature">a -- b</td><td class="meaning">If the argument is a 0, returns 1. Otherwise returns 0</td></tr>
|
||||
<tr><td class="word">compare</td><td class="signature">a b -- c</td><td class="meaning">Compares two strings for equality, returns 1 if they're equal and 0 otherwise</td></tr>
|
||||
<tr><td class="word">if / else / then</td><td class="signature">cond --</td><td class="meaning">A conditional branch: "<em>condition</em> if <em>truepath</em> else <em>falsepath</em> then". The "else" branch is optional (prelude words)</td></tr>
|
||||
</table>
|
||||
<h4>Memory management</h4>
|
||||
<table>
|
||||
<tr><td class="word">@</td><td class="signature">addr -- val</td><td class="meaning">Read the 3-byte word at the given address</td></tr>
|
||||
<tr><td class="word">!</td><td class="signature">val addr --</td><td class="meaning">Write a 3-byte word to the given address</td></tr>
|
||||
<tr><td class="word">c@</td><td class="signature">addr -- val</td><td class="meaning">Read one byte from the given address</td></tr>
|
||||
<tr><td class="word">c!</td><td class="signature">val addr --</td><td class="meaning">Write one byte to the given address</td></tr>
|
||||
<tr><td class="word">&heap</td><td class="signature">-- addr</td><td class="meaning">Pushes the address of the heap pointer</td></tr>
|
||||
<tr><td class="word">here</td><td class="signature">-- addr</td><td class="meaning">Pushes the current value of the heap pointer (equivalent to "&heap @")</td></tr>
|
||||
<tr><td class="word">variable <em>name</em></td><td class="signature">--</td><td class="meaning">Creates a variable of the given name, which pushes its address when called (prelude word)</td></tr>
|
||||
<tr><td class="word">+!</td><td class="signature">val addr --</td><td class="meaning">Increments the 3-byte word at "addr" by "val" (prelude word)</td></tr>
|
||||
<tr><td class="word">c+!</td><td class="signature">val addr --</td><td class="meaning">Increments the byte at "addr" by "val" (prelude word)</td></tr>
|
||||
<tr><td class="word">allot</td><td class="signature">val -- addr</td><td class="meaning">Increment the heap by "val" bytes, returning the start address of the allotted region (prelude word)</td></tr>
|
||||
<tr><td class="word">free</td><td class="signature">val -- addr</td><td class="meaning">Decrement the heap by "val" bytes, returning the new heap address (prelude word)</td></tr>
|
||||
</table>
|
||||
<h4>Assembly and compilation</h4>
|
||||
<table>
|
||||
<tr><td class="word">execute</td><td class="signature">addr --</td><td class="meaning">Calls the given address</td></tr>
|
||||
<tr><td class="word">[</td><td class="signature">--</td><td class="meaning">Enters interpret mode</td></tr>
|
||||
<tr><td class="word">]</td><td class="signature">--</td><td class="meaning">Enters compile mode</td></tr>
|
||||
<tr><td class="word">,</td><td class="signature">a --</td><td class="meaning">Compiles a number to the heap</td></tr>
|
||||
<tr><td class="word">:</td><td class="signature">--</td><td class="meaning">Begins definition of a new word: calls create and enters compile mode</td></tr>
|
||||
<tr><td class="word">;</td><td class="signature">--</td><td class="meaning">Ends a word definition: compiles a return instruction and leaves compile mode</td></tr>
|
||||
<tr><td class="word">$ <em>mnemonic</em></td><td class="signature">-- a</td><td class="meaning">Pushes the equivalent opcode to the given instruction mnemonic</td></tr>
|
||||
<tr><td class="word">asm</td><td class="signature">op --</td><td class="meaning">Compiles an instruction of the given opcode (with no argument)</td></tr>
|
||||
<tr><td class="word">#asm</td><td class="signature">op arg --</td><td class="meaning">Compiles an instruction of the given opcode with an argument</td></tr>
|
||||
<tr><td class="word">>asm</td><td class="signature">op --</td><td class="meaning">Compiles an instruction of the given opcode with a blank argument, and stores the argument's address to the R stack</td></tr>
|
||||
<tr><td class="word">resolve</td><td class="signature">addr --</td><td class="meaning">Writes the top of the stack to the address on top of the R stack (used to resolve a blank argument left by >asm)</td></tr>
|
||||
<tr><td class="word">{</td><td class="signature">--</td><td class="meaning">Begins an anonymous function</td></tr>
|
||||
<tr><td class="word">}</td><td class="signature">-- addr</td><td class="meaning">Ends an anonymous function and leaves its address on the stack</td></tr>
|
||||
<tr><td class="word">exit</td><td class="signature">--</td><td class="meaning">Early return from a word definition</td></tr>
|
||||
<tr><td class="word">continue <em>word</em></td><td class="signature">--</td><td class="meaning">Jumps to the given word as a tail call (replacing the current stack frame)</td></tr>
|
||||
<tr><td class="word">postpone <em>word</em></td><td class="signature">--</td><td class="meaning">Delays execution of the given word: compiles a call to a compile-mode word or compiles instructions to compile a call to an interpret-mode word (see the NovaForth guide)</td></tr>
|
||||
<tr><td class="word">literal</td><td class="signature">-- addr</td><td class="meaning">Compiles an instruction to push the number at the top of the stack</td></tr>
|
||||
</table>
|
||||
<h4>Dictionary manipulation</h4>
|
||||
<table>
|
||||
<tr><td class="word">create <em>name</em></td><td class="signature">--</td><td class="meaning">Creates a dictionary entry for a given word (pointing to the heap)</td></tr>
|
||||
<tr><td class="word">immediate</td><td class="signature">--</td><td class="meaning">Moves the most recently defined word from the interpret dictionary to the compile dictionary</td></tr>
|
||||
<tr><td class="word">does></td><td class="signature">-- addr</td><td class="meaning">Defines the runtime behavior of a defining word (see the NovaForth guide)</td></tr>
|
||||
<tr><td class="word">' <em>word</em></td><td class="signature">-- addr</td><td class="meaning">Consumes a word, looks it up in the dictionary, and returns its address</td></tr>
|
||||
<tr><td class="word">[']</td><td class="signature">-- addr</td><td class="meaning">Consumes a word at runtime, looks it up in the dictionary, and returns its address</td></tr>
|
||||
</table>
|
||||
<h4>Miscellaneous</h4>
|
||||
<table>
|
||||
<tr><td class="word">\</td><td class="signature">--</td><td class="meaning">Begins a comment that lasts to the end of the line</td></tr>
|
||||
<tr><td class="word">(</td><td class="signature">--</td><td class="meaning">Begins a comment that lasts to the matching close paren</td></tr>
|
||||
</table>
|
||||
<h4>Prelude</h4>
|
||||
<p>These definitions are run when the console is loaded:</p>
|
||||
<pre class="prelude"></pre>
|
||||
<hr/>
|
||||
<p>This early-access demo was created by <a href="mailto:ross.andrews@gmail.com">Ross Andrews</a> in January 2023</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,89 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
use vcore::{CPU, Word};
|
||||
use vcore::memory::{PeekPoke, PeekPokeExt};
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct NovaForth;
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl NovaForth {
|
||||
pub fn rom() -> Vec<u8> {
|
||||
Vec::from(*include_bytes!("../4th/4th.rom"))
|
||||
}
|
||||
|
||||
pub fn symbols() -> String {
|
||||
include_str!("../4th/4th.rom.sym").into()
|
||||
}
|
||||
pub fn prelude() -> String { include_str!("../4th/prelude.f").into() }
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct WasmCPU(CPU);
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl WasmCPU {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> WasmCPU {
|
||||
WasmCPU(CPU::new_random())
|
||||
}
|
||||
|
||||
pub fn push_data(&mut self, data: i32) {
|
||||
self.0.push_data(data)
|
||||
}
|
||||
|
||||
pub fn pop_data(&mut self) -> i32 {
|
||||
self.0.pop_data().into()
|
||||
}
|
||||
|
||||
pub fn push_call(&mut self, data: i32) {
|
||||
self.0.push_call(data)
|
||||
}
|
||||
|
||||
pub fn pop_call(&mut self) -> i32 {
|
||||
self.0.pop_call().into()
|
||||
}
|
||||
|
||||
pub fn poke(&mut self, addr: u32, val: u8) {
|
||||
self.0.poke(addr.into(), val.into())
|
||||
}
|
||||
|
||||
pub fn peek(&self, addr: u32) -> u8 {
|
||||
self.0.peek(addr.into()).into()
|
||||
}
|
||||
|
||||
pub fn poke24(&mut self, addr: u32, val: i32) {
|
||||
self.0.poke24(Word::from(addr), Word::from(val))
|
||||
}
|
||||
|
||||
pub fn peek24(&self, addr: u32) -> i32 {
|
||||
self.0.peek24(Word::from(addr)).into()
|
||||
}
|
||||
|
||||
pub fn pc(&self) -> u32 {
|
||||
self.0.pc().into()
|
||||
}
|
||||
|
||||
pub fn sp(&self) -> u32 {
|
||||
self.0.sp().into()
|
||||
}
|
||||
|
||||
pub fn dp(&self) -> u32 {
|
||||
self.0.dp().into()
|
||||
}
|
||||
|
||||
pub fn set_pc(&mut self, val: u32) {
|
||||
self.0.set_pc(Word::from(val))
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
self.0.run_to_halt()
|
||||
}
|
||||
|
||||
pub fn load(&mut self, rom: Vec<u8>) {
|
||||
for (i, b) in rom.iter().enumerate() {
|
||||
self.poke(0x400 + i as u32, *b)
|
||||
}
|
||||
|
||||
self.set_pc(0x400)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user