Skip to content

Commit 7661757

Browse files
stevedekorteclaude
andcommitted
Add Live Interpreter page at /repl/ with card on the home page
A public-facing Io REPL in the style of dekorte.com/projects/aiapps: chat-like transcript (input echoes right, VM output left, exceptions in error bubbles), one-click examples including live DOM manipulation via the JS bridge, and a collapsible How It Works section. The page reuses browser/io.js and io_browser.wasm — io.js gains a window.IO_WASM_URL override so pages outside browser/ can locate the wasm. io_browser.c now tracks top-level exceptions with a flag (set by the exception callback) so do_eval can return status 1; previously IoState_tryToPerform cleared errorRaised after printing, so uncaught exceptions reported success and rendered as normal results. The Pages workflow installs wasi-sdk and runs `make browser` so the gitignored wasm is built for deploys, and repl/browser/Links paths now trigger it. Home page card added to _index.json; static HTML regenerated (the prefetch blob embeds the root index, hence the sweep across generated pages). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 5c987b4 commit 7661757

105 files changed

Lines changed: 366 additions & 103 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/pages.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ on:
1414
- 'FAQ/**'
1515
- 'Timeline/**'
1616
- 'images/**'
17+
- 'Links/**'
18+
- 'repl/**'
19+
- 'browser/**'
1720
- '.github/workflows/pages.yml'
1821
workflow_dispatch:
1922

@@ -29,6 +32,9 @@ concurrency:
2932
jobs:
3033
build:
3134
runs-on: ubuntu-latest
35+
env:
36+
WASI_SDK_VERSION: "24"
37+
WASI_SDK_FULL: "24.0"
3238
steps:
3339
- uses: actions/checkout@v4
3440
with:
@@ -41,6 +47,16 @@ jobs:
4147
- name: Regenerate static HTML
4248
run: node colvmn/static-gen.js
4349

50+
- name: Install wasi-sdk
51+
run: |
52+
mkdir -p "$HOME/wasi-sdk"
53+
curl -L -o /tmp/wasi-sdk.tar.gz \
54+
"https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_FULL}-x86_64-linux.tar.gz"
55+
tar -xzf /tmp/wasi-sdk.tar.gz -C "$HOME/wasi-sdk" --strip-components=1
56+
57+
- name: Build browser WASM (for /repl/ live interpreter)
58+
run: make browser WASI_SDK="$HOME/wasi-sdk"
59+
4460
- name: Upload Pages artifact
4561
uses: actions/upload-pages-artifact@v3
4662
with:

FAQ/index.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

Links/index.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

Timeline/index.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

_index.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717
"type": "ContentCards",
1818
"columns": 2,
1919
"items": [
20+
{
21+
"title": "Live Interpreter",
22+
"href": "repl/index.html",
23+
"subtitle": "Try Io right now — the full VM compiled to WebAssembly, running in your browser."
24+
},
2025
{
2126
"title": "Documentation",
2227
"href": "docs/index.html",

browser/README.md

Lines changed: 4 additions & 1 deletion

browser/io.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Io VM — Browser WASM loader + WASI shim + JS bridge + REPL logic
22

3-
const IO_WASM_URL = "io_browser.wasm";
3+
// Pages outside browser/ can point at the wasm by setting window.IO_WASM_URL
4+
// before loading this script.
5+
const IO_WASM_URL = (typeof window !== "undefined" && window.IO_WASM_URL) || "io_browser.wasm";
46

57
let wasm = null; // WebAssembly instance
68
let memory = null; // WASM linear memory

browser/io_browser.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,15 @@ static void browser_print_callback(void *context, const UArray *ba) {
6767
output_append((const char *)UArray_bytes(ba), UArray_size(ba));
6868
}
6969

70+
// Set when an uncaught exception reaches the top level during an eval.
71+
// IoState_tryToPerform clears state->errorRaised after reporting, so this
72+
// flag is the only way do_eval can tell the input failed.
73+
static int exception_raised = 0;
74+
7075
// Exception callback: capture exception text
7176
static void browser_exception_callback(void *context, IoObject *coroutine) {
7277
(void)context;
78+
exception_raised = 1;
7379
// Use the default backtrace printing — it goes through printCallback
7480
IoCoroutine_rawPrintBackTrace(coroutine);
7581
}
@@ -138,6 +144,7 @@ static int do_eval(const char *code) {
138144

139145
output_clear();
140146
state->errorRaised = 0;
147+
exception_raised = 0;
141148

142149
IoObject *result = IoState_doCString_(state, code);
143150

@@ -147,7 +154,7 @@ static int do_eval(const char *code) {
147154
return 2;
148155
}
149156

150-
if (state->errorRaised) {
157+
if (state->errorRaised || exception_raised) {
151158
return 1;
152159
}
153160

@@ -175,6 +182,7 @@ static int do_resume_eval(void) {
175182
IoObject *coro = state->suspendedCoro;
176183
state->suspendedCoro = NULL;
177184
state->awaitingJsPromise = 0;
185+
exception_raised = 0;
178186

179187
// Save current coro state
180188
IoObject *previousCoro = (IoObject *)state->currentCoroutine;
@@ -207,7 +215,7 @@ static int do_resume_eval(void) {
207215
}
208216

209217
output_clear();
210-
if (state->errorRaised) {
218+
if (state->errorRaised || exception_raised) {
211219
return 1;
212220
}
213221

docs/Book/Appendix/index.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

docs/Book/Concurrency/index.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)