added web UI

This commit is contained in:
Parker TenBroeck 2025-12-24 19:11:32 -05:00
parent 48f0c6eed8
commit f1b8c08e8f
15 changed files with 1114 additions and 78 deletions

219
web/src/lib.rs Normal file
View file

@ -0,0 +1,219 @@
use automata::{
automata::npda::{self, NPDA},
loader::{self, Span, Spanned, lexer::Lexer},
};
use wasm_bindgen::prelude::wasm_bindgen;
#[wasm_bindgen]
pub fn test() {
panic!()
}
#[wasm_bindgen(start)]
pub fn main() {}
#[wasm_bindgen]
pub fn init() {
console_error_panic_hook::set_once();
}
#[wasm_bindgen]
pub fn silly(machine: &str, input: &str) {
let table = match npda::TransitionTable::load_table(machine) {
Ok((ok, logs)) => {
for log in logs.displayable() {
println!("{log}")
}
ok
}
Err(logs) => {
for log in logs.displayable() {
println!("{log}")
}
return;
}
};
println!("running on: '{input}'");
let mut simulator = npda::Simulator::begin(input, table);
loop {
match simulator.step() {
npda::SimulatorResult::Pending => {}
npda::SimulatorResult::Reject => {
println!("REJECTED");
break;
}
npda::SimulatorResult::Accept(npda) => {
println!("ACCEPT: {npda:?}");
break;
}
}
}
}
#[wasm_bindgen]
#[derive(Clone, Copy)]
pub enum Kind {
Ident = "ident",
Keyword = "keyword",
Error = "error",
Comment = "comment",
Punc = "punc",
LPar = "lpar",
LBrace = "lbrace",
LBracket = "lbracket",
RPar = "rpar",
RBrace = "rbrace",
RBracket = "rbracket",
}
#[wasm_bindgen]
#[derive(Clone, Copy)]
pub struct Tok {
pub start: usize,
pub end: usize,
pub scope_level: usize,
pub kind: Kind,
}
#[wasm_bindgen]
pub fn lex(input: &str) -> Vec<Tok> {
let mut scope_level = 0;
let mut index_utf16 = 0;
let mut index_utf8 = 0;
Lexer::new(input)
.map(|Spanned(tok, Span(start_utf8, end_utf8))| {
let since_last = &input[index_utf8..start_utf8];
let since_start = &input[start_utf8..end_utf8];
index_utf8 = end_utf8;
let start = index_utf16 + since_last.chars().map(char::len_utf16).sum::<usize>();
let end = start + since_start.chars().map(char::len_utf16).sum::<usize>();
index_utf16 = end;
let Ok(tok) = tok else {
return Tok {
start,
end,
kind: Kind::Error,
scope_level,
};
};
use automata::loader::lexer::Token;
let kind = match tok {
Token::LPar => Kind::LPar,
Token::RPar => Kind::RPar,
Token::LBrace => Kind::LBrace,
Token::RBrace => Kind::RBrace,
Token::LBracket => Kind::LBracket,
Token::RBracket => Kind::RBracket,
Token::Tilde => Kind::Keyword,
Token::Eq => Kind::Punc,
Token::Comma => Kind::Punc,
Token::Or => Kind::Punc,
Token::Plus => Kind::Punc,
Token::Star => Kind::Punc,
Token::And => Kind::Punc,
Token::LSmallArrow => Kind::Punc,
Token::LBigArrow => Kind::Punc,
Token::Comment(_) => Kind::Comment,
Token::Ident(_)
if input[..start_utf8]
.split("\n")
.last()
.unwrap_or_default()
.trim()
.is_empty() =>
{
Kind::Keyword
}
Token::Ident(
loader::EPSILON_LOWER
| "epsilon"
| loader::DELTA_LOWER
| "delta"
| loader::GAMMA_UPPER
| "gamma"
| loader::GAMMA_LOWER
| loader::SIGMA_UPPER
| "sigma",
) => Kind::Keyword,
Token::Ident(_) => Kind::Ident,
};
let scope_level = match kind {
Kind::LPar | Kind::LBrace | Kind::LBracket => {
scope_level = scope_level.saturating_add(1);
scope_level.saturating_sub(1)
}
Kind::RPar | Kind::RBrace | Kind::RBracket => {
scope_level = scope_level.saturating_sub(1);
scope_level
}
_ => scope_level,
};
Tok {
start,
end,
kind,
scope_level,
}
})
.collect()
}
#[wasm_bindgen]
#[derive(Clone, Copy)]
pub enum LogLevel {
Info = "info",
Warning = "warning",
Error = "error",
}
#[wasm_bindgen(getter_with_clone)]
#[derive(Clone)]
pub struct CompileLog {
pub level: LogLevel,
pub message: String,
pub start: Option<usize>,
pub end: Option<usize>,
}
#[wasm_bindgen(getter_with_clone)]
pub struct CompileResult{
pub log: Vec<CompileLog>,
pub log_formatted: String,
}
#[wasm_bindgen]
pub fn compile(input: &str) -> CompileResult {
let log = match npda::TransitionTable::load_table(input) {
Ok((_, logs)) => logs,
Err(logs) => logs,
};
use std::fmt::Write;
let log_formatted = log.displayable().fold(String::new(), |mut s, e|{write!(&mut s, "{e}").unwrap(); s});
let log = log.into_entries()
.map(|e| CompileLog {
level: match e.level {
loader::log::LogLevel::Info => LogLevel::Info,
loader::log::LogLevel::Warning => LogLevel::Warning,
loader::log::LogLevel::Error => LogLevel::Error,
},
message: e.message,
start: e
.span
.map(|span| input[..span.0].chars().map(char::len_utf16).count()),
end: e
.span
.map(|span| input[..span.1].chars().map(char::len_utf16).count()),
})
.collect();
CompileResult { log, log_formatted }
}