Skip to content

Commit 3e470f1

Browse files
committed
early support for user input
1 parent a50bf2a commit 3e470f1

File tree

1 file changed

+89
-15
lines changed

1 file changed

+89
-15
lines changed

demo/index.html

Lines changed: 89 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
margin: 0;
2828
padding: 0;
2929
border: none;
30-
+fieldset {margin-top: .5rem;}
30+
+ fieldset {margin-top: .5rem;}
3131
}
3232
pre {
3333
overflow-y: scroll;
@@ -47,30 +47,48 @@ <h1>agda2lambox</h1>
4747
<button id="run" disabled>Run</button>
4848
<button id="reload" disabled>Reload</button>
4949
<button id="clear">Clear</button>
50+
<input type="file" id="file" />
51+
</fieldset>
52+
<fieldset>
53+
<label for="useinput">Input</label>
54+
<input type="checkbox" id="useinput">
55+
<input type="text" id="input">
56+
<select id="encoder">
57+
<option value="bool">Bool</option>
58+
</select>
59+
</fieldset>
60+
<fieldset>
61+
Output
5062
<select id="decoder">
5163
<option value="nat">Nat</option>
5264
<option value="bool">Bool</option>
5365
<option value="listnat">List Nat</option>
5466
<option value="listbool">List Bool</option>
5567
<option value="string">String (List Nat)</option>
5668
</select>
57-
<input type="file" id="file" />
69+
</fieldset>
70+
<fieldset>
71+
Function
72+
<select id="program"></select>
5873
</fieldset>
5974
</header>
6075
<pre><code id="output"></code></pre>
6176
<script type="module">
6277
const on = (t, e, f) => t.addEventListener(e, f)
6378

64-
run.disabled = true
65-
reload.disabled = true
79+
run.disabled = reload.disabled = true
80+
input.disabled = encoder.disabled = !useinput.checked
81+
on(useinput, "change", () => input.disabled = encoder.disabled = !useinput.checked)
6682

67-
let wasm = null
68-
let mem = null
83+
let wasm = null
84+
let mem_ptr = null
85+
let mem = null
86+
let exposed = null
6987

7088
on(file, "change", load)
7189
on(reload, "click", load)
7290
on(run, "click", exec)
73-
on(clear, "click", () => {output.innerHTML = ""})
91+
on(clear, "click", () => output.innerHTML = "")
7492

7593
async function load() {
7694
if (file.files.length == 0) return
@@ -84,13 +102,30 @@ <h1>agda2lambox</h1>
84102
wasm =
85103
await blob.arrayBuffer()
86104
.then(buf => {
87-
log("Compiling...")
88-
return WebAssembly.compile(buf)
89-
})
105+
log("Compiling...")
106+
return WebAssembly.compile(buf)
107+
})
90108
.then(mod => new WebAssembly.Instance(mod))
91109

110+
mem_ptr = wasm.exports.mem_ptr
111+
mem = wasm.exports.memory.buffer
112+
92113
log(`Compiled!`)
93114

115+
exposed =
116+
Object.keys(wasm.exports)
117+
.filter(key => typeof wasm.exports[key] == 'function')
118+
119+
// update available function list
120+
program.textContent = ''
121+
exposed.forEach(fn => {
122+
let opt = document.createElement('option')
123+
opt.value = fn
124+
// show arity
125+
opt.textContent = `${fn} (${wasm.exports[fn].length})`
126+
program.appendChild(opt)
127+
})
128+
94129
run.disabled = false
95130
reload.disabled = false
96131

@@ -100,15 +135,24 @@ <h1>agda2lambox</h1>
100135
}
101136

102137
async function exec() {
103-
log("Running main_function()")
138+
log(`Running ${program.value}`)
139+
140+
let fn = wasm.exports[program.value]
104141

105142
try {
106-
wasm.exports.main_function()
143+
if (useinput.checked) {
144+
let val = eval(input.value)
145+
let enc = encoders[encoder.value]
146+
let res = enc(val)
147+
fn(res)
148+
}
149+
else {
150+
fn()
151+
}
107152

108-
mem = new Uint32Array(wasm.exports.memory.buffer)
109153
let res = wasm.exports.result.value
110154
let dec = decoders[decoder.value]
111-
// mem = new Uint32Array(wasm.exports.memory.buffer)
155+
112156
log(`Result: ${pretty(dec(res))}`)
113157
} catch (e) {
114158
log(`Failed to run: ${e}`, true)
@@ -137,7 +181,19 @@ <h1>agda2lambox</h1>
137181

138182
// custom decoders -------------------------
139183

140-
const bool = value => (value >> 1) == 1
184+
/* "CertiCoq-Wasm’s representation of
185+
a 𝜆ANF constructor value 𝐶(𝑣s) is based on the one used by
186+
CertiCoq’s C backend [ 41, §4.1], which in turn is based on the
187+
one used by the OCaml compiler. For efficiency, we represent
188+
nullary constructor values as unboxed i32 values (using 31
189+
bits), while non-nullary constructor values are boxed: they
190+
are represented by an address starting from which linear
191+
memory contains the code of the constructor, followed by
192+
the arguments. The least significant bit of the i32 is used to
193+
distinguish the two."
194+
*/
195+
196+
const bool = value => (value >> 1) == 1
141197

142198
const nat = value => {
143199
let acc = 0
@@ -170,6 +226,24 @@ <h1>agda2lambox</h1>
170226
, listbool: list(bool)
171227
, string
172228
}
229+
230+
// custom encoders -------------------------------
231+
232+
/*
233+
NOTE: for now, encoders happily write in the memory buffer,
234+
and update the mem_ptr.
235+
TODO: proper memory mgmt, where the linear memory is expanded if
236+
we run out of memory.
237+
238+
- All encoders take a JS value as input,
239+
- They write it in memory starting from mem_ptr.
240+
- They update mem_ptr to point to the next available location.
241+
- They return a value to be given to programs.
242+
(Likely to be the a pointer, but not necessarily).
243+
*/
244+
const encoders =
245+
{ bool: v => v << 1 | 1
246+
}
173247
</script>
174248
</body>
175249
</html>

0 commit comments

Comments
 (0)