adding test for embed
This commit is contained in:
parent
0f8a720fe8
commit
af147b3cb6
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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: ") {
|
||||
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()
|
||||
.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)]
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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(())
|
||||
|
|
Loading…
Reference in a new issue