adding test for embed

This commit is contained in:
Jakub Doka 2024-10-13 20:01:18 +02:00
parent 0f8a720fe8
commit af147b3cb6
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
10 changed files with 113 additions and 50 deletions

View file

@ -104,3 +104,14 @@ button {
button:hover:not(:active) {
background: white;
}
div#code-editor {
display: flex;
position: relative;
span#code-size {
position: absolute;
right: 2px;
font-size: 12px;
}
}

View file

@ -40,17 +40,19 @@ function compileCode(instance, code, fuel) {
/**@type{WebAssembly.Instance}*/ let fmtInstance;
/**@type{Promise<WebAssembly.WebAssemblyInstantiatedSource>}*/ let fmtInstaceFuture;
/** @param {string} code @param {"fmt" | "minify"} action
* @returns {Promise<string>} */
async function modifyCode(code, action) {
async function getFmtInstance() {
fmtInstaceFuture ??= WebAssembly.instantiateStreaming(fetch("/hbfmt.wasm"), {});
fmtInstance ??= (await fmtInstaceFuture).instance;
return fmtInstance ??= (await fmtInstaceFuture).instance;
}
/** @param {WebAssembly.Instance} instance @param {string} code @param {"fmt" | "minify"} action
* @returns {string | undefined} */
function modifyCode(instance, code, action) {
let {
INPUT, INPUT_LEN,
OUTPUT, OUTPUT_LEN,
memory, fmt, minify
} = fmtInstance.exports;
} = instance.exports;
if (!(true
&& memory instanceof WebAssembly.Memory
@ -71,15 +73,15 @@ async function modifyCode(code, action) {
dw.setUint32(INPUT_LEN.value, code.length, true);
new Uint8Array(memory.buffer, INPUT.value).set(new TextEncoder().encode(code));
return runWasmFunction(fmtInstance, action === "fmt" ? fmt : minify) ?
bufToString(memory, OUTPUT, OUTPUT_LEN) : "invalid code";
return runWasmFunction(instance, action === "fmt" ? fmt : minify) ?
bufToString(memory, OUTPUT, OUTPUT_LEN) : undefined;
}
/** @param {WebAssembly.Instance} instance @param {CallableFunction} func @param {any[]} args
* @returns {boolean} */
function runWasmFunction(instance, func, ...args) {
const prev = performance.now();
//const prev = performance.now();
const { PANIC_MESSAGE, PANIC_MESSAGE_LEN, memory, stack_pointer } = instance.exports;
if (!(true
&& memory instanceof WebAssembly.Memory
@ -101,7 +103,7 @@ function runWasmFunction(instance, func, ...args) {
stack_pointer.value = ptr;
return false;
} finally {
console.log("compiletion took:", performance.now() - prev);
//console.log("compiletion took:", performance.now() - prev);
}
}
@ -147,17 +149,22 @@ function wireUp(target) {
/** @type {{ [key: string]: (content: string) => Promise<string> | string }} */
const applyFns = {
timestamp: (content) => new Date(parseInt(content) * 1000).toLocaleString(),
fmt: (content) => modifyCode(content, "fmt").then(c => c),
fmt: (content) => getFmtInstance().then(i => modifyCode(i, content, "fmt") ?? "invalid code"),
};
/** @param {HTMLElement} target */
async function bindCodeEdit(target) {
const edit = target.querySelector("#code-edit");
if (!(edit instanceof HTMLTextAreaElement)) return;
const codeSize = target.querySelector("#code-size");
if (!(codeSize instanceof HTMLSpanElement)) never();
const MAX_CODE_SIZE = parseInt(codeSize.innerHTML);
if (Number.isNaN(MAX_CODE_SIZE)) never();
const errors = target.querySelector("#compiler-output");
if (!(errors instanceof HTMLPreElement)) never();
const hbc = await getHbcInstance();
const fmt = await getFmtInstance();
const debounce = 100;
let timeout = 0;
@ -166,9 +173,14 @@ async function bindCodeEdit(target) {
timeout = setTimeout(() => {
const buf = packPosts([
{ path: "local.hb", code: edit.value },
{ path: "lam.hb", code: "foo:=10" },
]);
errors.textContent = compileCode(hbc, buf, 1);
const minified_size = modifyCode(fmt, edit.value, "minify")?.length;
if (minified_size) {
codeSize.textContent = (MAX_CODE_SIZE - minified_size) + "";
const perc = Math.min(100, Math.floor(100 * (minified_size / MAX_CODE_SIZE)));
codeSize.style.color = `color-mix(in srgb, white, var(--error) ${perc}%)`;
}
timeout = 0;
}, debounce);
});
@ -246,8 +258,9 @@ if (window.location.hostname === 'localhost') {
(async function test() {
{
const code = "main:=fn():void{return}";
const fmtd = await modifyCode(code, "fmt") ?? never();
const prev = await modifyCode(fmtd, "minify") ?? never();
const inst = await getFmtInstance()
const fmtd = modifyCode(inst, code, "fmt") ?? never();
const prev = modifyCode(inst, fmtd, "minify") ?? never();
if (code != prev) console.error(code, prev);
}
{

View file

@ -12,7 +12,7 @@ use {
const MAX_NAME_LENGTH: usize = 32;
const MAX_POSTNAME_LENGTH: usize = 64;
//const MAX_CODE_LENGTH: usize = 1024 * 4;
const MAX_CODE_LENGTH: usize = 1024 * 4;
const SESSION_DURATION_SECS: u64 = 60 * 60;
type Redirect<const COUNT: usize = 1> = AppendHeaders<[(&'static str, &'static str); COUNT]>;
@ -153,7 +153,11 @@ impl Page for Post {
<input name="author" type="text" value={session.name} hidden>
<input name="name" type="text" placeholder="name" value=name
required maxlength=MAX_POSTNAME_LENGTH>
<textarea id="code-edit" name="code" placeholder="code" rows=1 required>code</textarea>
<div id="code-editor">
<textarea id="code-edit" name="code" placeholder="code" rows=1 required
style="flex: 1">code</textarea>
<span id="code-size">MAX_CODE_LENGTH</span>
</div>
<input type="submit" value="submit">
<pre id="compiler-output"></pre>
</form>

View file

@ -104,5 +104,5 @@ unsafe fn compile_and_run(mut fuel: usize) {
}
}
log::error!("memory consumption: {}b / {}b", ALLOCATOR.used(), ARENA_CAP);
//log::error!("memory consumption: {}b / {}b", ALLOCATOR.used(), ARENA_CAP);
}

View file

@ -251,6 +251,7 @@ main := fn(): int {
align_of_Type_in_bytes := @alignof(foo.Type)
hardcoded_pointer := @as(^u8, @bitcast(10))
ecall_that_returns_int := @as(int, @eca(1, foo.Type.(10, 20), 5, 6))
embedded_array := @as([u8; 15], @embed("text.txt"))
return @inline(foo.foo)
}
@ -262,6 +263,9 @@ Type := struct {
}
foo := fn(): int return 0
// in module: text.txt
arbitrary text
```
- `@use(<string>)`: imports a module based of string, the string is passed to a loader that can be customized, default loader uses following syntax:

View file

@ -12,7 +12,7 @@ use {
TypedReloc, Types, HEADER_SIZE,
},
alloc::{boxed::Box, string::String, vec::Vec},
core::{fmt::Display, u16},
core::fmt::Display,
};
type Offset = u32;
@ -2843,8 +2843,9 @@ mod tests {
_ = log::set_logger(&crate::fs::Logger);
log::set_max_level(log::LevelFilter::Debug);
let mut codegen =
super::Codegen { files: crate::test_parse_files(ident, input), ..Default::default() };
let (files, embeds) = crate::test_parse_files(ident, input);
let mut codegen = super::Codegen { files, ..Default::default() };
codegen.push_embeds(embeds);
codegen.generate(0);
let mut out = Vec::new();

View file

@ -41,7 +41,6 @@ use {
core::{cell::Cell, ops::Range},
hashbrown::hash_map,
hbbytecode as instrs,
std::println,
};
#[macro_use]
@ -1081,7 +1080,6 @@ impl Types {
match entry {
hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value,
hash_map::RawEntryMut::Vacant(v) => {
println!("waht");
self.ins.ptrs.push(ptr);
v.insert(
ctx_map::Key {
@ -1345,7 +1343,7 @@ pub fn run_test(
}
#[cfg(test)]
fn test_parse_files(ident: &'static str, input: &'static str) -> Vec<parser::Ast> {
fn test_parse_files(ident: &'static str, input: &'static str) -> (Vec<parser::Ast>, Vec<Vec<u8>>) {
use {
self::parser::FileKind,
std::{borrow::ToOwned, string::ToString},
@ -1377,32 +1375,51 @@ fn test_parse_files(ident: &'static str, input: &'static str) -> Vec<parser::Ast
let input = find_block(input, ident);
let mut module_map = Vec::new();
let mut embed_map = Vec::new();
let mut last_start = 0;
let mut last_module_name = "test";
let mut last_module_name = "test.hb";
for (i, m) in input.match_indices("// in module: ") {
fmt::test::format(ident, input[last_start..i].trim());
module_map.push((last_module_name, &input[last_start..i]));
if last_module_name.ends_with(".hb") {
fmt::test::format(ident, input[last_start..i].trim());
module_map.push((last_module_name, &input[last_start..i]));
} else {
embed_map.push((last_module_name, &input[last_start..i]));
}
let (module_name, _) = input[i + m.len()..].split_once('\n').unwrap();
last_module_name = module_name;
last_start = i + m.len() + module_name.len() + 1;
}
fmt::test::format(ident, input[last_start..].trim());
module_map.push((last_module_name, input[last_start..].trim()));
let mut loader = |path: &str, _: &str, kind| {
assert_eq!(kind, FileKind::Module);
module_map
if last_module_name.ends_with(".hb") {
fmt::test::format(ident, input[last_start..].trim());
module_map.push((last_module_name, &input[last_start..]));
} else {
embed_map.push((last_module_name, &input[last_start..]));
}
let mut loader = |path: &str, _: &str, kind| match kind {
FileKind::Module => module_map
.iter()
.position(|&(name, _)| name == path)
.map(|i| i as parser::FileId)
.ok_or("Not Found".to_string())
.ok_or("Module Not Found".to_string()),
FileKind::Embed => embed_map
.iter()
.position(|&(name, _)| name == path)
.map(|i| i as parser::FileId)
.ok_or("Embed Not Found".to_string()),
};
let mut ctx = parser::ParserCtx::default();
module_map
.iter()
.map(|&(path, content)| parser::Ast::new(path, content.to_owned(), &mut ctx, &mut loader))
.collect()
(
module_map
.iter()
.map(|&(path, content)| {
parser::Ast::new(path, content.to_owned(), &mut ctx, &mut loader)
})
.collect(),
embed_map.iter().map(|&(_, content)| content.to_owned().into_bytes()).collect(),
)
}
#[cfg(test)]

View file

@ -2861,8 +2861,8 @@ mod tests {
_ = log::set_logger(&crate::fs::Logger);
log::set_max_level(log::LevelFilter::Info);
let mut codegen =
super::Codegen { files: crate::test_parse_files(ident, input), ..Default::default() };
let (files, _embeds) = crate::test_parse_files(ident, input);
let mut codegen = super::Codegen { files, ..Default::default() };
codegen.generate();

View file

@ -1,6 +1,6 @@
main:
ADDI64 r254, r254, -88d
ST r31, r254, 16a, 72h
ADDI64 r254, r254, -96d
ST r31, r254, 16a, 80h
LI64 r32, 10d
LI64 r33, 30d
LI64 r34, 40d
@ -18,11 +18,13 @@ main:
LI64 r6, 6d
ECA
CP r39, r1
LRA r40, r0, :arbitrary text
LI64 r1, 0d
LD r31, r254, 16a, 72h
ADDI64 r254, r254, 88d
LD r31, r254, 16a, 80h
ADDI64 r254, r254, 96d
JALA r0, r31, 0a
ev: Ecall
code size: 233
code size: 255
ret: 0
status: Ok(())

View file

@ -6,20 +6,31 @@ drop:
ADDI64 r254, r254, 16d
JALA r0, r31, 0a
main:
ADDI64 r254, r254, -40d
ST r31, r254, 8a, 32h
ADDI64 r254, r254, -48d
ST r31, r254, 8a, 40h
LI64 r32, 1d
ST r32, r254, 0a, 8h
ADDI64 r32, r254, 0d
LI64 r33, 1000d
CP r34, r32
CP r35, r33
MULI64 r35, r35, 8d
ADD64 r34, r34, r35
ADDI64 r32, r34, -16d
CP r34, r33
ADDI64 r34, r34, -2d
CP r35, r34
MULI64 r35, r35, 8d
SUB64 r32, r32, r35
CP r2, r32
JAL r31, r0, :modify
LD r2, r254, 0a, 8h
JAL r31, r0, :drop
CP r33, r32
LD r34, r33, 0a, 8h
ADDI64 r1, r34, -2d
LD r31, r254, 8a, 32h
ADDI64 r254, r254, 40d
CP r34, r32
LD r35, r34, 0a, 8h
ADDI64 r1, r35, -2d
LD r31, r254, 8a, 40h
ADDI64 r254, r254, 48d
JALA r0, r31, 0a
modify:
ADDI64 r254, r254, -32d
@ -31,6 +42,6 @@ modify:
LD r31, r254, 0a, 32h
ADDI64 r254, r254, 32d
JALA r0, r31, 0a
code size: 308
code size: 382
ret: 0
status: Ok(())