Compare commits
No commits in common. "a64383e72b0920ef1c03773aac197404c78b330f" and "13714eb5135fd043f0b15dbfcf9490bac8b042db" have entirely different histories.
a64383e72b
...
13714eb513
|
@ -141,24 +141,3 @@ div#dep-list {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fmt {
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
.syn {
|
|
||||||
font-family: monospace;
|
|
||||||
&.Comment { color: #939f91; }
|
|
||||||
&.Keyword { color: #f85552; }
|
|
||||||
&.Identifier { color: #3a94c5; }
|
|
||||||
&.Directive { color: #3a94c5; }
|
|
||||||
&.Number {}
|
|
||||||
&.String { color: #8da101; }
|
|
||||||
&.Op { color: #f57d26; }
|
|
||||||
&.Assign { color: #f57d26; }
|
|
||||||
&.Paren { color: #5c6a72; }
|
|
||||||
&.Bracket { color: #5c6a72; }
|
|
||||||
&.Colon { color: #5c6a72; }
|
|
||||||
&.Comma { color: #5c6a72; }
|
|
||||||
&.Dot { color: #5c6a72; }
|
|
||||||
&.Ctor { color: #3a94c5; }
|
|
||||||
}
|
|
||||||
|
|
|
@ -50,20 +50,18 @@ function modifyCode(instance, code, action) {
|
||||||
let {
|
let {
|
||||||
INPUT, INPUT_LEN,
|
INPUT, INPUT_LEN,
|
||||||
OUTPUT, OUTPUT_LEN,
|
OUTPUT, OUTPUT_LEN,
|
||||||
memory, fmt, tok, minify
|
memory, fmt, minify
|
||||||
} = instance.exports;
|
} = instance.exports;
|
||||||
|
|
||||||
let funs = { fmt, tok, minify };
|
|
||||||
if (!(true
|
if (!(true
|
||||||
&& memory instanceof WebAssembly.Memory
|
&& memory instanceof WebAssembly.Memory
|
||||||
&& INPUT instanceof WebAssembly.Global
|
&& INPUT instanceof WebAssembly.Global
|
||||||
&& INPUT_LEN instanceof WebAssembly.Global
|
&& INPUT_LEN instanceof WebAssembly.Global
|
||||||
&& OUTPUT instanceof WebAssembly.Global
|
&& OUTPUT instanceof WebAssembly.Global
|
||||||
&& OUTPUT_LEN instanceof WebAssembly.Global
|
&& OUTPUT_LEN instanceof WebAssembly.Global
|
||||||
&& funs.hasOwnProperty(action)
|
&& typeof fmt === "function"
|
||||||
&& typeof funs[action] === "function"
|
&& typeof minify === "function"
|
||||||
)) never();
|
)) never();
|
||||||
let fun = funs[action];
|
|
||||||
|
|
||||||
if (action !== "fmt") {
|
if (action !== "fmt") {
|
||||||
INPUT = OUTPUT;
|
INPUT = OUTPUT;
|
||||||
|
@ -74,14 +72,8 @@ function modifyCode(instance, 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));
|
||||||
|
|
||||||
if (!runWasmFunction(instance, fun)) {
|
return runWasmFunction(instance, action === "fmt" ? fmt : minify) ?
|
||||||
return undefined;
|
bufToString(memory, OUTPUT, OUTPUT_LEN) : undefined;
|
||||||
}
|
|
||||||
if (action === "tok") {
|
|
||||||
return bufSlice(memory, OUTPUT, OUTPUT_LEN);
|
|
||||||
} else {
|
|
||||||
return bufToString(memory, OUTPUT, OUTPUT_LEN);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,15 +119,6 @@ function packPosts(posts, view) {
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {WebAssembly.Memory} mem
|
|
||||||
* @param {WebAssembly.Global} ptr
|
|
||||||
* @param {WebAssembly.Global} len
|
|
||||||
* @return {Uint8Array} */
|
|
||||||
function bufSlice(mem, ptr, len) {
|
|
||||||
return new Uint8Array(mem.buffer, ptr.value,
|
|
||||||
new DataView(mem.buffer).getUint32(len.value, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param {WebAssembly.Memory} mem
|
/** @param {WebAssembly.Memory} mem
|
||||||
* @param {WebAssembly.Global} ptr
|
* @param {WebAssembly.Global} ptr
|
||||||
* @param {WebAssembly.Global} len
|
* @param {WebAssembly.Global} len
|
||||||
|
@ -282,80 +265,19 @@ async function bindCodeEdit(target) {
|
||||||
edit.dispatchEvent(new InputEvent("input"));
|
edit.dispatchEvent(new InputEvent("input"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** @type {{ [key: string]: (content: string) => Promise<string> | string }} */
|
||||||
* @type {{ Array<string> }}
|
|
||||||
* to be synched with `enum TokenGroup` in bytecode/src/fmt.rs */
|
|
||||||
const TOK_CLASSES = [
|
|
||||||
'Blank',
|
|
||||||
'Comment',
|
|
||||||
'Keyword',
|
|
||||||
'Identifier',
|
|
||||||
'Directive',
|
|
||||||
'Number',
|
|
||||||
'String',
|
|
||||||
'Op',
|
|
||||||
'Assign',
|
|
||||||
'Paren',
|
|
||||||
'Bracket',
|
|
||||||
'Colon',
|
|
||||||
'Comma',
|
|
||||||
'Dot',
|
|
||||||
'Ctor',
|
|
||||||
];
|
|
||||||
|
|
||||||
/** @type {{ [key: string]: (el: HTMLElement) => undefined | Promise<undefined> }} */
|
|
||||||
const applyFns = {
|
const applyFns = {
|
||||||
timestamp: (el) => {
|
timestamp: (content) => new Date(parseInt(content) * 1000).toLocaleString(),
|
||||||
const timestamp = el.innerText;
|
fmt: (content) => getFmtInstance().then(i => modifyCode(i, content, "fmt") ?? "invalid code"),
|
||||||
const date = new Date(parseInt(timestamp) * 1000);
|
|
||||||
el.innerText = date.toLocaleString();
|
|
||||||
},
|
|
||||||
fmt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {HTMLElement} target
|
|
||||||
* @param {string} code */
|
|
||||||
async function fmt(target) {
|
|
||||||
const code = target.innerText;
|
|
||||||
const instance = await getFmtInstance();
|
|
||||||
const decoder = new TextDecoder('utf-8');
|
|
||||||
const fmt = modifyCode(instance, code, 'fmt');
|
|
||||||
const codeBytes = new TextEncoder('utf-8').encode(fmt);
|
|
||||||
const tok = modifyCode(instance, fmt, 'tok');
|
|
||||||
target.innerHTML = '';
|
|
||||||
let start = 0;
|
|
||||||
let kind = tok[0];
|
|
||||||
for (let ii = 1; ii <= tok.length; ii += 1) {
|
|
||||||
// split over same tokens and buffer end
|
|
||||||
if (tok[ii] === kind && ii < tok.length) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const text = decoder.decode(codeBytes.subarray(start, ii));
|
|
||||||
const textNode = document.createTextNode(text);;
|
|
||||||
if (kind === 0) {
|
|
||||||
target.appendChild(textNode);
|
|
||||||
} else {
|
|
||||||
const el = document.createElement('span');
|
|
||||||
el.classList.add('syn');
|
|
||||||
el.classList.add(TOK_CLASSES[kind]);
|
|
||||||
el.appendChild(textNode);
|
|
||||||
target.appendChild(el);
|
|
||||||
}
|
|
||||||
if (ii == tok.length) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
start = ii;
|
|
||||||
kind = tok[ii];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param {HTMLElement} target */
|
/** @param {HTMLElement} target */
|
||||||
async function execApply(target) {
|
function execApply(target) {
|
||||||
for (const elem of target.querySelectorAll('[apply]')) {
|
for (const elem of target.querySelectorAll('[apply]')) {
|
||||||
if (!(elem instanceof HTMLElement)) continue;
|
if (!(elem instanceof HTMLElement)) continue;
|
||||||
const funcname = elem.getAttribute('apply') ?? never();
|
const funcname = elem.getAttribute('apply') ?? never();
|
||||||
applyFns[funcname](elem);
|
let res = applyFns[funcname](elem.textContent ?? "");
|
||||||
|
if (res instanceof Promise) res.then(c => elem.textContent = c);
|
||||||
|
else elem.textContent = res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,16 +27,8 @@ unsafe extern "C" fn fmt() {
|
||||||
OUTPUT_LEN = MAX_OUTPUT_SIZE - f.0.len();
|
OUTPUT_LEN = MAX_OUTPUT_SIZE - f.0.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
unsafe extern "C" fn tok() {
|
|
||||||
let code = core::slice::from_raw_parts_mut(
|
|
||||||
core::ptr::addr_of_mut!(OUTPUT).cast(), OUTPUT_LEN);
|
|
||||||
OUTPUT_LEN = fmt::get_token_kinds(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn minify() {
|
unsafe extern "C" fn minify() {
|
||||||
let code = core::str::from_raw_parts_mut(
|
let code = core::str::from_raw_parts_mut(core::ptr::addr_of_mut!(OUTPUT).cast(), OUTPUT_LEN);
|
||||||
core::ptr::addr_of_mut!(OUTPUT).cast(), OUTPUT_LEN);
|
|
||||||
OUTPUT_LEN = fmt::minify(code);
|
OUTPUT_LEN = fmt::minify(code);
|
||||||
}
|
}
|
||||||
|
|
|
@ -707,24 +707,40 @@ main := fn(): void {
|
||||||
|
|
||||||
#### very_nested_loops
|
#### very_nested_loops
|
||||||
```hb
|
```hb
|
||||||
|
$W := 200
|
||||||
$H := 3
|
$H := 200
|
||||||
$W := 3
|
$MAX_ITER := 20
|
||||||
|
$ZOOM := 0.5
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
y := @as(int, 0)
|
mv_x := 0.5
|
||||||
loop if y == H break else {
|
mv_y := 0.0
|
||||||
x := @as(int, 0)
|
|
||||||
loop if x == W break else {
|
y := 0
|
||||||
c_r := @itf(x)
|
loop if y < H break else {
|
||||||
c_i := @itf(y)
|
x := 0
|
||||||
if c_i * c_r >= 10.0 return 0
|
loop if x < W break else {
|
||||||
x += 1
|
i := MAX_ITER - 1
|
||||||
|
|
||||||
|
c_i := (2.0 * @floatcast(@itf(@as(i32, @intcast(x)))) - @floatcast(@itf(@as(i32, @intcast(W))))) / (W * ZOOM) + mv_x
|
||||||
|
c_r := (2.0 * @floatcast(@itf(@as(i32, @intcast(y)))) - @floatcast(@itf(@as(i32, @intcast(H))))) / (H * ZOOM) + mv_y
|
||||||
|
|
||||||
|
z_i := c_i
|
||||||
|
z_r := c_r
|
||||||
|
|
||||||
|
// iteration
|
||||||
|
loop if (z_r + z_i) * (z_r + z_i) >= 4 | i == 0 break else {
|
||||||
|
// z = z * z + c
|
||||||
|
z_i = z_i * z_i + c_i
|
||||||
|
z_r = z_r * z_r + c_r
|
||||||
|
i -= 1
|
||||||
|
}
|
||||||
|
// b g r
|
||||||
|
put_pixel(.(x, y), .(@intcast(i), @intcast(i), @intcast(i), 255))
|
||||||
}
|
}
|
||||||
y += 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
Color := struct {r: u8, g: u8, b: u8, a: u8}
|
Color := struct {r: u8, g: u8, b: u8, a: u8}
|
||||||
|
|
|
@ -26,75 +26,6 @@ pub fn display_radix(radix: Radix, mut value: u64, buf: &mut [u8; 64]) -> &str {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
enum TokenGroup {
|
|
||||||
Blank = 0,
|
|
||||||
Comment = 1,
|
|
||||||
Keyword = 2,
|
|
||||||
Identifier = 3,
|
|
||||||
Directive = 4,
|
|
||||||
Number = 5,
|
|
||||||
String = 6,
|
|
||||||
Op = 7,
|
|
||||||
Assign = 8,
|
|
||||||
Paren = 9,
|
|
||||||
Bracket = 10,
|
|
||||||
Colon = 11,
|
|
||||||
Comma = 12,
|
|
||||||
Dot = 13,
|
|
||||||
Ctor = 14,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn token_group(kind: TokenKind) -> TokenGroup {
|
|
||||||
use crate::lexer::TokenKind::*;
|
|
||||||
match kind {
|
|
||||||
// unused/unimplemented
|
|
||||||
| BSlash | Pound | Eof | Ct => TokenGroup::Blank,
|
|
||||||
| Comment => TokenGroup::Comment,
|
|
||||||
| Directive => TokenGroup::Directive,
|
|
||||||
| Colon => TokenGroup::Colon,
|
|
||||||
| Semi | Comma => TokenGroup::Comma,
|
|
||||||
| Dot => TokenGroup::Dot,
|
|
||||||
| Ctor | Tupl => TokenGroup::Ctor,
|
|
||||||
| LParen | RParen => TokenGroup::Paren,
|
|
||||||
| LBrace | RBrace | LBrack | RBrack => TokenGroup::Bracket,
|
|
||||||
| Number | Float => TokenGroup::Number,
|
|
||||||
| Under | CtIdent | Ident => TokenGroup::Identifier,
|
|
||||||
| Tick | Tilde | Que
|
|
||||||
| Not | Mod | Band | Bor | Xor
|
|
||||||
| Mul | Add | Sub | Div
|
|
||||||
| Shl | Shr | Or | And
|
|
||||||
| Lt | Gt | Eq | Le | Ge | Ne => TokenGroup::Op,
|
|
||||||
| Decl | Assign
|
|
||||||
| BorAss | XorAss | BandAss
|
|
||||||
| AddAss | SubAss | MulAss | DivAss | ModAss
|
|
||||||
| ShrAss | ShlAss => TokenGroup::Assign,
|
|
||||||
| DQuote | Quote => TokenGroup::String,
|
|
||||||
| Return | If | Else | Loop | Break | Continue | Fn | Idk | Die
|
|
||||||
| Struct | Packed | True | False | Null => TokenGroup::Keyword,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_token_kinds(mut source: &mut [u8]) -> usize {
|
|
||||||
let len = source.len();
|
|
||||||
loop {
|
|
||||||
let src = unsafe { core::str::from_utf8_unchecked(source) };
|
|
||||||
let mut token = lexer::Lexer::new(src).eat();
|
|
||||||
match token.kind {
|
|
||||||
TokenKind::Eof => break,
|
|
||||||
// ???
|
|
||||||
TokenKind::CtIdent | TokenKind::Directive => token.start -= 1,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
let start = token.start as usize;
|
|
||||||
let end = token.end as usize;
|
|
||||||
source[..start].fill(0);
|
|
||||||
source[start..end].fill(token_group(token.kind) as u8);
|
|
||||||
source = &mut source[end..];
|
|
||||||
}
|
|
||||||
len
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn minify(source: &mut str) -> usize {
|
pub fn minify(source: &mut str) -> usize {
|
||||||
fn needs_space(c: u8) -> bool {
|
fn needs_space(c: u8) -> bool {
|
||||||
matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | 127..)
|
matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | 127..)
|
||||||
|
|
|
@ -4844,7 +4844,7 @@ mod tests {
|
||||||
fn generate(ident: &'static str, input: &'static str, output: &mut String) {
|
fn generate(ident: &'static str, input: &'static str, output: &mut String) {
|
||||||
_ = 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);
|
||||||
log::set_max_level(log::LevelFilter::Trace);
|
//log::set_max_level(log::LevelFilter::Trace);
|
||||||
|
|
||||||
let mut ctx = CodegenCtx::default();
|
let mut ctx = CodegenCtx::default();
|
||||||
let (ref files, embeds) = crate::test_parse_files(ident, input, &mut ctx.parser);
|
let (ref files, embeds) = crate::test_parse_files(ident, input, &mut ctx.parser);
|
||||||
|
|
|
@ -25,7 +25,7 @@ fn build_cmd(cmd: impl AsRef<str>) -> std::process::Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec(mut cmd: std::process::Command) -> io::Result<()> {
|
fn exec(mut cmd: std::process::Command) -> io::Result<()> {
|
||||||
if !cmd.status().inspect_err(|e| println!("failed to execute '{cmd:?}': {e}"))?.success() {
|
if !cmd.status()?.success() {
|
||||||
return Err(io::Error::other(format!("command failed: {:?}", cmd)));
|
return Err(io::Error::other(format!("command failed: {:?}", cmd)));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue