adding test for embed
This commit is contained in:
parent
0f8a720fe8
commit
af147b3cb6
|
@ -104,3 +104,14 @@ button {
|
||||||
button:hover:not(:active) {
|
button:hover:not(:active) {
|
||||||
background: white;
|
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{WebAssembly.Instance}*/ let fmtInstance;
|
||||||
/**@type{Promise<WebAssembly.WebAssemblyInstantiatedSource>}*/ let fmtInstaceFuture;
|
/**@type{Promise<WebAssembly.WebAssemblyInstantiatedSource>}*/ let fmtInstaceFuture;
|
||||||
/** @param {string} code @param {"fmt" | "minify"} action
|
async function getFmtInstance() {
|
||||||
* @returns {Promise<string>} */
|
|
||||||
async function modifyCode(code, action) {
|
|
||||||
fmtInstaceFuture ??= WebAssembly.instantiateStreaming(fetch("/hbfmt.wasm"), {});
|
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 {
|
let {
|
||||||
INPUT, INPUT_LEN,
|
INPUT, INPUT_LEN,
|
||||||
OUTPUT, OUTPUT_LEN,
|
OUTPUT, OUTPUT_LEN,
|
||||||
memory, fmt, minify
|
memory, fmt, minify
|
||||||
} = fmtInstance.exports;
|
} = instance.exports;
|
||||||
|
|
||||||
if (!(true
|
if (!(true
|
||||||
&& memory instanceof WebAssembly.Memory
|
&& memory instanceof WebAssembly.Memory
|
||||||
|
@ -71,15 +73,15 @@ async function modifyCode(code, action) {
|
||||||
dw.setUint32(INPUT_LEN.value, code.length, true);
|
dw.setUint32(INPUT_LEN.value, code.length, true);
|
||||||
new Uint8Array(memory.buffer, INPUT.value).set(new TextEncoder().encode(code));
|
new Uint8Array(memory.buffer, INPUT.value).set(new TextEncoder().encode(code));
|
||||||
|
|
||||||
return runWasmFunction(fmtInstance, action === "fmt" ? fmt : minify) ?
|
return runWasmFunction(instance, action === "fmt" ? fmt : minify) ?
|
||||||
bufToString(memory, OUTPUT, OUTPUT_LEN) : "invalid code";
|
bufToString(memory, OUTPUT, OUTPUT_LEN) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @param {WebAssembly.Instance} instance @param {CallableFunction} func @param {any[]} args
|
/** @param {WebAssembly.Instance} instance @param {CallableFunction} func @param {any[]} args
|
||||||
* @returns {boolean} */
|
* @returns {boolean} */
|
||||||
function runWasmFunction(instance, func, ...args) {
|
function runWasmFunction(instance, func, ...args) {
|
||||||
const prev = performance.now();
|
//const prev = performance.now();
|
||||||
const { PANIC_MESSAGE, PANIC_MESSAGE_LEN, memory, stack_pointer } = instance.exports;
|
const { PANIC_MESSAGE, PANIC_MESSAGE_LEN, memory, stack_pointer } = instance.exports;
|
||||||
if (!(true
|
if (!(true
|
||||||
&& memory instanceof WebAssembly.Memory
|
&& memory instanceof WebAssembly.Memory
|
||||||
|
@ -101,7 +103,7 @@ function runWasmFunction(instance, func, ...args) {
|
||||||
stack_pointer.value = ptr;
|
stack_pointer.value = ptr;
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} 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 }} */
|
/** @type {{ [key: string]: (content: string) => Promise<string> | string }} */
|
||||||
const applyFns = {
|
const applyFns = {
|
||||||
timestamp: (content) => new Date(parseInt(content) * 1000).toLocaleString(),
|
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 */
|
/** @param {HTMLElement} target */
|
||||||
async function bindCodeEdit(target) {
|
async function bindCodeEdit(target) {
|
||||||
const edit = target.querySelector("#code-edit");
|
const edit = target.querySelector("#code-edit");
|
||||||
if (!(edit instanceof HTMLTextAreaElement)) return;
|
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");
|
const errors = target.querySelector("#compiler-output");
|
||||||
if (!(errors instanceof HTMLPreElement)) never();
|
if (!(errors instanceof HTMLPreElement)) never();
|
||||||
|
|
||||||
const hbc = await getHbcInstance();
|
const hbc = await getHbcInstance();
|
||||||
|
const fmt = await getFmtInstance();
|
||||||
|
|
||||||
const debounce = 100;
|
const debounce = 100;
|
||||||
let timeout = 0;
|
let timeout = 0;
|
||||||
|
@ -166,9 +173,14 @@ async function bindCodeEdit(target) {
|
||||||
timeout = setTimeout(() => {
|
timeout = setTimeout(() => {
|
||||||
const buf = packPosts([
|
const buf = packPosts([
|
||||||
{ path: "local.hb", code: edit.value },
|
{ path: "local.hb", code: edit.value },
|
||||||
{ path: "lam.hb", code: "foo:=10" },
|
|
||||||
]);
|
]);
|
||||||
errors.textContent = compileCode(hbc, buf, 1);
|
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;
|
timeout = 0;
|
||||||
}, debounce);
|
}, debounce);
|
||||||
});
|
});
|
||||||
|
@ -246,8 +258,9 @@ if (window.location.hostname === 'localhost') {
|
||||||
(async function test() {
|
(async function test() {
|
||||||
{
|
{
|
||||||
const code = "main:=fn():void{return}";
|
const code = "main:=fn():void{return}";
|
||||||
const fmtd = await modifyCode(code, "fmt") ?? never();
|
const inst = await getFmtInstance()
|
||||||
const prev = await modifyCode(fmtd, "minify") ?? never();
|
const fmtd = modifyCode(inst, code, "fmt") ?? never();
|
||||||
|
const prev = modifyCode(inst, fmtd, "minify") ?? never();
|
||||||
if (code != prev) console.error(code, prev);
|
if (code != prev) console.error(code, prev);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,7 @@ use {
|
||||||
|
|
||||||
const MAX_NAME_LENGTH: usize = 32;
|
const MAX_NAME_LENGTH: usize = 32;
|
||||||
const MAX_POSTNAME_LENGTH: usize = 64;
|
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;
|
const SESSION_DURATION_SECS: u64 = 60 * 60;
|
||||||
|
|
||||||
type Redirect<const COUNT: usize = 1> = AppendHeaders<[(&'static str, &'static str); COUNT]>;
|
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="author" type="text" value={session.name} hidden>
|
||||||
<input name="name" type="text" placeholder="name" value=name
|
<input name="name" type="text" placeholder="name" value=name
|
||||||
required maxlength=MAX_POSTNAME_LENGTH>
|
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">
|
<input type="submit" value="submit">
|
||||||
<pre id="compiler-output"></pre>
|
<pre id="compiler-output"></pre>
|
||||||
</form>
|
</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)
|
align_of_Type_in_bytes := @alignof(foo.Type)
|
||||||
hardcoded_pointer := @as(^u8, @bitcast(10))
|
hardcoded_pointer := @as(^u8, @bitcast(10))
|
||||||
ecall_that_returns_int := @as(int, @eca(1, foo.Type.(10, 20), 5, 6))
|
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)
|
return @inline(foo.foo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,6 +263,9 @@ Type := struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
foo := fn(): int return 0
|
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:
|
- `@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,
|
TypedReloc, Types, HEADER_SIZE,
|
||||||
},
|
},
|
||||||
alloc::{boxed::Box, string::String, vec::Vec},
|
alloc::{boxed::Box, string::String, vec::Vec},
|
||||||
core::{fmt::Display, u16},
|
core::fmt::Display,
|
||||||
};
|
};
|
||||||
|
|
||||||
type Offset = u32;
|
type Offset = u32;
|
||||||
|
@ -2843,8 +2843,9 @@ mod tests {
|
||||||
_ = log::set_logger(&crate::fs::Logger);
|
_ = log::set_logger(&crate::fs::Logger);
|
||||||
log::set_max_level(log::LevelFilter::Debug);
|
log::set_max_level(log::LevelFilter::Debug);
|
||||||
|
|
||||||
let mut codegen =
|
let (files, embeds) = crate::test_parse_files(ident, input);
|
||||||
super::Codegen { files: crate::test_parse_files(ident, input), ..Default::default() };
|
let mut codegen = super::Codegen { files, ..Default::default() };
|
||||||
|
codegen.push_embeds(embeds);
|
||||||
|
|
||||||
codegen.generate(0);
|
codegen.generate(0);
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
|
|
|
@ -41,7 +41,6 @@ use {
|
||||||
core::{cell::Cell, ops::Range},
|
core::{cell::Cell, ops::Range},
|
||||||
hashbrown::hash_map,
|
hashbrown::hash_map,
|
||||||
hbbytecode as instrs,
|
hbbytecode as instrs,
|
||||||
std::println,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -1081,7 +1080,6 @@ impl Types {
|
||||||
match entry {
|
match entry {
|
||||||
hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value,
|
hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value,
|
||||||
hash_map::RawEntryMut::Vacant(v) => {
|
hash_map::RawEntryMut::Vacant(v) => {
|
||||||
println!("waht");
|
|
||||||
self.ins.ptrs.push(ptr);
|
self.ins.ptrs.push(ptr);
|
||||||
v.insert(
|
v.insert(
|
||||||
ctx_map::Key {
|
ctx_map::Key {
|
||||||
|
@ -1345,7 +1343,7 @@ pub fn run_test(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(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 {
|
use {
|
||||||
self::parser::FileKind,
|
self::parser::FileKind,
|
||||||
std::{borrow::ToOwned, string::ToString},
|
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 input = find_block(input, ident);
|
||||||
|
|
||||||
let mut module_map = Vec::new();
|
let mut module_map = Vec::new();
|
||||||
|
let mut embed_map = Vec::new();
|
||||||
let mut last_start = 0;
|
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: ") {
|
for (i, m) in input.match_indices("// in module: ") {
|
||||||
fmt::test::format(ident, input[last_start..i].trim());
|
if last_module_name.ends_with(".hb") {
|
||||||
module_map.push((last_module_name, &input[last_start..i]));
|
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();
|
let (module_name, _) = input[i + m.len()..].split_once('\n').unwrap();
|
||||||
last_module_name = module_name;
|
last_module_name = module_name;
|
||||||
last_start = i + m.len() + module_name.len() + 1;
|
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| {
|
if last_module_name.ends_with(".hb") {
|
||||||
assert_eq!(kind, FileKind::Module);
|
fmt::test::format(ident, input[last_start..].trim());
|
||||||
module_map
|
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()
|
.iter()
|
||||||
.position(|&(name, _)| name == path)
|
.position(|&(name, _)| name == path)
|
||||||
.map(|i| i as parser::FileId)
|
.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();
|
let mut ctx = parser::ParserCtx::default();
|
||||||
module_map
|
(
|
||||||
.iter()
|
module_map
|
||||||
.map(|&(path, content)| parser::Ast::new(path, content.to_owned(), &mut ctx, &mut loader))
|
.iter()
|
||||||
.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)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -2861,8 +2861,8 @@ mod tests {
|
||||||
_ = log::set_logger(&crate::fs::Logger);
|
_ = log::set_logger(&crate::fs::Logger);
|
||||||
log::set_max_level(log::LevelFilter::Info);
|
log::set_max_level(log::LevelFilter::Info);
|
||||||
|
|
||||||
let mut codegen =
|
let (files, _embeds) = crate::test_parse_files(ident, input);
|
||||||
super::Codegen { files: crate::test_parse_files(ident, input), ..Default::default() };
|
let mut codegen = super::Codegen { files, ..Default::default() };
|
||||||
|
|
||||||
codegen.generate();
|
codegen.generate();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
main:
|
main:
|
||||||
ADDI64 r254, r254, -88d
|
ADDI64 r254, r254, -96d
|
||||||
ST r31, r254, 16a, 72h
|
ST r31, r254, 16a, 80h
|
||||||
LI64 r32, 10d
|
LI64 r32, 10d
|
||||||
LI64 r33, 30d
|
LI64 r33, 30d
|
||||||
LI64 r34, 40d
|
LI64 r34, 40d
|
||||||
|
@ -18,11 +18,13 @@ main:
|
||||||
LI64 r6, 6d
|
LI64 r6, 6d
|
||||||
ECA
|
ECA
|
||||||
CP r39, r1
|
CP r39, r1
|
||||||
|
LRA r40, r0, :arbitrary text
|
||||||
|
|
||||||
LI64 r1, 0d
|
LI64 r1, 0d
|
||||||
LD r31, r254, 16a, 72h
|
LD r31, r254, 16a, 80h
|
||||||
ADDI64 r254, r254, 88d
|
ADDI64 r254, r254, 96d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
ev: Ecall
|
ev: Ecall
|
||||||
code size: 233
|
code size: 255
|
||||||
ret: 0
|
ret: 0
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
|
@ -6,20 +6,31 @@ drop:
|
||||||
ADDI64 r254, r254, 16d
|
ADDI64 r254, r254, 16d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
main:
|
main:
|
||||||
ADDI64 r254, r254, -40d
|
ADDI64 r254, r254, -48d
|
||||||
ST r31, r254, 8a, 32h
|
ST r31, r254, 8a, 40h
|
||||||
LI64 r32, 1d
|
LI64 r32, 1d
|
||||||
ST r32, r254, 0a, 8h
|
ST r32, r254, 0a, 8h
|
||||||
ADDI64 r32, r254, 0d
|
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
|
CP r2, r32
|
||||||
JAL r31, r0, :modify
|
JAL r31, r0, :modify
|
||||||
LD r2, r254, 0a, 8h
|
LD r2, r254, 0a, 8h
|
||||||
JAL r31, r0, :drop
|
JAL r31, r0, :drop
|
||||||
CP r33, r32
|
CP r34, r32
|
||||||
LD r34, r33, 0a, 8h
|
LD r35, r34, 0a, 8h
|
||||||
ADDI64 r1, r34, -2d
|
ADDI64 r1, r35, -2d
|
||||||
LD r31, r254, 8a, 32h
|
LD r31, r254, 8a, 40h
|
||||||
ADDI64 r254, r254, 40d
|
ADDI64 r254, r254, 48d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
modify:
|
modify:
|
||||||
ADDI64 r254, r254, -32d
|
ADDI64 r254, r254, -32d
|
||||||
|
@ -31,6 +42,6 @@ modify:
|
||||||
LD r31, r254, 0a, 32h
|
LD r31, r254, 0a, 32h
|
||||||
ADDI64 r254, r254, 32d
|
ADDI64 r254, r254, 32d
|
||||||
JALA r0, r31, 0a
|
JALA r0, r31, 0a
|
||||||
code size: 308
|
code size: 382
|
||||||
ret: 0
|
ret: 0
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
Loading…
Reference in a new issue